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.