Version

Documentation » Admin

7. Creating and Editing objects »

« 5. Search

6. The List View

Note

This document is a stub representing a new work in progress. If you’re reading this you can help contribute, no matter what your experience level with Sonata is. Check out the issues on GitHub for more information about how to get involved.

This document will cover the List view which you use to browse the objects in your system. It will cover configuration of the list itself and the filters you can use to control what’s visible.

6.1. Basic configuration

SonataAdmin Options that may affect the list view:

sonata_admin:
    templates:
        list:                       SonataAdminBundle:CRUD:list.html.twig
        action:                     SonataAdminBundle:CRUD:action.html.twig
        select:                     SonataAdminBundle:CRUD:list__select.html.twig
        list_block:                 SonataAdminBundle:Block:block_admin_list.html.twig
        short_object_description:   SonataAdminBundle:Helper:short-object-description.html.twig
        batch:                      SonataAdminBundle:CRUD:list__batch.html.twig
        inner_list_row:             SonataAdminBundle:CRUD:list_inner_row.html.twig
        base_list_field:            SonataAdminBundle:CRUD:base_list_field.html.twig
        pager_links:                SonataAdminBundle:Pager:links.html.twig
        pager_results:              SonataAdminBundle:Pager:results.html.twig

Note

TODO: * a note about Routes and how disabling them disables the related action * adding custom columns

6.2. Customizing the fields displayed on the list page

You can customize the columns displayed on the list through the configureListFields method. Here is an example:

<?php

// ...

public function configureListFields(ListMapper $listMapper)
{
    $listMapper
        // addIdentifier allows to specify that this column
        // will provide a link to the entity
        // (edit or show route, depends on your access rights)
        ->addIdentifier('name')

        // you may specify the field type directly as the
        // second argument instead of in the options
        ->add('isVariation', 'boolean')

        // if null, the type will be guessed
        ->add('enabled', null, array(
            'editable' => true
        ))

        // editable association field
        ->add('status', 'choice', array(
            'editable' => true,
            'class' => 'Vendor\ExampleBundle\Entity\ExampleStatus',
            'choices' => array(
                1 => 'Active',
                2 => 'Inactive',
                3 => 'Draft',
            ),
        ))

        // we can add options to the field depending on the type
        ->add('price', 'currency', array(
            'currency' => $this->currencyDetector->getCurrency()->getLabel()
        ))

        // Here we specify which property is used to render the label of each entity in the list
        ->add('productCategories', null, array(
            'associated_property' => 'name')
        )

        // you may also use dotted-notation to access
        // specific properties of a relation to the entity
        ->add('image.name')

        // You may also specify the actions you want to be displayed in the list
        ->add('_action', null, array(
            'actions' => array(
                'show' => array(),
                'edit' => array(),
                'delete' => array(),
            )
        ))

    ;
}

6.2.1. Options

Note

  • (m) stands for mandatory
  • (o) stands for optional
  • type (m): defines the field type - mandatory for the field description itself but will try to detect the type automatically if not specified
  • template (o): the template used to render the field
  • label (o): the name used for the column’s title
  • link_parameters (o): add link parameter to the related Admin class when the Admin::generateUrl is called
  • code (o): the method name to retrieve the related value (for example, if you have an array type field, you would like to show info prettier than [0] => ‘Value’; useful when simple getter is not enough). Notice: works with string-like types (string, text, html)
  • 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.
  • identifier (o): if set to true a link appears on the value to edit the element

6.2.2. Available types and associated options

Note

(m) means that option is mandatory

Type Options Description
actions actions List of available actions
batch   Renders a checkbox
select   Renders a select box
array   Displays an array
boolean ajax_hidden Yes/No; ajax_hidden allows to hide list field during an AJAX context.
editable Yes/No; editable allows to edit directly from the list if authorized.
inverse Yes/No; reverses the background color (green for false, red for true)
choice choices Possible choices
multiple Is it a multiple choice option? Defaults to false.
delimiter Separator of values if multiple.
catalogue Translation catalogue.
class Class path for editable association field.
currency currency (m) A currency string (EUR or USD for instance).
date format A format understandable by Twig’s date function.
datetime format A format understandable by Twig’s date function.
email as_string Renders the email as string, without any link.
subject Add subject parameter to email link.
body Add body parameter to email link.
percent   Renders value as a percentage.
string   Renders a simple string.
text   See ‘string’
html   Renders string as html
time   Renders a datetime’s time with format H:i:s.
trans catalogue Translates the value with catalogue catalogue if defined.
url url Adds a link with url url to the displayed value

route

name

parameters

Give a route to generate the url

Route name

Route parameters

hide_protocol Hide http:// or https:// (default: false)

If you have the SonataDoctrineORMAdminBundle installed, you have access to more field types, see SonataDoctrineORMAdminBundle Documentation.

Note

It is better to prefer non negative notions when possible for boolean values so use the inverse option if you really cannot find a good enough antonym for the name you have.

6.3. Customizing the query used to generate the list

You can customize the list query thanks to the createQuery method.

<?php

