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?

Lubię tacos
źródło

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();
Pier-Luc Gendreau
źródło
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']);
Stiig
źródło
24

Prosty:

$this->getDoctrine()->getRepository('AcmeBundle:User')->findBy(
    array(),
    array('username' => 'ASC')
);
Daniele Dolci
źródło
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)
luchaninov
źródło
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.

Buttler
źródło
5

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

class EntityRepository{
  ...
  public function findAll(){
    return $this->findBy(array());
  }
  ...
}
Gilles Vanderstraeten
źródło
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,
        ]);
    }
}
Lighthart
źródło
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']);
    }
Shaz
źródło
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 ().

Nicolai Fröhlich
źródło
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'));
Mahdi Dhifi
źródło
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.

Moisés Márquez
źródło
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

niksa
źródło