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?

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();

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']);

24

Facile:

$this->getDoctrine()->getRepository('AcmeBundle:User')->findBy(
    array(),
    array('username' => 'ASC')
);

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)

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.


5

Regardez le code source de l'API Doctrine:

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

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,
        ]);
    }
}

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']);
    }

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 ().


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'));

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.


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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.