action_list.rst 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. The List View
  2. =============
  3. .. note::
  4. This document is a stub representing a new work in progress. If you're reading
  5. this you can help contribute, **no matter what your experience level with Sonata
  6. is**. Check out the `issues on GitHub`_ for more information about how to get involved.
  7. This document will cover the List view which you use to browse the objects in your
  8. system. It will cover configuration of the list itself and the filters you can use
  9. to control what's visible.
  10. Basic configuration
  11. -------------------
  12. SonataAdmin Options that may affect the list view:
  13. .. code-block:: yaml
  14. sonata_admin:
  15. templates:
  16. list: SonataAdminBundle:CRUD:list.html.twig
  17. action: SonataAdminBundle:CRUD:action.html.twig
  18. select: SonataAdminBundle:CRUD:list__select.html.twig
  19. list_block: SonataAdminBundle:Block:block_admin_list.html.twig
  20. short_object_description: SonataAdminBundle:Helper:short-object-description.html.twig
  21. batch: SonataAdminBundle:CRUD:list__batch.html.twig
  22. inner_list_row: SonataAdminBundle:CRUD:list_inner_row.html.twig
  23. base_list_field: SonataAdminBundle:CRUD:base_list_field.html.twig
  24. pager_links: SonataAdminBundle:Pager:links.html.twig
  25. pager_results: SonataAdminBundle:Pager:results.html.twig
  26. .. note::
  27. **TODO**:
  28. * a note about Routes and how disabling them disables the related action
  29. * adding custom columns
  30. Customizing the fields displayed on the list page
  31. -------------------------------------------------
  32. You can customize the columns displayed on the list through the ``configureListFields`` method.
  33. Here is an example:
  34. .. code-block:: php
  35. <?php
  36. // ...
  37. public function configureListFields(ListMapper $listMapper)
  38. {
  39. $listMapper
  40. // addIdentifier allows to specify that this column
  41. // will provide a link to the entity
  42. // (edit or show route, depends on your access rights)
  43. ->addIdentifier('name')
  44. // you may specify the field type directly as the
  45. // second argument instead of in the options
  46. ->add('isVariation', 'boolean')
  47. // if null, the type will be guessed
  48. ->add('enabled', null, array(
  49. 'editable' => true
  50. ))
  51. // editable association field
  52. ->add('status', 'choice', array(
  53. 'editable' => true,
  54. 'class' => 'Vendor\ExampleBundle\Entity\ExampleStatus',
  55. 'choices' => array(
  56. 1 => 'Active',
  57. 2 => 'Inactive',
  58. 3 => 'Draft',
  59. ),
  60. ))
  61. // we can add options to the field depending on the type
  62. ->add('price', 'currency', array(
  63. 'currency' => $this->currencyDetector->getCurrency()->getLabel()
  64. ))
  65. // Here we specify which property is used to render the label of each entity in the list
  66. ->add('productCategories', null, array(
  67. 'associated_property' => 'name')
  68. )
  69. // you may also use dotted-notation to access
  70. // specific properties of a relation to the entity
  71. ->add('image.name')
  72. // You may also specify the actions you want to be displayed in the list
  73. ->add('_action', null, array(
  74. 'actions' => array(
  75. 'show' => array(),
  76. 'edit' => array(),
  77. 'delete' => array(),
  78. )
  79. ))
  80. ;
  81. }
  82. Options
  83. ^^^^^^^
  84. .. note::
  85. * ``(m)`` stands for mandatory
  86. * ``(o)`` stands for optional
  87. - ``type`` (m): defines the field type - mandatory for the field description itself but will try to detect the type automatically if not specified
  88. - ``template`` (o): the template used to render the field
  89. - ``label`` (o): the name used for the column's title
  90. - ``link_parameters`` (o): add link parameter to the related Admin class when the ``Admin::generateUrl`` is called
  91. - ``code`` (o): the method name to retrieve the related value (for example,
  92. if you have an `array` type field, you would like to show info prettier
  93. than `[0] => 'Value'`; useful when simple getter is not enough).
  94. Notice: works with string-like types (string, text, html)
  95. - ``associated_property`` (o): property path to retrieve the "string" representation of the collection element, or a closure with the element as argument and return a string.
  96. - ``identifier`` (o): if set to true a link appears on the value to edit the element
  97. Available types and associated options
  98. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  99. .. note::
  100. ``(m)`` means that option is mandatory
  101. +-----------+----------------+-----------------------------------------------------------------------+
  102. | Type | Options | Description |
  103. +===========+================+=======================================================================+
  104. | actions | actions | List of available actions |
  105. +-----------+----------------+-----------------------------------------------------------------------+
  106. | batch | | Renders a checkbox |
  107. +-----------+----------------+-----------------------------------------------------------------------+
  108. | select | | Renders a select box |
  109. +-----------+----------------+-----------------------------------------------------------------------+
  110. | array | | Displays an array |
  111. +-----------+----------------+-----------------------------------------------------------------------+
  112. | boolean | ajax_hidden | Yes/No; ajax_hidden allows to hide list field during an AJAX context. |
  113. + +----------------+-----------------------------------------------------------------------+
  114. | | editable | Yes/No; editable allows to edit directly from the list if authorized. |
  115. + +----------------+-----------------------------------------------------------------------+
  116. | | inverse | Yes/No; reverses the background color (green for false, red for true) |
  117. +-----------+----------------+-----------------------------------------------------------------------+
  118. | choice | choices | Possible choices |
  119. + +----------------+-----------------------------------------------------------------------+
  120. | | multiple | Is it a multiple choice option? Defaults to false. |
  121. + +----------------+-----------------------------------------------------------------------+
  122. | | delimiter | Separator of values if multiple. |
  123. + +----------------+-----------------------------------------------------------------------+
  124. | | catalogue | Translation catalogue. |
  125. + +----------------+-----------------------------------------------------------------------+
  126. | | class | Class path for editable association field. |
  127. +-----------+----------------+-----------------------------------------------------------------------+
  128. | currency | currency (m) | A currency string (EUR or USD for instance). |
  129. +-----------+----------------+-----------------------------------------------------------------------+
  130. | date | format | A format understandable by Twig's ``date`` function. |
  131. +-----------+----------------+-----------------------------------------------------------------------+
  132. | datetime | format | A format understandable by Twig's ``date`` function. |
  133. +-----------+----------------+-----------------------------------------------------------------------+
  134. | email | as_string | Renders the email as string, without any link. |
  135. + +----------------+-----------------------------------------------------------------------+
  136. | | subject | Add subject parameter to email link. |
  137. + +----------------+-----------------------------------------------------------------------+
  138. | | body | Add body parameter to email link. |
  139. +-----------+----------------+-----------------------------------------------------------------------+
  140. | percent | | Renders value as a percentage. |
  141. +-----------+----------------+-----------------------------------------------------------------------+
  142. | string | | Renders a simple string. |
  143. +-----------+----------------+-----------------------------------------------------------------------+
  144. | text | | See 'string' |
  145. +-----------+----------------+-----------------------------------------------------------------------+
  146. | html | | Renders string as html |
  147. +-----------+----------------+-----------------------------------------------------------------------+
  148. | time | | Renders a datetime's time with format ``H:i:s``. |
  149. +-----------+----------------+-----------------------------------------------------------------------+
  150. | trans | catalogue | Translates the value with catalogue ``catalogue`` if defined. |
  151. +-----------+----------------+-----------------------------------------------------------------------+
  152. | url | url | Adds a link with url ``url`` to the displayed value |
  153. + +----------------+-----------------------------------------------------------------------+
  154. | | route | Give a route to generate the url |
  155. + + + +
  156. | | name | Route name |
  157. + + + +
  158. | | parameters | Route parameters |
  159. + +----------------+-----------------------------------------------------------------------+
  160. | | hide_protocol | Hide http:// or https:// (default: false) |
  161. +-----------+----------------+-----------------------------------------------------------------------+
  162. If you have the SonataDoctrineORMAdminBundle installed, you have access to more field types, see `SonataDoctrineORMAdminBundle Documentation <https://sonata-project.org/bundles/doctrine-orm-admin/master/doc/reference/list_field_definition.html>`_.
  163. .. note::
  164. It is better to prefer non negative notions when possible for boolean
  165. values so use the ``inverse`` option if you really cannot find a good enough
  166. antonym for the name you have.
  167. Customizing the query used to generate the list
  168. -----------------------------------------------
  169. You can customize the list query thanks to the ``createQuery`` method.
  170. .. code-block:: php
  171. <?php
  172. public function createQuery($context = 'list')
  173. {
  174. $query = parent::createQuery($context);
  175. $query->andWhere(
  176. $query->expr()->eq($query->getRootAliases()[0] . '.my_field', ':my_param')
  177. );
  178. $query->setParameter('my_param', 'my_value');
  179. return $query;
  180. }
  181. Customizing the sort order
  182. --------------------------
  183. Configure the default ordering in the list view
  184. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  185. Configuring the default ordering column can simply be achieved by overriding
  186. the ``datagridValues`` array property. All three keys ``_page``, ``_sort_order`` and
  187. ``_sort_by`` can be omitted.
  188. .. code-block:: php
  189. <?php
  190. // src/AppBundle/Admin/PostAdmin.php
  191. use Sonata\AdminBundle\Admin\AbstractAdmin;
  192. class PostAdmin extends AbstractAdmin
  193. {
  194. // ...
  195. protected $datagridValues = array(
  196. // display the first page (default = 1)
  197. '_page' => 1,
  198. // reverse order (default = 'ASC')
  199. '_sort_order' => 'DESC',
  200. // name of the ordered field (default = the model's id field, if any)
  201. '_sort_by' => 'updatedAt',
  202. );
  203. // ...
  204. }
  205. .. note::
  206. The ``_sort_by`` key can be of the form ``mySubModel.mySubSubModel.myField``.
  207. .. note::
  208. **TODO**: how to sort by multiple fields (this might be a separate recipe?)
  209. Filters
  210. -------
  211. You can add filters to let user control which data will be displayed.
  212. .. code-block:: php
  213. <?php
  214. // src/AppBundle/Admin/PostAdmin.php
  215. use Sonata\AdminBundle\Datagrid\DatagridMapper;
  216. class ClientAdmin extends AbstractAdmin
  217. {
  218. protected function configureDatagridFilters(DatagridMapper $datagridMapper)
  219. {
  220. $datagridMapper
  221. ->add('phone')
  222. ->add('email')
  223. ;
  224. }
  225. // ...
  226. }
  227. All filters are hidden by default for space-saving. User has to check which filter he wants to use.
  228. To make the filter always visible (even when it is inactive), set the parameter
  229. ``show_filter`` to ``true``.
  230. .. code-block:: php
  231. <?php
  232. protected function configureDatagridFilters(DatagridMapper $datagridMapper)
  233. {
  234. $datagridMapper
  235. ->add('phone')
  236. ->add('email', null, array(
  237. 'show_filter' => true
  238. ))
  239. // ...
  240. ;
  241. }
  242. By default the template generates an ``operator`` for a filter which defaults to ``sonata_type_equal``.
  243. Though this ``operator_type`` is automatically detected it can be changed or even be hidden:
  244. .. code-block:: php
  245. protected function configureDatagridFilters(DatagridMapper $datagridMapper)
  246. {
  247. $datagridMapper
  248. ->add('foo', null, array(
  249. 'operator_type' => 'sonata_type_boolean'
  250. ))
  251. ->add('bar', null, array(
  252. 'operator_type' => 'hidden'
  253. ))
  254. // ...
  255. ;
  256. }
  257. If you don't need the advanced filters, or all your ``operator_type`` are hidden, you can disable them by setting
  258. ``advanced_filter`` to ``false``. You need to disable all advanced filters to make the button disappear.
  259. .. code-block:: php
  260. protected function configureDatagridFilters(DatagridMapper $datagridMapper)
  261. {
  262. $datagridMapper
  263. ->add('bar', null, array(
  264. 'operator_type' => 'hidden',
  265. 'advanced_filter' => false
  266. ))
  267. // ...
  268. ;
  269. }
  270. Default filters
  271. ^^^^^^^^^^^^^^^
  272. Default filters can be added to the datagrid values by using the ``configureDefaultFilterValues`` method.
  273. A filter has a ``value`` and an optional ``type``. If no ``type`` is given the default type ``is equal`` is used.
  274. .. code-block:: php
  275. public function configureDefaultFilterValues(array &$filterValues)
  276. {
  277. $filterValues['foo'] = array(
  278. 'type' => ChoiceFilter::TYPE_CONTAINS,
  279. 'value' => 'bar',
  280. );
  281. }
  282. Available types are represented through classes which can be found here:
  283. https://github.com/sonata-project/SonataCoreBundle/tree/master/Form/Type
  284. Types like ``equal`` and ``boolean`` use constants to assign a choice of ``type`` to an ``integer`` for its ``value``:
  285. .. code-block:: php
  286. <?php
  287. // SonataCoreBundle/Form/Type/EqualType.php
  288. namespace Sonata\CoreBundle\Form\Type;
  289. class EqualType extends AbstractType
  290. {
  291. const TYPE_IS_EQUAL = 1;
  292. const TYPE_IS_NOT_EQUAL = 2;
  293. }
  294. The integers are then passed in the URL of the list action e.g.:
  295. **/admin/user/user/list?filter[enabled][type]=1&filter[enabled][value]=1**
  296. This is an example using these constants for an ``boolean`` type:
  297. .. code-block:: php
  298. use Sonata\UserBundle\Admin\Model\UserAdmin as SonataUserAdmin;
  299. use Sonata\CoreBundle\Form\Type\EqualType;
  300. use Sonata\CoreBundle\Form\Type\BooleanType;
  301. class UserAdmin extends SonataUserAdmin
  302. {
  303. protected $datagridValues = array(
  304. 'enabled' => array(
  305. 'type' => EqualType::TYPE_IS_EQUAL, // => 1
  306. 'value' => BooleanType::TYPE_YES // => 1
  307. )
  308. );
  309. }
  310. Please note that setting a ``false`` value on a the ``boolean`` type will not work since the type expects an integer of ``2`` as ``value`` as defined in the class constants:
  311. .. code-block:: php
  312. <?php
  313. // SonataCoreBundle/Form/Type/BooleanType.php
  314. namespace Sonata\CoreBundle\Form\Type;
  315. class BooleanType extends AbstractType
  316. {
  317. const TYPE_YES = 1;
  318. const TYPE_NO = 2;
  319. }
  320. Default filters can also be added to the datagrid values by overriding the ``getFilterParameters`` method.
  321. .. code-block:: php
  322. use Sonata\CoreBundle\Form\Type\EqualType;
  323. use Sonata\CoreBundle\Form\Type\BooleanType;
  324. class UserAdmin extends SonataUserAdmin
  325. {
  326. public function getFilterParameters()
  327. {
  328. $this->datagridValues = array_merge(array(
  329. 'enabled' => array (
  330. 'type' => EqualType::TYPE_IS_EQUAL,
  331. 'value' => BooleanType::TYPE_YES
  332. )
  333. ), $this->datagridValues);
  334. return parent::getFilterParameters();
  335. }
  336. }
  337. This approach is useful when you need to create dynamic filters.
  338. .. code-block:: php
  339. class PostAdmin extends SonataUserAdmin
  340. {
  341. public function getFilterParameters()
  342. {
  343. // Assuming security context injected
  344. if (!$this->securityContext->isGranted('ROLE_ADMIN')) {
  345. $user = $this->securityContext->getToken()->getUser();
  346. $this->datagridValues = array_merge(array(
  347. 'author' => array (
  348. 'type' => EqualType::TYPE_IS_EQUAL,
  349. 'value' => $user->getId()
  350. )
  351. ), $this->datagridValues);
  352. }
  353. return parent::getFilterParameters();
  354. }
  355. }
  356. Please note that this is not a secure approach to hide posts from others. It's just an example for setting filters on demand.
  357. Callback filter
  358. ^^^^^^^^^^^^^^^
  359. If you have the **SonataDoctrineORMAdminBundle** installed you can use the ``doctrine_orm_callback`` filter type e.g. for creating a full text filter:
  360. .. code-block:: php
  361. use Sonata\UserBundle\Admin\Model\UserAdmin as SonataUserAdmin;
  362. use Sonata\AdminBundle\Datagrid\DatagridMapper;
  363. class UserAdmin extends SonataUserAdmin
  364. {
  365. protected function configureDatagridFilters(DatagridMapper $datagridMapper)
  366. {
  367. $datagridMapper
  368. ->add('full_text', CallbackFilter::class, array(
  369. 'callback' => array($this, 'getFullTextFilter'),
  370. 'field_type' => 'text'
  371. ))
  372. // ...
  373. ;
  374. }
  375. public function getFullTextFilter($queryBuilder, $alias, $field, $value)
  376. {
  377. if (!$value['value']) {
  378. return;
  379. }
  380. // Use `andWhere` instead of `where` to prevent overriding existing `where` conditions
  381. $queryBuilder->andWhere($queryBuilder->expr()->orX(
  382. $queryBuilder->expr()->like($alias.'.username', $queryBuilder->expr()->literal('%' . $value['value'] . '%')),
  383. $queryBuilder->expr()->like($alias.'.firstName', $queryBuilder->expr()->literal('%' . $value['value'] . '%')),
  384. $queryBuilder->expr()->like($alias.'.lastName', $queryBuilder->expr()->literal('%' . $value['value'] . '%'))
  385. ));
  386. return true;
  387. }
  388. }
  389. You can also get the filter type which can be helpful to change the operator type of your condition(s):
  390. .. code-block:: php
  391. use Sonata\CoreBundle\Form\Type\EqualType;
  392. class UserAdmin extends SonataUserAdmin
  393. {
  394. public function getFullTextFilter($queryBuilder, $alias, $field, $value)
  395. {
  396. if (!$value['value']) {
  397. return;
  398. }
  399. $operator = $value['type'] == EqualType::TYPE_IS_EQUAL ? '=' : '!=';
  400. $queryBuilder
  401. ->andWhere($alias.'.username '.$operator.' :username')
  402. ->setParameter('username', $value['value'])
  403. ;
  404. return true;
  405. }
  406. }
  407. .. note::
  408. **TODO**:
  409. * basic filter configuration and options
  410. * targeting submodel fields using dot-separated notation
  411. * advanced filter options (global_search)
  412. Visual configuration
  413. --------------------
  414. You have the possibility to configure your List View to customize the render without overriding to whole template.
  415. You can :
  416. - `header_style`: Customize the style of header (width, color, background, align...)
  417. - `header_class`: Customize the class of the header
  418. - `collapse`: Allow to collapse long text fields with a "read more" link
  419. - `row_align`: Customize the alignment of the rendered inner cells
  420. - `label_icon`: Add an icon before label
  421. .. code-block:: php
  422. <?php
  423. public function configureListFields(ListMapper $list)
  424. {
  425. $list
  426. ->add('id', null, array(
  427. 'header_style' => 'width: 5%; text-align: center',
  428. 'row_align' => 'center'
  429. ))
  430. ->add('name', 'text', array(
  431. 'header_style' => 'width: 35%'
  432. )
  433. ->add('description', 'text', array(
  434. 'header_style' => 'width: 35%',
  435. 'collapse' => true
  436. )
  437. ->add('upvotes', null, array(
  438. 'label_icon' => 'fa fa-thumbs-o-up'
  439. )
  440. ->add('actions', null, array(
  441. 'header_class' => 'customActions',
  442. 'row_align' => 'right'
  443. )
  444. // ...
  445. ;
  446. }
  447. If you want to customise the `collapse` option, you can also give an array to override the default parameters.
  448. .. code-block:: php
  449. // ...
  450. ->add('description', 'text', array(
  451. 'header_style' => 'width: 35%',
  452. 'collapse' => array(
  453. 'height' => 40, // height in px
  454. 'read_more' => 'I want to see the full description', // content of the "read more" link
  455. 'read_less' => 'This text is too long, reduce the size' // content of the "read less" link
  456. )
  457. )
  458. // ...
  459. If you want to show only the `label_icon`:
  460. .. code-block:: php
  461. // ...
  462. ->add('upvotes', null, array(
  463. 'label' => false,
  464. 'label_icon' => 'fa fa-thumbs-o-up'
  465. )
  466. // ...
  467. .. _`issues on GitHub`: https://github.com/sonata-project/SonataAdminBundle/issues/1519
  468. Mosaic view button
  469. ------------------
  470. You have the possibility to show/hide mosaic view button.
  471. .. code-block:: yaml
  472. sonata_admin:
  473. # for hide mosaic view button on all screen using `false`
  474. show_mosaic_button: true
  475. You can show/hide mosaic view button using admin service configuration. You need to add option ``show_mosaic_button``
  476. in your admin services:
  477. .. code-block:: yaml
  478. sonata_admin.admin.post:
  479. class: Sonata\AdminBundle\Admin\PostAdmin
  480. arguments: [~, Sonata\AdminBundle\Entity\Post, ~]
  481. tags:
  482. - { name: sonata.admin, manager_type: orm, group: admin, label: Post, show_mosaic_button: true }
  483. sonata_admin.admin.news:
  484. class: Sonata\AdminBundle\Admin\NewsAdmin
  485. arguments: [~, Sonata\AdminBundle\Entity\News, ~]
  486. tags:
  487. - { name: sonata.admin, manager_type: orm, group: admin, label: News, show_mosaic_button: false }
  488. Checkbox range selection
  489. ------------------------
  490. .. tip::
  491. You can check / uncheck a range of checkboxes by clicking a first one,
  492. then a second one with shift + click.