public function createQuery($context = 'list')
{
    $query = parent::createQuery($context);
    $query->andWhere(
        $query->expr()->eq($query->getRootAliases()[0] . '.my_field', ':my_param')
    );
    $query->setParameter('my_param', 'my_value');
    return $query;
}

6.4. Customizing the sort order

6.4.1. Configure the default ordering in the list view

Configuring the default ordering column can simply be achieved by overriding the datagridValues array property. All three keys _page, _sort_order and _sort_by can be omitted.

<?php
// src/AppBundle/Admin/PostAdmin.php

use Sonata\AdminBundle\Admin\AbstractAdmin;

class PostAdmin extends AbstractAdmin
{
    // ...

    protected $datagridValues = array(

        // display the first page (default = 1)
        '_page' => 1,

        // reverse order (default = 'ASC')
        '_sort_order' => 'DESC',

        // name of the ordered field (default = the model's id field, if any)
        '_sort_by' => 'updatedAt',
    );

    // ...
}

Note

The _sort_by key can be of the form mySubModel.mySubSubModel.myField.

Note

TODO: how to sort by multiple fields (this might be a separate recipe?)

6.5. Filters

You can add filters to let user control which data will be displayed.

<?php
// src/AppBundle/Admin/PostAdmin.php

use Sonata\AdminBundle\Datagrid\DatagridMapper;

class ClientAdmin extends AbstractAdmin
{

    protected function configureDatagridFilters(DatagridMapper $datagridMapper)
    {
        $datagridMapper
            ->add('phone')
            ->add('email')
        ;
    }

    // ...
}

All filters are hidden by default for space-saving. User has to check which filter he wants to use.

To make the filter always visible (even when it is inactive), set the parameter show_filter to true.

<?php

protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
    $datagridMapper
        ->add('phone')
        ->add('email', null, array(
            'show_filter' => true
        ))

        // ...
    ;
}

By default the template generates an operator for a filter which defaults to sonata_type_equal. Though this operator_type is automatically detected it can be changed or even be hidden:

protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
    $datagridMapper
        ->add('foo', null, array(
            'operator_type' => 'sonata_type_boolean'
        ))
        ->add('bar', null, array(
            'operator_type' => 'hidden'
        ))

        // ...
    ;
}

If you don’t need the advanced filters, or all your operator_type are hidden, you can disable them by setting advanced_filter to false. You need to disable all advanced filters to make the button disappear.

protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
    $datagridMapper
        ->add('bar', null, array(
            'operator_type' => 'hidden',
            'advanced_filter' => false
        ))

        // ...
    ;
}

6.5.1. Default filters

Default filters can be added to the datagrid values by using the configureDefaultFilterValues method. A filter has a value and an optional type. If no type is given the default type is equal is used.

public function configureDefaultFilterValues(array &$filterValues)
{
    $filterValues['foo'] = array(
        'type'  => ChoiceFilter::TYPE_CONTAINS,
        'value' => 'bar',
    );
}

Available types are represented through classes which can be found here: https://github.com/sonata-project/SonataCoreBundle/tree/master/Form/Type

Types like equal and boolean use constants to assign a choice of type to an integer for its value:

<?php
// SonataCoreBundle/Form/Type/EqualType.php

namespace Sonata\CoreBundle\Form\Type;

class EqualType extends AbstractType
{
    const TYPE_IS_EQUAL = 1;
    const TYPE_IS_NOT_EQUAL = 2;
}

The integers are then passed in the URL of the list action e.g.: /admin/user/user/list?filter[enabled][type]=1&filter[enabled][value]=1

This is an example using these constants for an boolean type:

use Sonata\UserBundle\Admin\Model\UserAdmin as SonataUserAdmin;
use Sonata\CoreBundle\Form\Type\EqualType;
use Sonata\CoreBundle\Form\Type\BooleanType;

class UserAdmin extends SonataUserAdmin
{
    protected $datagridValues = array(
        'enabled' => array(
            'type'  => EqualType::TYPE_IS_EQUAL, // => 1
            'value' => BooleanType::TYPE_YES     // => 1
        )
    );
}

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:

<?php
// SonataCoreBundle/Form/Type/BooleanType.php

namespace Sonata\CoreBundle\Form\Type;

class BooleanType extends AbstractType
{
    const TYPE_YES = 1;
    const TYPE_NO = 2;
}

Default filters can also be added to the datagrid values by overriding the getFilterParameters method.

use Sonata\CoreBundle\Form\Type\EqualType;
use Sonata\CoreBundle\Form\Type\BooleanType;

class UserAdmin extends SonataUserAdmin
{
    public function getFilterParameters()
    {
        $this->datagridValues = array_merge(array(
                'enabled' => array (
                    'type'  => EqualType::TYPE_IS_EQUAL,
                    'value' => BooleanType::TYPE_YES
                )
            ), $this->datagridValues);

        return parent::getFilterParameters();
    }
}

This approach is useful when you need to create dynamic filters.

