Jak posortować metodę findAll Doctrine


111

Czytałem dokumentację Doctrine, ale nie byłem w stanie znaleźć sposobu sortowania wyników findAll ().

Używam doktryny symfony2 +, oto stwierdzenie, którego używam w moim kontrolerze:

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

ale chcę, aby wyniki były uporządkowane według rosnących nazw użytkowników.

Próbowałem przekazać tablicę jako argument w ten sposób:

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

ale to nie działa (też nie narzeka).

Czy można to zrobić bez tworzenia zapytania DQL?

Odpowiedzi:


229

Jak pokazano na @Lighthart, tak jest to możliwe, chociaż dodaje znaczną ilość tłuszczu do kontrolera i nie jest SUCHY.

Naprawdę powinieneś zdefiniować własne zapytanie w repozytorium encji, jest to proste i najlepsze rozwiązanie.

use Doctrine\ORM\EntityRepository;

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

Następnie musisz powiedzieć swojej encji, aby szukała zapytań w repozytorium:

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

Wreszcie w kontrolerze:

$this->getDoctrine()->getRepository('AcmeBundle:User')->findAll();

2
To lepsze podejście niż moje, ale będziesz pisać dql; moja metoda ma mniej dql, więc odpowiada na ograniczenie OP. Szczerze mówiąc, strach przed dql powinien zostać przezwyciężony. Jeśli to możliwe, używaj tej metody zamiast mojej.
Lighthart

cóż, to nie jest strach przed dql, a przed przeczytaniem tej odpowiedzi ostatecznie użyłem DQL, aby to osiągnąć, ale nie chciałem używać DQL na początku, ponieważ mój kontroler nie miał w nim żadnego DQL, a chciałem się trzymać styl kodu, który kontroler już miał. To rozwiązanie działa na mnie naprawdę dobrze!
ILikeTacos

1
Lub po prostu: $ this-> getDoctrine () -> getRepository ('AcmeBundle: User') -> findBy (array (), array ('username' => 'ASC'));
Benji_X80,

1
@ Benji_X80 Chociaż ta jedna linijka jest z pewnością krótsza, wcale nie jest SUCHA. Metoda findAll należy do repozytorium, a nie do kontrolera.
Pier-Luc Gendreau

1
Czy możesz powiedzieć encji, aby szukała zapytań w repozytorium niestandardowym w inny sposób niż za pomocą komentarzy? To najstraszniejsza praktyka programistyczna, jaką kiedykolwiek widziałem
Sejanus

81
$this->getDoctrine()->getRepository('MyBundle:MyTable')->findBy([], ['username' => 'ASC']);

24

Prosty:

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

To zadziałało jak urok! I nadal działa dokładnie w ten sposób z Symfony 4
Robert Saylor

20

Czasami warto spojrzeć na kod źródłowy.

Na przykład findAllimplementacja jest bardzo prosta ( vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php):

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

Więc patrzymy findByi znajdujemy to, czego potrzebujemy ( orderBy)

public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)

6

To działa dla mnie:

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

Pozostawienie pierwszej tablicy pustej powoduje odzyskanie wszystkich danych, w moim przypadku zadziałało.


5

Spójrz na kod źródłowy Doctrine API:

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

Ten fragment kodu niczego nie sortuje
Nico Haase

5

Musisz użyć kryteriów, na przykład:

<?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

findBy w Symfony oprócz dwóch parametrów. Pierwsza to tablica pól, które chcesz przeszukać, a druga to pole sortowania i jego kolejność

public function findSorted()
    {
        return $this->findBy(['name'=>'Jhon'], ['date'=>'DESC']);
    }

Czy możesz dodać wyjaśnienie do swojej bardzo krótkiej odpowiedzi?
Nico Haase,

To bardzo krótka odpowiedź. Opracuj - wyjaśnij ... edytuj .
Paul Hodges

to była doskonała odpowiedź! findBy (array (), array ('fieldname' => 'ASC') To znajdzie wszystko i posortuje według wskazanego kierunku.
Robert Saylor

2

Możesz posortować istniejącą kolekcję ArrayCollection za pomocą iteratora tablicy.

zakładając, że $ collection jest Twoim ArrayCollection zwróconym przez findAll ()

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

Można to łatwo przekształcić w funkcję, którą można umieścić w repozytorium w celu utworzenia metody findAllOrderBy ().


4
O co ci tu chodzi? Jest więcej niż wystarczająco przypadków użycia do tego ... tj. Sortowanie już pobranej kolekcji w PHP jest zawsze szybsze niż wykonywanie kolejnego zapytania mysql tylko do sortowania! Wyobraź sobie, że musisz wydrukować te same dane kolekcji w dwóch różnych stylach sortowania na jednej stronie ...
Nicolai Fröhlich

2
Ogólnie rzecz biorąc, zwrócenie uporządkowanego zapytania powinno być zadaniem bazy danych. OTOH, ta technika ma zastosowanie w bardziej skomplikowanych przypadkach, o których wspomina nifr.
Lighthart

2

Spróbuj tego:

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

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

1

Używam alternatywy dla rozwiązania, które napisał nifr.

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

Jest szybszy niż klauzula ORDER BY i bez narzutu Iteratora.


Dodaj dodatkowe wyjaśnienie do swojej odpowiedzi. Jak sortowanie w twojej aplikacji może być szybsze niż robienie tego na poziomie bazy danych?
Nico Haase

0

Zmodyfikuj domyślną funkcję findAll w EntityRepository w następujący sposób:

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

W ten sposób możesz użyć funkcji „findAll” w każdym zapytaniu dla dowolnej tabeli danych z opcją sortowania zapytania

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.