Как использовать KNPPaginatorBundle для разбиения на страницы результатов с помощью Doctrine Repository?
Я работаю над проектом Symfony2 и решил использовать KNPPaginatorBundle для создания простой системы разбиения на страницы. Поэтому я создал сущность Product и хочу добавить paginator к действию 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
);
Он работает нормально, но я хочу использовать репозиторий Product вместо создания запроса непосредственно в контроллере. Как я могу это сделать? На самом деле, прямое добавление коллекции результатов к объекту разбивки на страницы происходит слишком медленно, поскольку его загрузка всех продуктов затем разбивает на страницы ArrayCollection.
Заранее спасибо.
K4
3 ответа
Я предлагаю использовать 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
);
Я думаю, что в некоторых случаях мы могли бы использовать 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
! Пожалуйста, проверьте документы для получения дополнительной информации.
В нашем проекте мы хотим избежать использования запросов Doctrine в контроллерах. У нас также есть отдельные слои. Контроллеры не должны иметь доступ к базе данных. Поэтому я включил нумерацию страниц в хранилище.
Вот мой код в контроллере:
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
}
}