← back to archive

September 17, 2013

Setting a default order for Doctrine 2 / Symfony 2

by Jurgens du Toit

Usually when you’re working with data you expect some kind of default ordering. It might be the primary key, or, more commonly, the data set will be ordered by a timestamp field or the data’s most important property. In Doctrine you can create custom repository classes to tweak queries to your liking:

  <?php
  // src/Acme/StoreBundle/Entity/ProductRepository.php
  namespace Acme\StoreBundle\Entity;
  
  use Doctrine\ORM\EntityRepository;
  
  class ProductRepository extends EntityRepository
  {
      public function findAllOrderedByName()
      {
          return $this->getEntityManager()
              ->createQuery(
                  'SELECT p FROM AcmeStoreBundle:Product p ORDER BY p.name ASC'
              )
              ->getResult();
      }
  }
  ?>
  

This is all fine and dandy, but do you really want to repeat yourself everytime you write a query for a model that will almost always be ordered by the same field? Or get caught out by calls to default repository methods that don’t use the ordering you like? No, you don’t. Enter this piece of code:

  <?php
  // src/Acme/StoreBundle/Entity/ProductRepository.php
  namespace Acme\StoreBundle\Entity;
  
  use Doctrine\ORM\EntityRepository;
  
  class ProductRepository extends EntityRepository
  {
      public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
      {
          // Default Ordering
          $orderBy = $orderBy === null ? array('added' => 'desc') : $orderBy;
  
          // Default Filtering
          if (array_key_exists('active', $criteria) === false) {
              $criteria['active'] = 1;
          }
          return parent::findBy($criteria, $orderBy, $limit, $offset);
      }
  }
  ?>
  

The findBy method of the EntityRepository class is the method used by most (if not all) of the the repository methods that fetch data. This includes findBy methods where you can specify an arbitrary column and value:

  <?php
  // find a group of products based on an arbitrary column value
  $products = $repository->findByPrice(19.99);
  ?>
  

So to ensure a default ordering, we override this method and check if an orderBy clause has been set. If not, set it to our default ordering — in this case by the added field, descending. For good measure we also add default filtering — the active field needs to equal 1. Once that’s done, call the parent method with the default values set.

Easy as π

← more posts