Hatena::ブログ(Diary)

connvoi_tyouの日記 RSSフィード

2010-12-20

PaginatorHelperでの複雑なURL指定(CakePHP Advent Calender 20日目)

CakePHP Advent Calender 2010の20番手として、

id:kunitさんControllerからModelを使用するいくつかの方法 (CakePHP Advent Calendar 19日目)からバトンを引き継ぎましたー。

今日は少し前に調べたPaginatorHelperについて、自分の備忘録として書いておこうかと思います。


PaginatorHelperでの複雑なURL指定

検索結果のPaginationはすべてのURLのどこかに検索クエリを引き継ぐ必要があります。

例えば、controller内のpaginateにcondisitonsを追加して、DBからlike句の検索結果を引きます。

/*
 *app/controllers/test_controller.php
 */
$this->paginate(array("comment"=>'LIKE %検索クエリ%'));

こういったときに、Paginatorをそのまま使うと

/*
 *app/views/test/index.php
 */
echo $paginator->numbers(array('modules'=>4));

/*出力されるURL*/
ROOT/test/index/page:1
ROOT/test/index/page:2
....
ROOT/test/index/page:5

になってしまい、次のページ以降で何で検索されてるのかがわからなくなってしまいます。

結果から言うと、イカのようにPaginatorのオプションurlに設定してあげるとうまく行きます。

/*
 *app/views/test/index.php
 */
echo $paginator->numbers(array(
                            'modules'=>4,
                            'url'=>array('?'=>'q=検索クエリ')
                         ));

/*出力されるURL*/
ROOT/test/index/page:1?q=検索クエリ
ROOT/test/index/page:2?q=検索クエリ
....
ROOT/test/index/page:5?q=検索クエリ

で、それをどうやって探したかを書いていきます。



ソースコードを読む

paginatorのソース内のコメントに

/* cake/libs/view/helpers/paginator.php 63行目
 *  - `$options['url']` Url of the action. See Router::url()
 */

と、コメント書いてあって(親切!)Urlをつくってるのは何となくRouter::url()だとわかります。


実際のところ、paginator内のurlメソッドが呼ばれて、その中で、Router::url()が呼ばれています。

   function url($options = array(), $asArray = false, $model = null) {
        $paging = $this->params($model);
        $url = array_merge(array_filter(Set::diff(array_merge(
            $paging['defaults'], $paging['options']), $paging['defaults'])), $options
        );  

        if (isset($url['order'])) {
            $sort = $direction = null;
            if (is_array($url['order'])) {
                list($sort, $direction) = array($this->sortKey($model, $url), current($url['order']));
            }   
            unset($url['order']);
            $url = array_merge($url, compact('sort', 'direction'));
        }   

        if ($asArray) {
            return $url;
        }
        /*ここで親(Helper::url()が呼ばれて、その中でRouter::url()が呼ばれます)*/   
        return parent::url($url);
    }   

確か、少し前のバージョン(Cake 1.2?)だと、直接Router::url()が呼ばれてた気がするのですが、

1.3.6ではHelper経由になってますね。


で、Router::url()が呼ばれる事がわかったので、router.phpを見に行きます。

/*
 *cake/libs/router.php
 * Router::url()
 */
/*略...*/
    if (isset($url['?'])) {
        $q = $url['?'];
        unset($url['?']);
    }
    if (isset($url['#'])) {
        $frag = '#' . urlencode($url['#']);
        unset($url['#']);
    }

/*略...*/
    return $output . $extension . $self->queryString($q, array(), $escape) . $frag;

という風に書いてあって、paginatorへ渡されたオプションの中で、"?"keyを持った物と、"#"keyを持った物は

"?"."#"の順でURLの最後に付けられそうなだなぁと言う事がわかります。


もうすこし、読んでいくと、urlオプションしていだと、keyの無いものは全部urlのpathになりそうな感じなので、

paginatorの指定はイカのようなカオスな感じにする事もできますね(笑)

/*
 *app/views/test/index.php
 */
echo $paginator->numbers(array(
                            'modules'=>4,
                            'url'=>array(
                                         '?'=>'q=検索クエリ',
                                         '#'=>'hogefuga',
                                         'a','b','c','d','e'
                                   )
                         ));

/*出力されるURL*/
ROOT/test/index/a/b/c/d/e/page:1?q=検索クエリ#hogefuga
ROOT/test/index/a/b/c/d/e/page:2?q=検索クエリ#hogefuga
....
ROOT/test/index/a/b/c/d/e/page:5?q=検索クエリ#hogefuga

paginatorで利用できる他のメソッド、prev、nextなど、urlを指定する物は共通して使えます。

CakePHPは実績がかなり多くて、web上での日本語ドキュメント等も豊富にあるのですが、

時間のあるときにでも、実行しようとしている物の中身を読むのも面白いです。

個人的な感想ですが、CakePHPソースコードが読みやすいフレームワークだと思ってます。

使ってるだけでは不満な方、まだ読んだ事の無い方は是非、


ソース嫁!


はい。これが言いたかっ(ry

若干、今までの方と比べると非力な記事でしたが、

これで、CakePHP Advent Calender 20日目は終わりです。


次は yashioさんですね!どんな記事が楽しみです。宜しくお願いします!!!

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/connvoi_tyou/20101220/1292822105