KnpPaginatorというバンドルは、何かを一覧表示する際に1ページに収まりきれなかった
時に、次のページのリンクや、前のページへのリンク、直接のページ番号へのリンクなどを
自動的に出力してくれます。
ダウンロード
以下のページから可能です。
「Download ZIP」というボタンがあるはずなのでそれをクリックすると
ダウンロードできます。
[KnpPaginatorBundle]
https://github.com/KnpLabs/KnpPaginatorBundle
$ unzip KnpPaginatorBundle-master.zip
$ mkdir -p vendor/bundles/Knp/Bundle
$ mv KnpPaginatorBundle-master vendor/bundles/Knp/Bundle/PaginatorBundle
[knp-component]
https://github.com/KnpLabs/knp-components
$ unzip knp-components-master.zip
$ mv knp-components-master vendor/knp-components
インストール
app/autoloader.phpに以下を追加
1 2 3 4 5 |
registerNamespaces(array( 'Knp\\Component' => __DIR__.'/../vendor/knp-components/src', 'Knp\\Bundle' => __DIR__.'/../vendor/bundles', // ... )); |
app/AppKernel.phpに以下を追加
1 2 3 4 5 6 7 8 9 |
// app/AppKernel.php public function registerBundles() { return array( // ... new Knp\Bundle\PaginatorBundle\KnpPaginatorBundle(), // ... ); } |
・コントローラにアクションを追加
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public function indexAction() { $em = $this->getDoctrine()->getEntityManager(); $query = $em->createQuery('SELECT u FROM MyHogeBundle:User u'); $paginator = $this->get('knp_paginator'); $pagination = $paginator->paginate( $query, $this->get('request')->query->get('page', 1), 10 ); return $this->render('MyHogeBundle:User:index.html.twig', array('pagination' => $pagination)); } |
コントローラに対応するテンプレートの作成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<table> <tr> <th>{{ knp_pagination_sortable(pagination, 'Id', 'u.id') }}</th> <th>{% if pagination.isSorted('u.Name') %} class="sorted"{% endif %}>{{ knp_pagination_sortable(pagination, 'Name', 'u.name') }}</th> </tr> {% for user in pagination %} <tr> <td>{{ use.pid }}</td> <td>{{ user.title }}</td> </tr> {% endfor %} </table> <div class="navigation"> {{ knp_pagination_render(pagination) }} </div> |
これで、準備完了ですのでアクセスしてみてください。
エラーになった場合
1 |
Fatal error: Call to a member function toArray() on a non-object in /home/hogehoge/public_html/hogehoge/vendor/knp-components/src/Knp/Component/Pager/Event/Subscriber/Paginate/Doctrine/ORM/QuerySubscriber.php on line 70 |
自分の場合そのままでは上記エラーがでて使用できませんでした。
そこで、以下のファイルの、items()メソッド内の一部を修正します。
– ./vendor/knp-components/src/Knp/Component/Pager/Event/Subscriber/Paginate/Doctrine/ORM/QuerySubscriber.php
以下のように修正してみてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
public function items(ItemsEvent $event) { if ($event->target instanceof Query) { // process count $useDoctrineWalkers = false; $useDoctrineOutputWalker = false; if (version_compare(\Doctrine\ORM\Version::VERSION, '2.3.0', '>=')) { $useDoctrineWalkers = true; $useDoctrineOutputWalker = true; } else if (version_compare(\Doctrine\ORM\Version::VERSION, '2.2.0', '>=')) { $useDoctrineWalkers = true; } if (($count = $event->target->getHint(self::HINT_COUNT)) !== false) { $event->count = intval($count); } else { $countQuery = QueryHelper::cloneQuery($event->target); if ($useDoctrineOutputWalker) { $treeWalker = 'Doctrine\ORM\Tools\Pagination\CountOutputWalker'; $countQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, $treeWalker); } else if ($useDoctrineWalkers) { QueryHelper::addCustomTreeWalker($countQuery, 'Doctrine\ORM\Tools\Pagination\CountWalker'); } else { $treeWalker = 'Knp\Component\Pager\Event\Subscriber\Paginate\Doctrine\ORM\Query\CountWalker'; QueryHelper::addCustomTreeWalker($countQuery, $treeWalker); } if ($useDoctrineWalkers) { $countQuery->setHint( DoctrineCountWalker::HINT_DISTINCT, $event->options['distinct'] ); } else { $countQuery->setHint( CountWalker::HINT_DISTINCT, $event->options['distinct'] ); } $countQuery ->setFirstResult(null) ->setMaxResults(null) ; $conn = $countQuery->getEntityManager()->getConnection(); $params = $countQuery->getParameters(); //getParameters()->toArray(); //getEntityManager()->getConnection(); |
今回使用したSymfonyは2.0.21で、それと、Knpのバンドルのバージョンが合わなかったのでしょうか?
“./vendor/doctrine/lib/Doctrine/ORM/AbstractQuery.php”のgetParameters()が返すものが
Knpが期待するオブジェクトではなく配列になっているのが原因のようです。
$countQuery->getParameters(); <= 2.0.21だと配列を返している。
追記:最新版のだと”\AsIsHydrator contains 1 abstract method and must therefore…”というエラーがでる
こんな感じのエラー
1 |
Fatal error: Class Knp\Component\Pager\Event\Subscriber\Paginate\Doctrine\ORM\Query\AsIsHydrator contains 1 abstract method and must therefore be declared abstract or implement the remaining methods |
昔はできたのにどうも最新版だとうまくいかない。
定義が必要な抽象メソッドが定義されていないというエラーらしい。
どう対処していいかわからないので、関連するクラスを呼んでいる処理を前と
同じように修正したら直った。
1 |
vendor/knp-components/src/Knp/Component/Pager/Event/Subscriber/Paginate/Doctrine/ORM/QuerySubscriber.php |
以下のように修正します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
public function items(ItemsEvent $event) { if ($event->target instanceof Query) { // process count $useDoctrineWalkers = false; $useDoctrineOutputWalker = false; if (version_compare(\Doctrine\ORM\Version::VERSION, '2.3.0', '>=')) { $useDoctrineWalkers = true; $useDoctrineOutputWalker = true; } else if (version_compare(\Doctrine\ORM\Version::VERSION, '2.2.0', '>=')) { $useDoctrineWalkers = true; } if (($count = $event->target->getHint(self::HINT_COUNT)) !== false) { $event->count = intval($count); } else { $countQuery = QueryHelper::cloneQuery($event->target); if ($useDoctrineOutputWalker) { $treeWalker = 'Doctrine\ORM\Tools\Pagination\CountOutputWalker'; $countQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, $treeWalker); } else if ($useDoctrineWalkers) { QueryHelper::addCustomTreeWalker($countQuery, 'Doctrine\ORM\Tools\Pagination\CountWalker'); } else { $treeWalker = 'Knp\Component\Pager\Event\Subscriber\Paginate\Doctrine\ORM\Query\CountWalker'; QueryHelper::addCustomTreeWalker($countQuery, $treeWalker); } if ($useDoctrineWalkers) { $countQuery->setHint( DoctrineCountWalker::HINT_DISTINCT, $event->options['distinct'] ); } else { $countQuery->setHint( CountWalker::HINT_DISTINCT, $event->options['distinct'] ); } $countQuery ->setFirstResult(null) ->setMaxResults(null) ; /* ここからついか */ $conn = $countQuery->getEntityManager()->getConnection(); $params = $countQuery->getParameters(); //$params = $countQuery->getParameters()->toArray(); list($types, $params) = array_reduce($params, function ($res, Parameter $par) { $res[0][] = $par->getType(); $res[1][] = $par->getValue(); return $res; }, array(array(), array())); $countResult = $conn ->executeQuery($countQuery->getSQL(), $params, $types) ->fetchColumn(); $event->count = intval($countResult); /* ここまで追加 */ /* $countQuery->getEntityManager()->getConfiguration()->addCustomHydrationMode('asIs', 'Knp\Component\Pager\Event\Subscriber\Paginate\Doctrine\ORM\Query\AsIsHydrator'); $countResult = $countQuery->getResult('asIs'); $event->count = intval(current(current($countResult))); */ |
これで動くようになりました。