CakePHP ページネーションを攻略する

多数のデータを扱う場合、「ページ分け」をして表示させることが必須になります。
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

コメントを残す