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?

Eu gosto de tacos
fonte

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();
Pier-Luc Gendreau
fonte
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']);
Stiig
fonte
24

Simples:

$this->getDoctrine()->getRepository('AcmeBundle:User')->findBy(
    array(),
    array('username' => 'ASC')
);
Daniele Dolci
fonte
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)
Luchaninov
fonte
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.

Buttler
fonte
5

Veja o código-fonte da API Doctrine:

class EntityRepository{
  ...
  public function findAll(){
    return $this->findBy(array());
  }
  ...
}
Gilles Vanderstraeten
fonte
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,
        ]);
    }
}
Lighthart
fonte
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']);
    }
Shaz
fonte
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 ().

Nicolai Fröhlich
fonte
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'));
Mahdi Dhifi
fonte
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.

Moisés Márquez
fonte
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

Niksa
fonte