Comment trier la méthode de findAll Doctrine

111

J'ai lu la documentation de Doctrine, mais je n'ai pas réussi à trouver un moyen de trier les résultats de findAll ().

J'utilise la doctrine symfony2 +, c'est la déclaration que j'utilise dans mon Controller:

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

mais je veux que les résultats soient classés par nom d'utilisateur croissant.

J'ai essayé de passer un tableau comme argument de cette façon:

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

mais ça ne marche pas (ça ne se plaint pas non plus).

Existe-t-il un moyen de le faire sans créer une requête DQL?

J'aime les tacos
la source

Réponses:

229

Comme @Lighthart comme indiqué, oui, c'est possible, bien que cela ajoute beaucoup de graisse au contrôleur et ne soit pas SEC.

Vous devez vraiment définir votre propre requête dans le référentiel d'entités, c'est simple et la meilleure pratique.

use Doctrine\ORM\EntityRepository;

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

Ensuite, vous devez dire à votre entité de rechercher les requêtes dans le référentiel:

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

Enfin, dans votre contrôleur:

$this->getDoctrine()->getRepository('AcmeBundle:User')->findAll();
Pier-Luc Gendreau
la source
2
C'est une meilleure approche que la mienne, mais vous allez écrire dql; ma méthode a moins de dql et répond donc à la contrainte de l'OP. Franchement, la peur de dql devrait simplement être surmontée. Utilisez cette méthode de préférence à la mienne si possible.
Lighthart
eh bien ce n'est pas la peur de dql, et avant de lire cette réponse j'ai finalement utilisé DQL pour y parvenir, mais je ne voulais pas utiliser DQL au début car mon contrôleur n'avait pas de DQL dedans, et je voulais m'en tenir au le style de code que le contrôleur avait déjà. Cette solution fonctionne vraiment bien pour moi!
ILikeTacos
1
Ou simplement: $ this-> getDoctrine () -> getRepository ('AcmeBundle: User') -> findBy (array (), array ('username' => 'ASC'));
Benji_X80
1
@ Benji_X80 Bien que cette ligne unique soit certainement plus courte, elle n'est pas du tout SÈCHE. La méthode findAll appartient au référentiel, pas au contrôleur.
Pier-Luc Gendreau
1
Pouvez-vous dire à l'entité de rechercher des requêtes dans le référentiel personnalisé d'une autre manière que d'utiliser des commentaires? C'est la pratique de programmation la plus terrible que j'ai jamais vue
Sejanus
81
$this->getDoctrine()->getRepository('MyBundle:MyTable')->findBy([], ['username' => 'ASC']);
Stiig
la source
24

Facile:

$this->getDoctrine()->getRepository('AcmeBundle:User')->findBy(
    array(),
    array('username' => 'ASC')
);
Daniele Dolci
la source
Cela a fonctionné comme un charme! Et fonctionne toujours exactement de cette façon avec Symfony 4
Robert Saylor
20

Il est parfois utile de consulter le code source.

Par exemple, l' findAllimplémentation est très simple ( vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php):

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

Donc nous regardons findByet trouvons ce dont nous avons besoin ( orderBy)

public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
Luchaninov
la source
6

Cela fonctionne pour moi:

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

Garder le premier tableau vide récupère toutes les données, cela a fonctionné dans mon cas.

Buttler
la source
5

Regardez le code source de l'API Doctrine:

class EntityRepository{
  ...
  public function findAll(){
    return $this->findBy(array());
  }
  ...
}
Gilles Vanderstraeten
la source
Cet extrait de code ne trie rien
Nico Haase
5

Vous devez utiliser un critère, par exemple:

<?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,
        ]);
    }
}
Lighthart
la source
4

La méthode findBy de Symfony exclut deux paramètres. Le premier est le tableau des champs sur lesquels vous souhaitez effectuer la recherche et le deuxième tableau est le champ de tri et son ordre

public function findSorted()
    {
        return $this->findBy(['name'=>'Jhon'], ['date'=>'DESC']);
    }
Shaz
la source
Pouvez-vous ajouter quelques explications à votre réponse très courte?
Nico Haase
C'est une réponse courte et puissante. Élaborer - expliquer ... modifier .
Paul Hodges
c'était la réponse parfaite! findBy (array (), array ('fieldname' => 'ASC') Cela va tout trouver et trier sur le champ avec la direction indiquée.
Robert Saylor
2

Vous pouvez trier un ArrayCollection existant à l'aide d'un itérateur de tableau.

en supposant que $ collection est votre ArrayCollection retournée par findAll ()

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

Cela peut facilement être transformé en une fonction que vous pouvez mettre dans votre référentiel afin de créer la méthode findAllOrderBy ().

Nicolai Fröhlich
la source
4
Quel est votre point ici? Il y a plus qu'assez de cas d'utilisation pour cela ... c'est-à-dire que le tri d'une collection déjà récupérée en PHP est toujours plus rapide que d'effectuer une autre requête mysql juste pour le tri! Imaginez que vous ayez besoin de produire les mêmes données de collection dans deux styles de tri différents sur une seule page ...
Nicolai Fröhlich
2
En général, renvoyer une requête ordonnée doit être le travail de la base de données. OTOH, cette technique a une applicabilité aux cas les plus impliqués que nifr mentionne.
Lighthart
2

Essaye ça:

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

$entities = $em->getRepository('MyBundle:MyTable')->findBy(array(), array('username' => 'ASC'));
Mahdi Dhifi
la source
1

J'utilise une alternative à la solution qui a écrit nifr.

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

C'est plus rapide que la clause ORDER BY et sans la surcharge de l'itérateur.

Moisés Márquez
la source
Veuillez ajouter quelques explications supplémentaires à votre réponse. Comment le tri dans votre application pourrait-il être plus rapide que le faire au niveau de la base de données?
Nico Haase le
0

Modifiez la fonction findAll par défaut dans EntityRepository comme ceci:

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

De cette façon, vous pouvez utiliser le '' findAll '' sur n'importe quelle requête pour n'importe quelle table de données avec une option pour trier la requête

Niksa
la source