140

I've been reading Doctrine's documentation, but I haven't been able to find a way to sort findAll() Results.

I'm using symfony2 + doctrine, this is the statement that I'm using inside my Controller:

$this->getDoctrine()->getRepository('MyBundle:MyTable')->findAll();

but I want the results to be ordered by ascending usernames.

I've been trying to pass an array as an argument this way:

findAll( array('username' => 'ASC') );

but it doesn't work (it doesn't complain either).

Is there any way to do this without building a DQL query?

simhumileco
  • 31,877
  • 16
  • 137
  • 115
ILikeTacos
  • 17,464
  • 20
  • 58
  • 88

12 Answers12

258

As @Lighthart as shown, yes it's possible, although it adds significant fat to the controller and isn't DRY.

You should really define your own query in the entity repository, it's simple and best practice.

use Doctrine\ORM\EntityRepository;

class UserRepository extends EntityRepository
{
    public function findAll()
    {
        return $this->findBy(array(), array('username' => 'ASC'));
    }
}

Then you must tell your entity to look for queries in the repository:

/**
 * @ORM\Table(name="User")
 * @ORM\Entity(repositoryClass="Acme\UserBundle\Entity\Repository\UserRepository")
 */
class User
{
    ...
}

Finally, in your controller:

$this->getDoctrine()->getRepository('AcmeBundle:User')->findAll();
Lighthart
  • 3,648
  • 6
  • 28
  • 47
Pier-Luc Gendreau
  • 13,553
  • 4
  • 58
  • 69
  • 3
    This is a better approach than mine, but you will be writing dql; my method has less dql and so answers the OP's constraint. Frankly, fear of dql should just be overcome. Use this method in preference to mine if at all possible. – Lighthart Jun 15 '13 at 08:22
  • 1
    well it's not fear of dql, and before reading this answer I ultimately used DQL to achieve this, but I didn't want to use DQL at the beginning because my controller did not have any DQL in it, and I wanted to stick to the code style the controller already had. This solutions works really good for me! – ILikeTacos Jun 15 '13 at 16:22
  • 3
    Or simply : $this->getDoctrine()->getRepository('AcmeBundle:User')->findBy(array(), array('username' => 'ASC')); – Benji_X80 Oct 23 '14 at 09:54
  • 2
    @Benji_X80 While that one-liner is certainly shorter, it is not DRY at all. The findAll method belongs to the repository, not the controller. – Pier-Luc Gendreau Oct 23 '14 at 15:34
  • 2
    Can you tell entity to look for queries in the custom repository in any other way than using comments? It's the most terrible programming practice I've ever seen – Sejanus Dec 15 '14 at 10:04
  • 1
    @Sejanus That's how the docs want you to do it: http://symfony.com/doc/current/book/doctrine.html#custom-repository-classes – Pier-Luc Gendreau Dec 15 '14 at 19:55
  • 1
    For those of you who want to sort on an associated entity, see http://stackoverflow.com/questions/22828669/ordering-doctrine-collection-based-on-associated-entity-when-it-is-not-possible – eddy147 Oct 11 '16 at 09:59
  • 1
    I find it easier to just call the function `findBy()` directly rather than enmaskarating it as a `findAll()` – S. Dre May 06 '22 at 07:18
92
$this->getDoctrine()->getRepository('MyBundle:MyTable')->findBy([], ['username' => 'ASC']);
Stiig
  • 1,265
  • 13
  • 19
29

Simple:

$this->getDoctrine()->getRepository('AcmeBundle:User')->findBy(
    array(),
    array('username' => 'ASC')
);
Daniele Dolci
  • 884
  • 1
  • 9
  • 22
25

It's useful to look at source code sometimes.

For example findAll implementation is very simple (vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php):

public function findAll()
{
    return $this->findBy(array());
}

So we look at findBy and find what we need (orderBy)

public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
luchaninov
  • 6,792
  • 6
  • 60
  • 75
8

This works for me:

$entities = $em->getRepository('MyBundle:MyTable')->findBy(array(),array('name' => 'ASC'));

Keeping the first array empty fetches back all data, it worked in my case.

Bono
  • 4,757
  • 6
  • 48
  • 77
Buttler
  • 81
  • 1
  • 1
8

findBy method in Symfony excepts two parameters. First is array of fields you want to search on and second array is the the sort field and its order

public function findSorted()
    {
        return $this->findBy(['name'=>'Jhon'], ['date'=>'DESC']);
    }
Shaz
  • 419
  • 3
  • 11
7

Look at the Doctrine API source-code :

class EntityRepository{
  ...
  public function findAll(){
    return $this->findBy(array());
  }
  ...
}
John Slegers
  • 45,213
  • 22
  • 199
  • 169
6

You need to use a criteria, for example:

<?php

namespace Bundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Doctrine\Common\Collections\Criteria;

/**
* Thing controller
*/
class ThingController extends Controller
{
    public function thingsAction(Request $request, $id)
    {
        $ids=explode(',',$id);
        $criteria = new Criteria(null, <<DQL ordering expression>>, null, null );

        $rep    = $this->getDoctrine()->getManager()->getRepository('Bundle:Thing');
        $things = $rep->matching($criteria);
        return $this->render('Bundle:Thing:things.html.twig', [
            'entities' => $things,
        ]);
    }
}
luchaninov
  • 6,792
  • 6
  • 60
  • 75
Lighthart
  • 3,648
  • 6
  • 28
  • 47
3

You can sort an existing ArrayCollection using an array iterator.

assuming $collection is your ArrayCollection returned by findAll()

$iterator = $collection->getIterator();
$iterator->uasort(function ($a, $b) {
    return ($a->getPropery() < $b->getProperty()) ? -1 : 1;
});
$collection = new ArrayCollection(iterator_to_array($iterator));

This can easily be turned into a function you can put into your repository in order to create findAllOrderBy() method.

Nicolai Fröhlich
  • 51,330
  • 11
  • 126
  • 130
  • 5
    What's your point here? There are more than enough use-cases for this ... i.e. sorting an already fetched collection in PHP is always faster than performing another mysql query just for sorting! Imagine you need to output the same collection data in two different sorting styles on one page ... – Nicolai Fröhlich Oct 21 '13 at 13:36
  • 3
    In general, returning an ordered query should be the database's job. OTOH, this technique does have applicability to the more involved cases nifr mentions. – Lighthart Jan 23 '14 at 19:06
3

Try this:

$em = $this->getDoctrine()->getManager();

$entities = $em->getRepository('MyBundle:MyTable')->findBy(array(), array('username' => 'ASC'));
ZygD
  • 22,092
  • 39
  • 79
  • 102
Mahdi Dhifi
  • 129
  • 1
  • 1
2

I use an alternative to the solution that wrote nifr.

$resultRows = $repository->fetchAll();
uasort($resultRows, function($a, $b){
    if ($a->getProperty() == $b->getProperty()) {
        return 0;
    }
    return ($a->getProperty()< $b->getProperty()) ? -1 : 1;
});

It's quicker than the ORDER BY clause, and without the overhead of the Iterator.

  • 1
    Please add some further explanation to your answer. How could sorting in your application be faster than doing it on the database level? – Nico Haase Jun 29 '20 at 10:34
2

Modify the default findAll function in EntityRepository like this:

public function findAll( array $orderBy = null )
{
    return $this->findBy([], $orderBy);
}

That way you can use the ''findAll'' on any query for any data table with an option to sort the query

niksa
  • 21
  • 1