多数のデータを扱う場合、「ページ分け」をして表示させることが必須になります。
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/ コンディションをいれて絞り込む […]