How to use KNPPaginatorBundle to paginate results using Doctrine Repository?

后端 未结 3 1418
梦如初夏
梦如初夏 2021-02-05 23:46

I\'m working on a Symfony2 project and I decided to use KNPPaginatorBundle to build an easy pagination system. So I created a Product entity and I want to add the paginator to i

相关标签:
3条回答
  • 2021-02-06 00:01

    In our project we want to avoid using Doctrine queries in controllers. We have also separate layers. Controllers must not access the database. So I included pagination in the Repository.

    Here my code in controller:

    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,
        ));
    }
    

    And here is the important code in my repository:

    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 讨论(0)
  • 2021-02-06 00:08

    I suggest using QueryBuilder in your ProductRepository and then passing that to the paginator:

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

    In the controller:

    $products = $productRepository->findAll();
    
    // Creating pagnination
    $paginator  = $this->get('knp_paginator');
    $pagination = $paginator->paginate(
        $products,
        $this->get('request')->query->get('page', 1),
        20
    );
    
    0 讨论(0)
  • 2021-02-06 00:10

    I think in some cases we could use Closure and pass to it a QueryBuilder object.

    In your ProductRepository you could do something like this:

    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();
        }
    }
    

    and then in 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);
    
        // ...
    }
    

    I think it more flexible and you could use findAllPublished method to get both paginated or NOT paginated results if you need.

    Also keep in mind that callable type hint work in PHP >=5.4! Please, check docs for more info.

    0 讨论(0)
提交回复
热议问题