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.