class PostAdmin extends SonataUserAdmin
{
    public function getFilterParameters()
    {
        // Assuming security context injected
        if (!$this->securityContext->isGranted('ROLE_ADMIN')) {
            $user = $this->securityContext->getToken()->getUser();

            $this->datagridValues = array_merge(array(
                    'author' => array (
                        'type'  => EqualType::TYPE_IS_EQUAL,
                        'value' => $user->getId()
                    )
                ), $this->datagridValues);
        }

        return parent::getFilterParameters();
    }
}

Please note that this is not a secure approach to hide posts from others. It’s just an example for setting filters on demand.

6.5.2. Callback filter

If you have the SonataDoctrineORMAdminBundle installed you can use the doctrine_orm_callback filter type e.g. for creating a full text filter:

use Sonata\UserBundle\Admin\Model\UserAdmin as SonataUserAdmin;
use Sonata\AdminBundle\Datagrid\DatagridMapper;

class UserAdmin extends SonataUserAdmin
{
    protected function configureDatagridFilters(DatagridMapper $datagridMapper)
    {
        $datagridMapper
            ->add('full_text', CallbackFilter::class, array(
                'callback' => array($this, 'getFullTextFilter'),
                'field_type' => 'text'
            ))

            // ...
        ;
    }

    public function getFullTextFilter($queryBuilder, $alias, $field, $value)
    {
        if (!$value['value']) {
            return;
        }

        // Use `andWhere` instead of `where` to prevent overriding existing `where` conditions
        $queryBuilder->andWhere($queryBuilder->expr()->orX(
            $queryBuilder->expr()->like($alias.'.username', $queryBuilder->expr()->literal('%' . $value['value'] . '%')),
            $queryBuilder->expr()->like($alias.'.firstName', $queryBuilder->expr()->literal('%' . $value['value'] . '%')),
            $queryBuilder->expr()->like($alias.'.lastName', $queryBuilder->expr()->literal('%' . $value['value'] . '%'))
        ));

        return true;
    }
}

You can also get the filter type which can be helpful to change the operator type of your condition(s):

use Sonata\CoreBundle\Form\Type\EqualType;

class UserAdmin extends SonataUserAdmin
{
    public function getFullTextFilter($queryBuilder, $alias, $field, $value)
    {
        if (!$value['value']) {
            return;
        }

        $operator = $value['type'] == EqualType::TYPE_IS_EQUAL ? '=' : '!=';

        $queryBuilder
            ->andWhere($alias.'.username '.$operator.' :username')
            ->setParameter('username', $value['value'])
        ;

        return true;
    }
}

Note

TODO: * basic filter configuration and options * targeting submodel fields using dot-separated notation * advanced filter options (global_search)

6.6. Visual configuration

You have the possibility to configure your List View to customize the render without overriding to whole template. You can :

  • header_style: Customize the style of header (width, color, background, align...)
  • header_class: Customize the class of the header
  • collapse: Allow to collapse long text fields with a “read more” link
  • row_align: Customize the alignment of the rendered inner cells
  • label_icon: Add an icon before label
<?php

public function configureListFields(ListMapper $list)
{
    $list
        ->add('id', null, array(
            'header_style' => 'width: 5%; text-align: center',
            'row_align' => 'center'
        ))
        ->add('name', 'text', array(
            'header_style' => 'width: 35%'
        )
        ->add('description', 'text', array(
            'header_style' => 'width: 35%',
            'collapse' => true
        )
        ->add('upvotes', null, array(
            'label_icon' => 'fa fa-thumbs-o-up'
        )
        ->add('actions', null, array(
            'header_class' => 'customActions',
            'row_align' => 'right'
        )

        // ...
    ;
}

If you want to customise the collapse option, you can also give an array to override the default parameters.

// ...
->add('description', 'text', array(
    'header_style' => 'width: 35%',
    'collapse' => array(
        'height' => 40, // height in px
        'read_more' => 'I want to see the full description', // content of the "read more" link
        'read_less' => 'This text is too long, reduce the size' // content of the "read less" link
    )
)
// ...

If you want to show only the label_icon:

// ...
->add('upvotes', null, array(
    'label' => false,
    'label_icon' => 'fa fa-thumbs-o-up'
)
// ...

6.7. Mosaic view button

You have the possibility to show/hide mosaic view button.

sonata_admin:
    # for hide mosaic view button on all screen using `false`
    show_mosaic_button:   true

You can show/hide mosaic view button using admin service configuration. You need to add option show_mosaic_button in your admin services:

sonata_admin.admin.post:
    class: Sonata\AdminBundle\Admin\PostAdmin
    arguments: [~, Sonata\AdminBundle\Entity\Post, ~]
    tags:
        - { name: sonata.admin, manager_type: orm, group: admin, label: Post, show_mosaic_button: true }

sonata_admin.admin.news:
    class: Sonata\AdminBundle\Admin\NewsAdmin
    arguments: [~, Sonata\AdminBundle\Entity\News, ~]
    tags:
        - { name: sonata.admin, manager_type: orm, group: admin, label: News, show_mosaic_button: false }

6.8. Checkbox range selection

Tip

You can check / uncheck a range of checkboxes by clicking a first one, then a second one with shift + click.

Found a typo? Something is wrong in this documentation? Just fork and edit it!