Как отсортировать метод findAll Doctrine?

112

Я читал документацию Doctrine, но не смог найти способ отсортировать результаты findAll ().

Я использую доктрину symfony2 +, это утверждение, которое я использую внутри своего контроллера:

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

но я хочу, чтобы результаты были упорядочены по возрастанию имен пользователей.

Я пытался передать массив в качестве аргумента следующим образом:

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

но не работает (тоже не жалуется).

Есть ли способ сделать это без построения DQL-запроса?

Я люблю тако
источник

Ответы:

229

Как показано на примере @Lighthart, да, это возможно, хотя он значительно увеличивает жирность контроллера и не является СУХИМ.

Вам действительно следует определить свой собственный запрос в репозитории сущностей, это просто и лучше всего.

use Doctrine\ORM\EntityRepository;

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

Затем вы должны указать своей сущности искать запросы в репозитории:

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

Наконец, в вашем контроллере:

$this->getDoctrine()->getRepository('AcmeBundle:User')->findAll();
Пьер-Люк Жендро
источник
2
Это лучший подход, чем мой, но вы будете писать dql; мой метод имеет меньше dql и поэтому отвечает ограничению OP. Честно говоря, страх перед dql надо просто преодолеть. По возможности используйте этот метод, а не мой.
Lighthart
ну, это не страх перед dql, и перед прочтением этого ответа я в конечном итоге использовал DQL для достижения этого, но я не хотел использовать DQL в начале, потому что в моем контроллере не было DQL, и я хотел придерживаться стиль кода, который уже был у контроллера. Это решение действительно хорошо работает для меня!
ILikeTacos
1
Или просто: $ this-> getDoctrine () -> getRepository ('AcmeBundle: User') -> findBy (array (), array ('username' => 'ASC'));
Benji_X80
1
@ Benji_X80 Хотя этот однострочник, конечно, короче, он совсем не СУХОЙ. Метод findAll принадлежит репозиторию, а не контроллеру.
Пьер-Люк Жендро,
1
Можете ли вы указать объекту искать запросы в настраиваемом репозитории иным способом, кроме комментариев? Это самая ужасная практика программирования, которую я когда-либо видел
Сеянус
82
$this->getDoctrine()->getRepository('MyBundle:MyTable')->findBy([], ['username' => 'ASC']);
Stiig
источник
24

Просто:

$this->getDoctrine()->getRepository('AcmeBundle:User')->findBy(
    array(),
    array('username' => 'ASC')
);
Даниэле Дольчи
источник
Это сработало как шарм! И до сих пор точно так же работает с Symfony 4
Роберт Сэйлор
20

Иногда полезно посмотреть исходный код.

Например, findAllреализация очень проста ( vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php):

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

Итак, смотрим findByи находим то, что нам нужно ( orderBy)

public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
Лучаниновыми
источник
6

Это работает для меня:

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

Сохранение первого массива пустым возвращает все данные, в моем случае это сработало.

Бутлер
источник
5

Посмотрите исходный код Doctrine API:

class EntityRepository{
  ...
  public function findAll(){
    return $this->findBy(array());
  }
  ...
}
Жиль Вандерстратен
источник
Этот фрагмент кода ничего не сортирует
Нико Хаасе,
5

Вам нужно использовать критерии, например:

<?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
источник
5

Метод findBy в Symfony исключает два параметра. Первый - это массив полей, по которым вы хотите выполнить поиск, а второй массив - это поле сортировки и его порядок.

public function findSorted()
    {
        return $this->findBy(['name'=>'Jhon'], ['date'=>'DESC']);
    }
Shaz
источник
Не могли бы вы добавить пояснения к своему очень короткому ответу?
Нико Хаасе
Это очень короткий ответ. Доделать - объяснить ... редактировать .
Пол Ходжес
это был прекрасный ответ! findBy (array (), array ('fieldname' => 'ASC') Это найдет все и отсортирует по полю в указанном направлении.
Роберт Сэйлор
2

Вы можете отсортировать существующую коллекцию ArrayCollection с помощью итератора массива.

предполагая, что $ collection - это ваш ArrayCollection, возвращаемый findAll ()

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

Это можно легко превратить в функцию, которую вы можете поместить в свой репозиторий, чтобы создать метод findAllOrderBy ().

Николай Фрёлих
источник
4
Что ты здесь делаешь? Для этого более чем достаточно вариантов использования ... т.е. сортировка уже выбранной коллекции в PHP всегда быстрее, чем выполнение другого запроса mysql только для сортировки! Представьте, что вам нужно вывести одни и те же данные коллекции в двух разных стилях сортировки на одной странице ...
Николай Фрёлих
2
В общем, возврат упорядоченного запроса должен быть задачей базы данных. OTOH, этот метод действительно применим к более сложным случаям, которые упоминаются в NIFR.
Lighthart
2

Попробуй это:

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

$entities = $em->getRepository('MyBundle:MyTable')->findBy(array(), array('username' => 'ASC'));
Махди Дхифи
источник
1

Использую альтернативу тому решению, которое написал nifr.

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

Это быстрее, чем предложение ORDER BY , и без накладных расходов Iterator.

Мойзес Маркес
источник
Пожалуйста, добавьте дополнительные пояснения к своему ответу. Как сортировка в вашем приложении может быть быстрее, чем на уровне базы данных?
Нико Хаасе,
0

Измените функцию findAll по умолчанию в EntityRepository следующим образом:

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

Таким образом, вы можете использовать findAll в любом запросе для любой таблицы данных с возможностью сортировки запроса.

Никса
источник