多数のデータを扱う場合、「ページ分け」をして表示させることが必須になります。
CakePHPには、これを実現する「ページネーション(Pagination)」という機能が提供されています。
今回は、このページネーションを攻略しますッ!
ページネーションの設定
コントローラーに「$paginate」というメンバ変数を用意します。
$paginate = array(オプション項目);
オプション項目を指定する場合は、設定名をキーとした連想配列で指定します。
page – 初期状態で表示されるページ番号。ディフォルトは「1」
conditions – レコードの取得条件
fields – 取得するフィールド名の配列
sort – ソートキーとなりフィールドの指定
limit – 表示する項目数
direction – 並び順。’asc’ or ‘desc’
recursive – 再帰的に取得する深度
コントローラー
<?php class StandsController extends AppController { public $name = 'Stands'; public $layout = 'stand'; public $paginate = array ( 'limit' => 10, 'sort' => 'id', ); function index() { $data = $this->paginate(); $this->set('data', $data); } } ?>
ビュー
<table> <tr> <th>Id</th> <th>Part</th> <th>スタンド名</th> <th>本体</th> </tr> <?php foreach ($data as $record): ?> <tr> <td><?php echo $record['Stand']['id']; ?></td> <td><?php echo $record['Stand']['part']; ?></td> <td><?php echo $record['Stand']['stand']; ?></td> <td><?php echo $record['Stand']['body']; ?></td> </tr> <?php endforeach; ?> </table> <?php echo $paginator->numbers ( array ( 'before' => $paginator->hasPrev() ? $paginator->first('<<').' | ' : '', 'after' => $paginator->hasNext() ? ' | '.$paginator->last('>>') : '', ) ); ?>
※ページングについては後で説明します。
条件付ページネーション
条件は、オプション項目の conditions と同様のものと考えます。
実際に、第5部のスタンド一覧を取得してみましょう。
コントローラーを変更します。
コントローラー
<?php class StandsController extends AppController { public $name = 'Stands'; public $layout = 'stand'; public $paginate = array ( 'limit' => 5, 'sort' => 'id', ); function index() { $conditions = array('part' => 5); $data = $this->paginate($conditions); $this->set('data', $data); } } ?>
$conditions = array(‘part’ => 5); つまり、第5部のスタンド一覧が取得できました。
1ページに表示する項目数より少ないので、次に説明するページングリンクが、非表示になっている点にも着目してください。
ページング(ページ移動)
ページ移動の為のリンクを生成します。
$paginator->numbers();
たったこれだけで、以下のようなページングリンク生成されます。
10ページまでは、このようにページ番号がずらりと表示されますが、それ以上のページ数がある場合は、前後に「first」「last」というリンクが表示され、現在のページの前後4ページ分の番号が表示されるようになります。
numbers() を呼び出すだけで、これらがまとめて生成されるなんて、実にッ!便利ですね。
・numbers のオプション項目
before – 最初のリンクの前に表示するもの
after – 最後おリンクの後に表示するもの
modules – 表示するリンクの数。現在表示しているページを中心に、前後あわせて何ページ分表示するか。
separator – 各リンク間の区切り文字
mod – 使用するモデル
最初に生成したページングは、以下のように少し手を加えて、さらに使いやすくしています。
<?php echo $paginator->numbers ( array ( 'before' => $paginator->hasPrev() ? $paginator->first('<<').' | ' : '', 'after' => $paginator->hasNext() ? ' | '.$paginator->last('>>') : '', ) ); ?>
hasPrev, hasNext メソッドで「前後のページが存在するか」をチェックしています。
こうすることにより、最初、もしくは最後のページでは、「<<」「>>」だけでなく、境界にある「 | 」も非表示になります。
ソート機能
ページネーションには「ソート機能」も提供されています。
$paginator->sort(表示テキスト, ソートキー, 属性);
これで、そのキーによってソートするためのリンクが生成されます。
実際に組み込んでみます。
<table> <tr> <th><?php echo $paginator->sort('Id', 'id'); ?></th> <th><?php echo $paginator->sort('Part', 'part'); ?></th> <th><?php echo $paginator->sort('スタンド名', 'stand'); ?></th> <th><?php echo $paginator->sort('本体', 'body'); ?></th> </tr> <?php foreach ($data as $record): ?> <tr> <td><?php echo $record['Stand']['id']; ?></td> <td><?php echo $record['Stand']['part']; ?></td> <td><?php echo $record['Stand']['stand']; ?></td> <td><?php echo $record['Stand']['body']; ?></td> </tr> <?php endforeach; ?> </table> <?php echo $paginator->numbers ( array ( 'before' => $paginator->hasPrev() ? $paginator->first('<<').' | ' : '', 'after' => $paginator->hasNext() ? ' | '.$paginator->last('>>') : '', ) ); ?>
ソートリンクをクリックすると、指定のキーでソートされます(降順 and 昇順)
生成されたソートリンクの、ソースコードは以下のようになっています。
<a href="/*/index/page:1/sort:id/direction:desc" class="asc">>Part</a>
リンクのURLに、必要なパラメーターが指定されていることがわかりますね。
この構造が分かれば、ヘルパーを使わずに、直接これらを操作することも出来そうです。
また、ソートされたリンクには、”asc” or “desc” のクラス名が自動的に生成されています。
この構造が分かれば、CSSで、現在どのキーでソートされているかをデザインすることも出来ます。
以上で、ページネーションの機能は、ほぼすべて網羅しているはずです。
検索フォームを設置してみる
検索フォームを設置してみます。
テキストを入力して「スタンド名」を検索する機能を実装します。
コントローラー
<?php class StandsController extends AppController { public $name = 'Stands'; public $layout = 'stand'; public $paginate = array ( 'limit' => 10, 'sort' => 'id', ); function index() { if (!empty($this->data)) { $search = $this->data['Stand']['stand']; } else { $search = ''; } if ($search) { $conditions = array('Stand.stand LIKE' => "%{$search}%"); } else { $conditions = array(); } $data = $this->paginate($conditions); $this->set('data', $data); } } ?>
ビュー
<?php echo $form->create(null); ?> <?php echo $form->text('Stand.stand'); ?> <?php echo $form->submit('スタンド検索'); ?> <?php echo $form->end(); ?> <table> <tr> <th><?php echo $paginator->sort('Id', 'id'); ?></th> <th><?php echo $paginator->sort('Part', 'part'); ?></th> <th><?php echo $paginator->sort('スタンド名', 'stand'); ?></th> <th><?php echo $paginator->sort('本体', 'body'); ?></th> </tr> <?php foreach ($data as $record): ?> <tr> <td><?php echo $record['Stand']['id']; ?></td> <td><?php echo $record['Stand']['part']; ?></td> <td><?php echo $record['Stand']['stand']; ?></td> <td><?php echo $record['Stand']['body']; ?></td> </tr> <?php endforeach; ?> </table> <?php echo $paginator->numbers ( array ( 'before' => $paginator->hasPrev() ? $paginator->first('<<').' | ' : '', 'after' => $paginator->hasNext() ? ' | '.$paginator->last('>>') : '', ) ); ?>
さらに、「スタンド名」もしくは「本体」の両方から、OR検索をしようとすると、こうなります。
コントローラー(抜粋)
if ($search) { $conditions = array('or' => array( 'Stand.stand LIKE' => "%{$search}%", 'Stand.body LIKE' => "%{$search}%" )); } else { $conditions = array(); }
Comments
[…] http://hijiriworld.com/web/cakephp-%E3%83%9A%E3%83%BC%E3%82%B8%E3%83%8D%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E6%94%BB%E7%95%A5%E3%81%99%E3%82%8B/ コンディションをいれて絞り込む […]