title: Admin Page Column Sorting
body: <p>We're using the Sonata bundle for our admin section. When a user goes to any section in admin, products for instance, and tries to sort by a particular column, it doesn't remember the sort order in the next page and also, the user can only sort in one direction.I don't know how to fixed it?</p>
  
  <p>Here my code where I extend Sonata admin class:</p>
  
  <pre><code>namespace Project\AdminBundle\Admin;
  
  use Sonata\AdminBundle\Admin\Admin;
  use Doctrine\ORM\EntityManager;
  use Sonata\AdminBundle\Datagrid\DatagridMapper;
  use Sonata\AdminBundle\Datagrid\ListMapper;
  use Sonata\AdminBundle\Show\ShowMapper;
  use Sonata\AdminBundle\Form\FormMapper;
  use Sonata\AdminBundle\Route\RouteCollection;
  
  abstract class AbstractAdmin extends Admin
  {
  /** @var int */
  protected $maxPerPage = 10;
  
  /** @var int */
  protected $maxPageLinks = 30;
  
  /** @var \Doctrine\ORM\Mapping\ClassMetadata */
  protected $metadata;
  
  /** @var Doctrine\ORM\EntityManager $entityManager */
  protected $entityManager;
  
  /** @var array */
  protected $forbiddenFormFields = array(
      'id', 'createdAt', 'updatedAt', 'publishedAt', 'notifiedAt'
  );
  
  /** @var array */
  protected $optionalFormFields = array(
      'slug'
  );
  
  /** @var array */
  protected $forbiddenShowFields = array(
      'id'
  );
  
  /** @var array */
  protected $forbiddenDatagridFields = array(
      'createdAt', 'updatedAt', 'publishedAt', 'notifiedAt'
  );
  
  /** @var array */
  protected $forbiddenDatagridTypes = array(
      'datetime', 'date', 'float', 'decimal'
  );
  
  /** @var array */
  protected $forbiddenListFields = array();
  
  /** @var array */
  protected $listIdentifierFields = array(
      'id', 'name', 'slug', 'symbol'
  );
  
  /** @var array */
  public $leftMostFields = array(
      'id', 'name', 'slug'
  );
  
  /** @var array */
  public $rightMostFields = array(
      'notifiedAt', 'createdAt', 'updatedAt', 'publishedAt',
  );
  
  /** @var array */
  public $fields;
  
  /**
   * Extended constructor with Entity Manager
   *
   * @param string                     $code
   * @param string                     $class
   * @param string                     $baseControllerName
   * @param Doctrine\ORM\EntityManager $entityManager
   */
  public function __construct($code, $class, $baseControllerName,
                              $entityManager)
  {
      parent::__construct($code, $class, $baseControllerName);
      $this-&gt;entityManager = $entityManager;
      $this-&gt;metadata      = $entityManager-&gt;getClassMetadata($class);
      $fields = array_merge($this-&gt;metadata-&gt;getAssociationNames(),
          $this-&gt;metadata-&gt;getFieldNames());
      $this-&gt;fields = $this-&gt;sortFields($fields);
  
      // Set default ordering of lists
      if (!$this-&gt;hasRequest()) {
          $this-&gt;datagridValues = array(
              '_page'       =&gt; 1,
              '_sort_order' =&gt; 'DESC',
              '_sort_by'    =&gt; 'updatedAt'
          );
      }
  }
  
  /**
   * @param FormMapper $mapper
   */
  protected function configureFormFields(FormMapper $mapper)
  {
      parent::configureFormFields($mapper);
      foreach ($this-&gt;fields as $field) {
          $options = array();
          $type = $this-&gt;metadata-&gt;getTypeOfField($field);
  
          if (in_array($type, array('bool', 'boolean'))) {
              $options['required'] = false;
          }
  
          if (in_array($field, $this-&gt;forbiddenFormFields)) {
              continue;
          }
  
          if (in_array($field, $this-&gt;optionalFormFields)) {
              $options['required'] = false;
          }
  
          if ($this-&gt;metadata-&gt;isAssociationWithSingleJoinColumn($field)) {
              $assoc = $this-&gt;metadata-&gt;getAssociationMapping($field);
              if (@$assoc['joinColumns']['0']['nullable']) {
                  $options['required'] = false;
              }
          }
  
          $associations = $this-&gt;metadata-&gt;getAssociationMappings();
          if (isset($associations[$field])) {
              $options['attr'] = array('class' =&gt; 'chzn-select');
              if ((isset($associations[$field]['joinTable'])) ||
                 (!$associations[$field]['isOwningSide'])) {
                  $options['required'] = false;
              }
          }
  
          $mapper-&gt;add($field, null, $options);
      }
  }
  
  /**
   * @param ShowMapper $mapper
   */
  protected function configureShowFields(ShowMapper $mapper)
  {
      parent::configureShowFields($mapper);
      foreach ($this-&gt;fields as $field) {
          if (in_array($field, $this-&gt;forbiddenShowFields)) {
              continue;
          }
          $mapper-&gt;add($field);
      }
  }
  
  /**
   * @param DatagridMapper $mapper
   *
   * @return void
   */
  protected function configureDatagridFilters(DatagridMapper $mapper)
  {
      parent::configureDatagridFilters($mapper);
      foreach ($this-&gt;fields as $field) {
          $type = $this-&gt;metadata-&gt;getTypeOfField($field);
          if (in_array($field, $this-&gt;forbiddenDatagridFields)) {
              continue;
          }
          if (in_array($type, $this-&gt;forbiddenDatagridTypes)) {
              continue;
          }
          $mapper-&gt;add($field);
      }
  }
  
  /**
   * @param ListMapper $mapper
   */
  protected function configureListFields(ListMapper $mapper)
  {
      parent::configureListFields($mapper);
  
      foreach ($this-&gt;fields as $field) {
          if (in_array($field, $this-&gt;forbiddenListFields)) {
              continue;
          }
  
          if (in_array($field, $this-&gt;listIdentifierFields)) {
              $mapper-&gt;addIdentifier($field, null, array('route' =&gt; array('name' =&gt; 'show')));
          } else {
              $mapper-&gt;add($field);
          }
      }
  }
  
  /**
   * @throws \Exception
   */
  public function sortFields($fields)
  {
      $leftMost = $this-&gt;leftMostFields;
      $rightMost = $this-&gt;rightMostFields;
  
      usort($fields, function($a, $b) use ($leftMost, $rightMost) {
          if (count(array_intersect($leftMost, $rightMost)) != 0) {
              throw new \Exception('Leftmost and Rightmost must differ');
          }
  
          $leftPosA = array_search($a, $leftMost);
          $isALeftMost = is_integer($leftPosA);
          $rightPosA = array_search($a, $rightMost);
          $isARightMost = is_integer($rightPosA);
  
          $leftPosB = array_search($b, $leftMost);
          $isBLeftMost = is_integer($leftPosB);
          $rightPosB = array_search($b, $rightMost);
          $isBRightMost = is_integer($rightPosB);
  
          if ($isALeftMost &amp;&amp; $isBLeftMost) {
              return $leftPosA - $leftPosB;
          }
          if ($isARightMost &amp;&amp; $isBRightMost) {
              return $rightPosA - $rightPosB;
          }
          if ($isALeftMost || $isBRightMost){
              return -1;
          }
          if ($isARightMost || $isBLeftMost) {
              return 1;
          }
          return strnatcasecmp($a, $b);
      });
  
      return $fields;
  }
  }
  </code></pre>
  
  <p>When we added "sort_by" in twig file.It is work only 1 to 9 pages when we go 1 to 11 or 9 to 10 then it doesn't remember the sort order in the next page.</p>
  
  <p>Twig file :</p>
  
  <pre><code>&lt;div class="pagination"&gt;
  &lt;ul&gt;
                                      {% if admin.datagrid.pager.page != 1  %}
                                          &lt;li&gt;&lt;a href="{{ admin.generateUrl('list', admin.modelmanager.paginationparameters(admin.datagrid, 1)) }}" title="{% trans from 'SonataAdminBundle' %}link_first_pager{% endtrans %}"&gt;&amp;laquo;&lt;/a&gt;&lt;/li&gt;
                                      {% endif %}
  
                                      {% if admin.datagrid.pager.page != admin.datagrid.pager.previouspage %}
                                          &lt;li&gt;&lt;a href="{{ admin.generateUrl('list', admin.modelmanager.paginationparameters(admin.datagrid, admin.datagrid.pager.previouspage)) }}" title="{% trans from 'SonataAdminBundle' %}link_previous_pager{% endtrans %}"&gt;&amp;lsaquo;&lt;/a&gt;&lt;/li&gt;
                                      {% endif %}
  
                                      {# Set the number of pages to display in the pager #}
                                      {% for page in admin.datagrid.pager.getLinks() %}
                                          {% if page == admin.datagrid.pager.page %}
                                              &lt;li class="active"&gt;&lt;a href="{{ admin.generateUrl('list', admin.modelmanager.paginationparameters(admin.datagrid, page)) }}{{sortBy}}"&gt;{{ page }}&lt;/a&gt;&lt;/li&gt;
                                          {% else %}
                                              &lt;li&gt;&lt;a href="{{ admin.generateUrl('list', admin.modelmanager.paginationparameters(admin.datagrid, page)) }}{{sortBy}}"&gt;{{ page }}&lt;/a&gt;&lt;/li&gt;
                                          {% endif %}
                                      {% endfor %}
  
                                      {% if admin.datagrid.pager.page != admin.datagrid.pager.nextpage %}
                                          &lt;li&gt;&lt;a href="{{ admin.generateUrl('list', admin.modelmanager.paginationparameters(admin.datagrid, admin.datagrid.pager.nextpage)) }}" title="{% trans from 'SonataAdminBundle' %}link_next_pager{% endtrans %}"&gt;&amp;rsaquo;&lt;/a&gt;&lt;/li&gt;
                                      {% endif %}
  
                                      {% if admin.datagrid.pager.page != admin.datagrid.pager.lastpage  %}
                                          &lt;li&gt;&lt;a href="{{ admin.generateUrl('list', admin.modelmanager.paginationparameters(admin.datagrid, admin.datagrid.pager.lastpage)) }}" title="{% trans from 'SonataAdminBundle' %}link_last_pager{% endtrans %}"&gt;&amp;raquo;&lt;/a&gt;&lt;/li&gt;
                                      {% endif %}
  </code></pre>
  
  <p>
  </p>