slimでknp-componentsのpaginatorを使う(データベースアクセス版)
前回の記事では最初から全データを用意してページ捲りを実装してました。
ただ、データベースに対象データが存在する場合は全件データを取得するのは現実的ではありません。
データベースからデータの一部を取得する形でページ捲りを実装する方法を記します。
1. データの投入
aからzまでのデータが存在するalphabetテーブルを用意します。
mysql> create table alphabet( str varchar(1), sort int); mysql> insert into alphabet(str, sort) values('a', 1); mysql> insert into alphabet(str, sort) values('b', 2); ~省略~ mysql> select * from alphabet; +------+------+ | str | sort | +------+------+ | a | 1 | | b | 2 | | c | 3 | | d | 4 | | e | 5 | | f | 6 | | g | 7 | ~省略~
2. DoctrineのORMを使う場合の実装例
DoctrineのORM等を利用する場合はpaginateの第1引数にDoctrineのQueryを指定すれば完了です。
$ vi src/Taka512/Controllers/ContentsController.php ~省略~ public function pageTest($page) { $paginator = new Paginator(); $pagination = $paginator->paginate( $this->em->createQuery('SELECT a FROM Entity\Alphabet a'), $page, 5); $this->app->render('page_test.html.twig', array('pagination' => $pagination)); }
3. PDOを使う場合の実装例
knp-componentsのページ捲りはSymfony2のEventDispatcherのcomponentsを使用して実装してます。
DoctrineのORMを使用している場合は既存のSubscriberを使用してページ捲り用の処理を行いますが、
PDOの場合は自分でSubscriberを実装する必要があります。
Subscriberの作成
Subscriberではcountでデータ件数とlimitでデータを取得してEventオブジェクトに設定します。
$ mkdir -p src/Taka512/Events/Subscriber $ vi src/Taka512/Events/Subscriber/PdoQuerySubscriber.php <?php namespace Taka512\Events\Subscriber; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Knp\Component\Pager\Event\ItemsEvent; use Taka512\Models\PdoQuery; class PdoQuerySubscriber implements EventSubscriberInterface { public function items(ItemsEvent $event) { if ($event->target instanceof PdoQuery) { $sth = $event->target->dbh->prepare('SELECT COUNT(*) AS count FROM alphabet'); $sth->execute(); while($row = $sth->fetch(\PDO::FETCH_ASSOC)){ $event->count = $row['count']; } $event->items = array(); if ($event->count) { $sth = $event->target->dbh->prepare('SELECT * FROM alphabet ORDER BY SORT LIMIT ? OFFSET ?'); $sth->execute(array($event->getLimit(),$event->getOffset())); while($row = $sth->fetch(\PDO::FETCH_ASSOC)){ $event->items[] = $row; } } $event->stopPropagation(); } } public static function getSubscribedEvents() { return array( 'knp_pager.items' => array('items', 2) ); } }
Subscriberに渡すデータを保持するクラスを作成します。
本来はここで検索条件などを保持してPdoQuerySubscriberで組み立てますが今回はdbhのみ保持します。
$ mkdir -p src/Taka512/Models $ vi src/Taka512/Models/PdoQuery.php <?php namespace Taka512\Models; class PdoQuery { public $dbh; public function __construct($dbh) { $this->dbh = $dbh; } }
Controllerの変更
Controllerでは明示的にsubscriberを指定し、作成したPdoQueryクラスを指定すると
PdoQuerySubscriberのitemsが動作してpaginationデータがセットされるようになります。
$ vi src/Taka512/Controllers/ContentsController.php ~省略~ public function pageTest($page) { $paginator = new Paginator(); $paginator->subscribe(new PdoQuerySubscriber()); $query = new PdoQuery($this->dbh); $pagination = $paginator->paginate($query, $page, 5); $this->app->render('page_test.html.twig', array('pagination' => $pagination)); }
こんな感じでデータベースを利用したページ捲りが実装できます。