Come ordinare il metodo findAll Doctrine


111

Ho letto la documentazione di Doctrine, ma non sono riuscito a trovare un modo per ordinare i risultati findAll ().

Sto usando symfony2 + doctrine, questa è l'affermazione che sto usando nel mio controller:

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

ma desidero che i risultati vengano ordinati in base a nomi utente crescenti.

Ho provato a passare un array come argomento in questo modo:

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

ma non funziona (non si lamenta neanche).

C'è un modo per farlo senza creare una query DQL?

Risposte:


229

Come mostrato da @Lighthart, sì, è possibile, anche se aggiunge una quantità significativa di grasso al controller e non è DRY.

Dovresti davvero definire la tua query nel repository di entità, è semplice e best practice.

use Doctrine\ORM\EntityRepository;

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

Quindi devi dire alla tua entità di cercare le query nel repository:

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

Infine, nel controller:

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

2
Questo è un approccio migliore del mio, ma scriverai dql; il mio metodo ha meno dql e quindi risponde al vincolo dell'OP. Francamente, la paura di dql dovrebbe essere superata. Usa questo metodo al posto del mio, se possibile.
Lighthart

beh, non ha paura di dql, e prima di leggere questa risposta alla fine ho usato DQL per raggiungere questo obiettivo, ma non volevo usare DQL all'inizio perché il mio controller non aveva alcun DQL in esso, e volevo attenermi al stile di codice che il controller aveva già. Questa soluzione funziona davvero bene per me!
ILikeTacos

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

1
@ Benji_X80 Anche se quella riga è certamente più corta, non è affatto ASCIUTTA. Il metodo findAll appartiene al repository, non al controller.
Pier-Luc Gendreau

1
Puoi dire all'entità di cercare le query nel repository personalizzato in un modo diverso dall'uso dei commenti? È la pratica di programmazione più terribile che abbia mai visto
Sejanus

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

24

Semplice:

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

Ha funzionato a meraviglia! E funziona ancora esattamente in questo modo con Symfony 4
Robert Saylor

20

A volte è utile guardare il codice sorgente.

Ad esempio l' findAllimplementazione è molto semplice ( vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php):

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

Quindi guardiamo findBye troviamo ciò di cui abbiamo bisogno ( orderBy)

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

6

Questo funziona per me:

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

Mantenere vuoto il primo array recupera tutti i dati, ha funzionato nel mio caso.


5

Guarda il codice sorgente dell'API di Doctrine:

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

Questo frammento di codice non ordina nulla
Nico Haase,

5

È necessario utilizzare un criterio, ad esempio:

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

Il metodo findBy in Symfony esclude due parametri. Il primo è l'array di campi in cui vuoi cercare e il secondo array è il campo di ordinamento e il suo ordine

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

Puoi aggiungere qualche spiegazione alla tua brevissima risposta?
Nico Haase

Questa è una potente risposta breve. Elaborare - spiegare ... modificare .
Paul Hodges

quella era la risposta perfetta! findBy (array (), array ('fieldname' => 'ASC') Questo troverà tutto e ordinerà nel campo con la direzione indicata.
Robert Saylor,

2

È possibile ordinare un ArrayCollection esistente utilizzando un iteratore di array.

supponendo che $ collection sia il tuo ArrayCollection restituito da findAll ()

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

Questo può essere facilmente trasformato in una funzione che puoi inserire nel tuo repository per creare il metodo findAllOrderBy ().


4
Qual è il tuo punto qui? Ci sono più che sufficienti casi d'uso per questo ... cioè ordinare una raccolta già recuperata in PHP è sempre più veloce che eseguire un'altra query mysql solo per l'ordinamento! Immagina di dover produrre gli stessi dati di raccolta in due diversi stili di ordinamento su una pagina ...
Nicolai Fröhlich

2
In generale, la restituzione di una query ordinata dovrebbe essere compito del database. OTOH, questa tecnica ha applicabilità ai casi più coinvolti menzionati da nifr.
Lighthart

2

Prova questo:

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

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

1

Uso un'alternativa alla soluzione che ha scritto nifr.

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

È più veloce della clausola ORDER BY e senza l'overhead di Iterator.


Per favore aggiungi qualche ulteriore spiegazione alla tua risposta. In che modo l'ordinamento nella tua applicazione può essere più veloce che farlo a livello di database?
Nico Haase,

0

Modifica la funzione findAll predefinita in EntityRepository in questo modo:

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

In questo modo puoi utilizzare "findAll" su qualsiasi query per qualsiasi tabella di dati con un'opzione per ordinare la query

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.