Como classificar o método findAll Doctrine


111

Tenho lido a documentação do Doctrine, mas não consegui encontrar uma maneira de classificar os resultados de findAll ().

Estou usando a doutrina do symfony2 +, esta é a instrução que estou usando dentro do meu controlador:

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

mas quero que os resultados sejam ordenados por nomes de usuário em ordem crescente.

Tenho tentado passar um array como argumento desta forma:

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

mas não funciona (também não reclama).

Existe alguma maneira de fazer isso sem construir uma consulta DQL?

Respostas:


229

Como @Lighthart mostrado, sim, é possível, embora adicione gordura significativa ao controlador e não seja SECO.

Você realmente deve definir sua própria consulta no repositório de entidades, é simples e prática recomendada.

use Doctrine\ORM\EntityRepository;

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

Em seguida, você deve dizer à sua entidade para procurar consultas no repositório:

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

Finalmente, em seu controlador:

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

2
Esta é uma abordagem melhor do que a minha, mas você escreverá dql; meu método tem menos dql e, portanto, responde à restrição do OP. Francamente, o medo de dql deve apenas ser superado. Use este método de preferência ao meu, se possível.
Lighthart de

bem, não é medo de dql, e antes de ler esta resposta, acabei usando DQL para conseguir isso, mas eu não queria usar DQL no início porque meu controlador não tinha nenhum DQL nele, e eu queria me ater ao estilo de código que o controlador já tinha. Esta solução funciona muito bem para mim!
ILikeTacos de

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

1
@ Benji_X80 Embora aquele one-liner seja certamente mais curto, não é nem um pouco SECO. O método findAll pertence ao repositório, não ao controlador.
Pier-Luc Gendreau

1
Você pode dizer à entidade para procurar consultas no repositório customizado de qualquer outra maneira que não usando comentários? É a prática de programação mais terrível que já vi
Sejanus

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

24

Simples:

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

Isso funcionou como um encanto! E ainda funciona exatamente assim com Symfony 4
Robert Saylor

20

É útil olhar o código-fonte às vezes.

Por exemplo, a findAllimplementação é muito simples ( vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php):

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

Então, olhamos findBye encontramos o que precisamos ( orderBy)

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

6

Isso funciona para mim:

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

Manter o primeiro array vazio recupera todos os dados, funcionou no meu caso.


5

Veja o código-fonte da API Doctrine:

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

Este snippet de código não classifica nada
Nico Haase

5

Você precisa usar um critério, por exemplo:

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

O método findBy no Symfony excede dois parâmetros. O primeiro é o array de campos que você deseja pesquisar e o segundo array é o campo de classificação e sua ordem

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

Você pode acrescentar alguma explicação à sua resposta muito curta?
Nico Haase de

Essa é uma resposta curta e poderosa. Elaborar - explicar ... editar .
Paul Hodges de

essa foi a resposta perfeita! findBy (array (), array ('fieldname' => 'ASC') Isso encontrará tudo e classificará no campo com a direção indicada.
Robert Saylor

2

Você pode classificar um ArrayCollection existente usando um iterador de matriz.

assumindo que $ collection é seu ArrayCollection retornado por findAll ()

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

Isso pode ser facilmente transformado em uma função que você pode colocar em seu repositório para criar o método findAllOrderBy ().


4
Qual é o seu ponto aqui? Existem casos de uso mais do que suficientes para isso ... ou seja, classificar uma coleção já obtida no PHP é sempre mais rápido do que executar outra consulta mysql apenas para classificar! Imagine que você precise gerar os mesmos dados de coleta em dois estilos de classificação diferentes em uma página ...
Nicolai Fröhlich

2
Em geral, retornar uma consulta ordenada deve ser a função do banco de dados. OTOH, esta técnica tem aplicabilidade para os casos mais envolvidos que o nifr menciona.
Lighthart

2

Experimente isto:

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

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

1

Eu uso uma alternativa para a solução que escreveu nifr.

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

É mais rápido do que a cláusula ORDER BY e sem a sobrecarga do Iterator.


Adicione mais explicações à sua resposta. Como a classificação em seu aplicativo poderia ser mais rápida do que no nível do banco de dados?
Nico Haase

0

Modifique a função findAll padrão em EntityRepository assim:

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

Dessa forma, você pode usar o '' findAll '' em qualquer consulta para qualquer tabela de dados com uma opção para classificar a consulta

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.