Search code examples
phpsonata-adminsymfony-sonata

In Symfony-Sonata all fields are sortable except for one


In Sonata I have created several lists and all work fine. (Please not that that was a while ago, so I may have done something there which fixed the issue I will describe here...).

Now I have created a new listing of Playlist entities: enter image description here

As you can see in the picture, both the "Id" column and the "Aangemaakt op" columns are sortable, however the "Playlist" column is not.

Both the "Aangemaakt op" and the "Playlist" fields are date-fields, but since the "Aangemaakt op" field is sortable I would say that has nothing to do with it.

I have been searching the Sonata documentation, Google and StackOverflow, but haven't found any clue concerning this issue. I did find thread about sorting a list based on an Entity field, but my field isn't an entity.

Relevant code:

/**
 * @param ListMapper $listMapper
 */
protected function configureListFields(ListMapper $listMapper) {
    $listMapper
        ->add('id')
        ->add('playlist_date', 'date', array('label' => 'Playlist'))
        ->add('created', 'datetime', array('label' => 'Aangemaakt op'))
        ->add(
            '_action', 'actions', array(
                'actions' => array(
                    'delete' => array(),
                )
            )
        );
}

Some StackOverflow threads and an answer below mention adding 'sortable' => true to the field that must be sortable.

Doing that indeed makes the column clickable to sort, but clicking it results in the following exception:

Catchable Fatal Error: Argument 1 passed to
Sonata\DoctrineORMAdminBundle\Datagrid\ProxyQuery::entityJoin() 
must be of the type array, null given, called in
/path/of/my/project/sonata-project/doctrine-orm-admin-bundle/Datagrid/ProxyQuery.php
on line 142 and defined.

According to other StackOverflow threads that is because a join must be created. However, the field is simply a field of the same Mysql record as the other fields. I did find a StackOverflow thread mentioning this as well and in which they joined the same record in order to make this work, but I didn't get that to work. Besides, I thank that shouldn't be the way to order the contents of a column.

Does anyone have a clue?

Update in reaction to Hibatallah Aouadni's answer

As Hibatallah suggests, I added the following to my PlaylistsAdmin:

protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
    $datagridMapper
        ->add('id')
        ->add('playlist_date')
        ->add('created');
}

This resulted in the following error message:

Notice: Undefined index: playlist_date

So I inspected my Entity and I found that it has a UniqueConstraint:

uniqueConstraints={@ORM\UniqueConstraint(name="playlist_date", columns={"playlist_date"})}

It does not have an actual "index" defined, but ofcourse it is. However as a test I added the following:

, indexes={@ORM\Index(name="playlist_date", columns={"playlist_date"})}

This didn't give any different result. So still no luck at all :(

** Entity and Entity admin **

Entity Admin:

<?php

namespace Company\AdminBundle\Admin;

use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Show\ShowMapper;
use Sonata\AdminBundle\Route\RouteCollection;

class PlaylistsAdmin extends Admin
{
    protected $baseRoutePattern = 'playlists';
    protected $baseRouteName = 'playlists';

    protected function configureRoutes(RouteCollection $collection) {
        $collection->clearExcept(array('list', 'delete', 'show'));
    }

    /**
     * @param ListMapper $listMapper
     */
    protected function configureListFields(ListMapper $listMapper) {
        $listMapper
            ->add('id')
            ->add('playlist_date', 'date', array('label' => 'Playlist'))
            ->add('created', 'datetime', array('label' => 'Aangemaakt op'))
            ->add(
                '_action', 'actions', array(
                'actions' => array(
                    'show' => array(),
                    /*'edit' => array(),*/
                    'delete' => array(),
                )
            )
            );
    }

    public function getBatchActions() {
        return array();
    }
}

Entity:

<?php

namespace Company\AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Playlist
 *
 * @ORM\Table(name="playlist", uniqueConstraints={@ORM\UniqueConstraint(name="playlist_date", columns={"playlist_date"})})
 * @ORM\Entity()
 */
class Playlist
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", options={"unsigned"=true})
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    protected $id;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="playlist_date", type="date", nullable=true)
     */
    protected $playlistDate;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="created", type="datetime", nullable=true)
     */
    protected $created;

    /**
     * @var \Doctrine\Common\Collections\Collection
     */
    protected $video;

    /**
     * Constructor
     */
    public function __construct() {
        $this->video = new \Doctrine\Common\Collections\ArrayCollection();
        $this->setCreated(new \DateTime());
    }

    /**
     * Get id
     *
     * @return integer
     */
    public function getId() {
        return $this->id;
    }

    /**
     * Set playlistDate
     *
     * @param \DateTime $playlistDate
     * @return Playlist
     */
    public function setPlaylistDate($playlistDate) {
        $this->playlistDate = $playlistDate;

        return $this;
    }

    /**
     * Get playlistDate
     *
     * @return \DateTime
     */
    public function getPlaylistDate() {
        return $this->playlistDate;
    }

    /**
     * Set created
     *
     * @param \DateTime $created
     * @return Playlist
     */
    public function setCreated($created) {
        $this->created = $created;

        return $this;
    }

    /**
     * Get created
     *
     * @return \DateTime
     */
    public function getCreated() {
        return $this->created;
    }

    /**
     * Add video
     *
     * @param \Company\AppBundle\Entity\Video $video
     * @return Playlist
     */
    public function addVideo(\Company\AppBundle\Entity\Video $video) {
        $this->video[] = $video;

        return $this;
    }

    /**
     * Remove video
     *
     * @param \Company\AppBundle\Entity\Video $video
     */
    public function removeVideo(\Company\AppBundle\Entity\Video $video) {
        $this->video->removeElement($video);
    }

    /**
     * Get video
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getVideo() {
        return $this->video;
    }
}

Solution

  • Finally I found it, it's so absurd, in the configureListFields method, you have to call the attribute with its name not the DataBase name, so:

    change

    ->add('playlist_date', 'date', array('label' => 'Playlist'))
    

    to

    ->add('playlistDate', 'date', array('label' => 'Playlist'))
    

    :D I can't beleive we spend all this time for some absurd mistake ;)