Как использовать KNPPaginatorBundle для разбиения результатов на страницы с помощью репозитория доктрин?


Я работаю над проектом Symfony2 и решил использовать KNPPaginatorBundle для создания простой системы разбиения на страницы. Поэтому я создал сущность продукта и хочу добавить разделитель страниц в действие indexAction (сгенерированное командой CRUD).

// Retrieving products.
$em = $this->getDoctrine()->getManager();

//$entities = $em->getRepository('LiveDataShopBundle:Product')->findAll();

$dql   = "SELECT a FROM LiveDataShopBundle:Product a";
$entities = $em->createQuery($dql);

// Creating pagnination
$paginator  = $this->get('knp_paginator');
$pagination = $paginator->paginate(
    $entities,
    $this->get('request')->query->get('page', 1),
    20
);

Это работает нормально, но я хочу использовать репозиторий продукта вместо создания запроса непосредственно в контроллере. Как я могу это сделать? На самом деле, прямое добавление коллекции результатов в объект разбиения на страницы происходит слишком медленно, потому что его загрузка затем все продукты разбивают коллекцию на страницы.

Заранее благодарю.

К4

Author: Victor Bocharsky, 2014-04-02

3 answers

Я предлагаю использовать QueryBuilder в вашем ProductRepository, а затем передать это в разделитель страниц:

ProductRepository extends EntityRepository
{
    // This will return a QueryBuilder instance
    public function findAll()
    {
        return $this->createQueryBuilder("p");
    }
}

В контроллере:

$products = $productRepository->findAll();

// Creating pagnination
$paginator  = $this->get('knp_paginator');
$pagination = $paginator->paginate(
    $products,
    $this->get('request')->query->get('page', 1),
    20
);
 16
Author: Alberto Fernández, 2014-04-02 10:26:49

Я думаю, что в некоторых случаях мы могли бы использовать Closure и передать ему объект QueryBuilder.

В вашем ProductRepository вы могли бы сделать что-то вроде этого:

ProductRepository extends EntityRepository
{
    public function findAllPublished(callable $func = null)
    {
        $qb = $this->createQueryBuilder('p');

        $qb->where('p.published = 1');

        if (is_callable($func)) {
            return $func($qb);
        }

        return $qb->getQuery()->getResult();
    }
}

А затем в ProductController:

public function indexAction(Request $request)
{
    $em = $this->get('doctrine.orm.entity_manager');
    $paginator = $this->get('knp_paginator');

    $func = function (QueryBuilder $qb) use ($paginator, $request) {
        return $paginator->paginate($qb, $request->query->getInt('page', 1), 10);
    };
    $pagination = $em->getRepository('AppBundle:Report')->findAllPublished($func);

    // ...
}

Я думаю, что он более гибкий, и вы могли бы использовать метод findAllPublished, чтобы получить как разбитые на страницы, так и НЕ разбитые на страницы результаты, если вам нужно.

Также имейте в виду, что callable подсказка типа работает в PHP >=5.4! Пожалуйста, проверьте документы для получения дополнительной информации.

 3
Author: Victor Bocharsky, 2015-08-06 14:56:25

В нашем проекте мы хотим избежать использования запросов доктрины в контроллерах. У нас также есть отдельные слои. Контроллеры не должны получать доступ к базе данных. Поэтому я включил разбивку на страницы в хранилище.

Вот мой код в контроллере:

public function indexAction(Request $request)
{
    $userRepository = $this->get('user_repository');
    $page = intval($request->query->get('page', 1));
    $pages = 0;
    $users = $userRepository->findAllPaginated($pages, $page - 1, 10);

    return $this->render('User:index.html.twig', array(
        'users' => $users,
        'page' => $page,
        'pages' => $pages,
    ));
}

И вот важный код в моем репозитории:

use Doctrine\ORM\Tools\Pagination\Paginator;
class UserRepository extends EntityRepository
{
    /**
     * @return User[]
     */
    public function findAllPaginated(&$pages, $startPage = 0, $resultsPerPage = 5)
    {
        $dql = 'SELECT u FROM CoreBundle:User u';
        $query = $this->getEntityManager()->createQuery($dql)
            ->setFirstResult($startPage * $resultsPerPage)
            ->setMaxResults($resultsPerPage);

        $paginator = new Paginator($query);
        $count = $paginator->count();
        $pages = floor($count/$resultsPerPage);

        return $paginator; // on $paginator you can use "foreach", so we can say return value is an array of User
    }
}
 0
Author: Xover, 2016-07-21 09:07:22