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?

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();

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']);

24

Sencillo:

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

¡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)

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.


5

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

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

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,
        ]);
    }
}

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']);
    }

¿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 ().


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'));

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.


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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.