CakephpでURL書き換えつつPagenation(ページング)

Tags:
  2010/06/04 03:05

CakephpのPagenatorヘルパーを使ってページングを実装する話。
ただ、URLはデフォルトのものじゃなくて、自由にやりたいんだけど?という制約。

Pagenatorの基本的な使い方

なんだかんだ言って公式が一番わかり易い気がする。
4.9 ページ付け(Pagination)

ダイナミックな検索を実装するときには、検索条件をなんらかの方法で保持しないといけない。
(Pagenatorは自動でそこまではやってくれない)

例えば、

$options = array(
	'conditions' => array(
		'Joboffer.industry_id' => $id,
		'Joboffer.is_deleted' => '0',
	)
);
$this->Session->write('options', $options);

とかってやってた。

CakePHPのセッションは配列やオブジェクトもそのまま保存できる。
いちいちシリアライズする必要がない。
(標準でもできたっけ?)

ある程度固定ならメンバに書いて、一部変更でも良い。

	public $paginate = array(
		'Joboffer' => array(
			'limit'	=> 20,
			'order'	=> array('Joboffer.regist_date' => 'desc', 'Joboffer.id'),
			'conditions' => array('Joboffer.is_deleted' => '0'),
		),
	);

Routesを使って、URLを書き換える

普段だとmod_rewriteを使う場面。
CakePHPはリクエストされるURLをすべて一度受け取って、
それからディスパッチしてるのでその際のルールを書き換えるだけでOK

3.4.5 Routesの設定

制約やルールを簡単に書くと、

  • Routesで指定した変数は$this->paramsに入る。
  • prefixをつけたい場合は、そのまま書くだけ
  • 但しsuffixをつけたい場合は書くだけでは出来ない。
    3.4.5.7 File extensionsを読む。ここで対応できない部分はたぶんできない。
  • /:someparam_:someparam/のような書き方はできない。
    ひとつのディレクトリーに1変数まで。

知らないと意外にハマる。

PagenatorとRoutesの連携

一緒になると非常にややこしい。

基本的には別々に設定すれば良い。
ただし、ページ数までカスタムURLの中に含めようとすると頭がいたくなる。

どういうことかというと、以下のように適当にURLを書き換えて、
そのページでページングするなら簡単に出来る。

	Router::connect('/job/:id', array(
		'controller' => 'job',
		'action' => 'get'
	), array(
		'id'	=> '[0-9]+',
	));

/job/:id/page:2みたいになるはず。

ただ、以下のようになると話が違ってくる。

	Router::connect('/search_:page',array(
		'controller' => 'search',
		'action' => 'index'
	), array(
		'page'=> '[0-9]+',
	));

search_2.htm のようなURLを作りたいということ。
普通だったらこういうことはもう不要なんだけどね。

実は公式には書いてないんだけど、Pagenatorでリンクを生成する関数を辿っていくと、router.phpに行き着く。
なので、Routesでしっかり設定しておくと、自動的にそのURLでページングされるようになるわけ!ここはもうマジック。

但しマジックなので、コツがいります。

  • router.phpではとても厳しい基準でマッチングをしている。
    本当に書き換えるべきURLなのか?分かりやすく正確にRoutesに設定し、Pagenatorで指定する必要がある。
    具体的に言うとURLだけでなくパラメーターまで見る。
  • router.phpのリンク生成の関数までパラメーターを渡すことができる。
    viewの関数の引数で、option['url']に配列で渡すと最後まで届く。

例を交えて説明します。

まず、router.phpではとても厳しい基準でマッチングをしている。という点。
当然なんですが、結構ハマります。

URLだけがマッチしていれば(他に曖昧なものがなければ)、書き換えてくれそうなものですが、
router.phpは指定したパラメーターまで見てくれます。

具体的に説明すると、

	Router::connect('/hogehoge/area_:pref/:page', array(
		'controller' => 'hogehoge',
		'action' => 'area'
	), array(
		'pref'	=> '[0-9]+',
		'page'	=> '[0-9]+',
	));

とした場合、パラメーターがprefとpageとあるわけです。
pageは自動的にPagenatorから渡されますが、
prefは手動で渡してあげないとrouter.phpは気づいてくれません。

ここで次のポイントが生きてきます。
router.phpのリンク生成の関数までパラメーターを渡すことができる。

router.phpではパラメーターまで見るので、そこまで値が渡せなければいけません。
ただ、普通にoptionに書いたのでは途中で切り捨てられ、届きません。

どうやるかというと、

$paginator->prev('前の20件を表示', array('url' => array('ext' => 'htm', 'pref' => $pref_id)));

のように、optionのurlに指定してあげます。

この例だと上のようにviewで指定すれば、ちゃんとURLが書き換えられてページングが出来ます。
ややこしいね。

興味がある方は/libs/view/helpers/paginator.phpを読んで、
router.phpまで辿ってみると理解が深まると思います。

ちょっとソースもややこしいので、もっと整理されて分かりやすく使いやすくなればいいなぁと思いました。
それでも標準でここまで出来ることが素晴らしいので、改めてCakePHPのパワーを感じる結果になりました。

ご参考になれば。