2014-04-02 1 views
10

Symfony2 프로젝트에서 작업 중이며 KNPPaginatorBundle을 사용하여 쉬운 페이지 매김 시스템을 구축하기로 결정했습니다. 그래서 Product 엔티티를 만들었고 (CRUD 명령으로 생성 된) indexAction 액션에 paginator를 추가하려고합니다.KNPPaginatorBundle을 사용하여 Doctrine Repository를 사용하여 결과를 페이지 매김하는 방법?

// 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 
); 

제대로 작동하지만 컨트롤러에서 직접 쿼리를 만드는 대신 제품의 저장소를 사용하고 싶습니다. 어떻게해야합니까? 실제로, 페이지 집합 객체에 결과 모음을 직접 추가하는 것은 모든 제품의로드가 ArrayCollection에 페이지 매기기 때문에 너무 느립니다.

미리 감사드립니다.

K4

+1

내가이 성능 문제를 발견. 문제는이 묶음이 페이지 배열을 생성하기 위해 전체 배열 컬렉션을 필요로한다는 것입니다. 부분 결과를 제공하면 페이지 번호가 전체 컬렉션에서 계산되기 때문에 페이지 번호가 잘못됩니다. – Chopchop

답변

16

내가 통과 한 후 ProductRepositoryQueryBuilder를 사용하여 제안 그 매기기에 : 컨트롤러에서

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 
); 
+0

감사합니다! 나는 그것을했고, 그것은 잘 작동한다! createQueryBuilder()와 createQuery()의 근본적인 차이점은 무엇입니까? createNativeQuery()를 사용할 수 있습니까? – K4timini

+2

Create query는 DQL을 직접 쓰고 싶을 때 사용합니다. 일반적으로 쿼리가 간단하면 충분합니다. 조건부로 복잡한 쿼리를 작성해야하는 경우 queryBuilder를 사용하십시오. 유체 인터페이스는 그 작업에 매우 편리합니다. 이것이 QueryBuilder로 작업하는 것이 매우 쉽기 때문에 paginator와 잘 작동하는 이유입니다! –

+0

하지만 find all을 사용하면 먼저 하나의 쿼리를 모두 가져옵니다. 사실입니까? –

3

나는 우리가 사용할 수있는 경우에 생각 Closure을 입력하고 QueryBuilder 개체를 전달합니다. 에서

당신의 ProductRepository 당신이 뭔가를 할 수 있습니다 :

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 방법을 사용할 수 있습니다 ProductController에 다음

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

과 필요한 경우 페이지 매김 결과.

유형 힌트가 PHP >=5.4에서 작동한다는 점도 유의하십시오! 자세한 내용은 docs을 확인하십시오.

+0

스마트 솔루션! – jmunozco

+0

@jmunozco 감사합니다! 하지만 아마도 최고는 아닙니다.) 사실,이 솔루션은 컨트롤러에있는 쿼리 작성기에 대한 완전한 제어권을 얻습니다. 컨트롤러가 좋지 않습니다. 즉, 스마트하게 사용해야하지만 더 제한적인 작업을 수행해야합니다. –

0

우리 프로젝트에서는 컨트롤러에서 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 
    } 
} 
+1

정확히 $ pages = floor ($ count/$ resultsPerPage); 사용? –

+0

누가 위와 같이 인스턴스화 된 $ 페이징 기가 큰 문제인지, 퍼포먼스인지 또는 그렇지 않은지 생각하십니까? 어떻게하면 저장소 클래스에 knp_paginator 서비스를 삽입해야 할 필요가 있을까요? – userfuser

관련 문제