Я работаю над проектом 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 );
Он работает нормально, но я хочу использовать репозиторий продукта вместо создания запроса непосредственно в контроллере. Как я могу это сделать ? Фактически, прямое добавление коллекции результатов в объект paginate является слишком медленным, потому что его загрузка всех продуктов затем разбивает на страницы ArrayCollection.
Заранее спасибо.
K4
Я предлагаю использовать QueryBuilder
в вашем ProductRepository
а затем передать это в paginator:
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
чтобы получить как findAllPublished
на страницы, так и НЕ findAllPublished
на страницы результаты, если вам нужно.
Также имейте в виду, что подсказка типа подсказки работает в 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 } }