Cómo ordenar el método de FindAll Doctrine

111

He estado leyendo la documentación de Doctrine, pero no he podido encontrar una manera de ordenar los resultados de findAll ().

Estoy usando la doctrina symfony2 +, esta es la declaración que estoy usando dentro de mi controlador:

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

pero quiero que los resultados se ordenen por nombres de usuario ascendentes.

He intentado pasar una matriz como argumento de esta manera:

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

pero no funciona (tampoco se queja).

¿Hay alguna forma de hacer esto sin crear una consulta DQL?

Me gustan los tacos
fuente

Respuestas:

229

Como se muestra en @Lighthart, sí, es posible, aunque agrega grasa significativa al controlador y no está SECO.

Realmente debería definir su propia consulta en el repositorio de entidades, es una práctica sencilla y recomendada.

use Doctrine\ORM\EntityRepository;

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

Luego debes decirle a tu entidad que busque consultas en el repositorio:

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

Finalmente, en tu controlador:

$this->getDoctrine()->getRepository('AcmeBundle:User')->findAll();
Pier-Luc Gendreau
fuente
2
Este es un enfoque mejor que el mío, pero escribirás dql; mi método tiene menos dql y, por lo tanto, responde a la restricción del OP. Francamente, el miedo a dql debería superarse. Utilice este método en lugar del mío si es posible.
Lighthart
bueno, no es miedo a dql, y antes de leer esta respuesta, finalmente usé DQL para lograr esto, pero no quería usar DQL al principio porque mi controlador no tenía ningún DQL, y quería seguir el estilo de código que el controlador ya tenía. ¡Esta solución funciona muy bien para mí!
ILikeTacos
1
O simplemente: $ this-> getDoctrine () -> getRepository ('AcmeBundle: User') -> findBy (array (), array ('username' => 'ASC'));
Benji_X80
1
@ Benji_X80 Si bien esa línea de una sola línea es ciertamente más corta, no está SECA en absoluto. El método findAll pertenece al repositorio, no al controlador.
Pier-Luc Gendreau
1
¿Puede decirle a la entidad que busque consultas en el repositorio personalizado de otra forma que no sea mediante comentarios? Es la práctica de programación más terrible que he visto en mi vida
Sejanus
81
$this->getDoctrine()->getRepository('MyBundle:MyTable')->findBy([], ['username' => 'ASC']);
Stiig
fuente
24

Sencillo:

$this->getDoctrine()->getRepository('AcmeBundle:User')->findBy(
    array(),
    array('username' => 'ASC')
);
Daniele Dolci
fuente
¡Funcionó como por arte de magia! Y todavía funciona exactamente de esta manera con Symfony 4
Robert Saylor
20

A veces es útil mirar el código fuente.

Por ejemplo, la findAllimplementación es muy simple ( vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php):

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

Entonces miramos findByy encontramos lo que necesitamos ( orderBy)

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

Esto funciona para mi:

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

Mantener la primera matriz vacía recupera todos los datos, funcionó en mi caso.

Mayordomo
fuente
5

Mira el código fuente de la API de Doctrine:

class EntityRepository{
  ...
  public function findAll(){
    return $this->findBy(array());
  }
  ...
}
Gilles Vanderstraeten
fuente
Este fragmento de código no ordena nada
Nico Haase
5

Debe utilizar un criterio, por ejemplo:

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

El método findBy en Symfony exceptúa dos parámetros. Primero está la matriz de campos en los que desea buscar y la segunda matriz es el campo de clasificación y su orden

public function findSorted()
    {
        return $this->findBy(['name'=>'Jhon'], ['date'=>'DESC']);
    }
Shaz
fuente
¿Puede agregar alguna explicación a su breve respuesta?
Nico Haase
Esa es una respuesta corta y poderosa. Elaborar - explicar ... editar .
Paul Hodges
esa fue la respuesta perfecta! findBy (array (), array ('fieldname' => 'ASC') Esto encontrará todo y ordenará en el campo con la dirección indicada.
Robert Saylor
2

Puede ordenar una ArrayCollection existente utilizando un iterador de matriz.

asumiendo que $ collection es su ArrayCollection devuelta por findAll ()

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

Esto se puede convertir fácilmente en una función que puede poner en su repositorio para crear el método findAllOrderBy ().

Nicolai Fröhlich
fuente
4
¿Cuál es tu punto aquí? Hay casos de uso más que suficientes para esto ... es decir, ¡ordenar una colección ya obtenida en PHP es siempre más rápido que realizar otra consulta mysql solo para ordenar! Imagine que necesita generar los mismos datos de recopilación en dos estilos de clasificación diferentes en una página ...
Nicolai Fröhlich
2
En general, devolver una consulta ordenada debería ser el trabajo de la base de datos. OTOH, esta técnica tiene aplicabilidad a los casos más involucrados que nifr menciona.
Lighthart
2

Prueba esto:

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

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

Utilizo una alternativa a la solución que escribió nifr.

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

Es más rápido que la cláusula ORDER BY y sin la sobrecarga del Iterador.

Moisés Márquez
fuente
Agregue alguna explicación adicional a su respuesta. ¿Cómo podría ser más rápido ordenar en su aplicación que hacerlo en el nivel de la base de datos?
Nico Haase
0

Modifique la función findAll predeterminada en EntityRepository de esta manera:

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

De esa manera, puede usar '' findAll '' en cualquier consulta para cualquier tabla de datos con una opción para ordenar la consulta

niksa
fuente