てきとう

ワーワーゆうとります

夏だわっしょいページネーションまつり

Paginationとは、リスト表示なんかした時に「●●件ずつ区切って表示」という処理をやってくれる便利機能です。
findの代わりにDBの情報を持ってきてくれるので、加工済みデータ等には使えません。
Paginationがやってくれる動きは、だいたいこんな感じ。

  1. データベースからの出力用を分割(SQLのlimitステートメント) (データベース検索条件をfindAllでなく、Paginatorに渡す【検索】)
  2. CakePHPで自動認識できるページリンクURLを作成する(表示用PaginatorにURL用のデータを渡す【表示】)


**使い方(標準)

1.2以降はコントローラーの機能として存在しているようです。
controller.phpの中をチラ見してみると、paginationの機能がなんとなくわかります。
その昔は、えらい人が作った自作コンポーネントなどでみんな潤っていたそうなので先人の知恵に感謝。


**コントローラー内に書く事。

	$helpers = array('Paginator');
	function hoge() {
		//使いたいfunction内でpaginateに指定。
		$this->paginate = array(
			'conditons'  => array(),
			'fields'	 => array(),
			'page'		 => 1,
			'limit'		 => 20,
			'sort'		 => '',
			'direction'  => 'ASC',
			'recursive'  => 1
		);
	    //こうして取れた結果をviewに渡す時はset関数で以下のように定義。
	    $this->set('result', $this->paginate());
    }

ソートまでしてデータを出してくれます。あらかじめ初期条件としてページ条件(page)、ソート条件(sort、direction)を与えたいときは
$this->paramsに配列で与えてやれば、最終的に条件をマージしてくれます。

//modelHogeのデータを、idでsortした結果を変数にセット
    $this->params['sort'] = $id;
    $this->set('result', $this->paginate('ModelHoge'));

**ビューで書く事

表示はpaginator helperを使います。

★カウンタ(ページ 1/5 1-10 みたいな表示↓)

    $paginator->counter(array('format' => 'ページ %page% / %pages% %start%-%end%')));
  1. 引数
format
カウンターのフォーマット
  1. 定数
%page%
現在のページ
%pages%
総ページ数
%current%
現在表示件数
%count%
全件数
%start%
表示中件数(〜から)
%end%
表示中件数(〜まで)

★前へ(prev)と次へ(next)

    $Paginator->prev("<", array(), null, null);
    $Paginator->next(">", array(), null, null);
  1. 引数
$title
(string)リンク文字。デフォルトはprevだと「<< previous」nextだと「Next >>」
$options
(array)リンクのオプション。オプション詳細については後述。
$disabledTitle
(string)リンク無効時のタイトル
$disabledOptions
(array)無効リンク時のオプション。オプション詳細はやっぱり下。
  1. 戻り値

prev(next)のリンク、又はリンク無効時のタイトル。

★最初(first)と最後(last)

    $Paginator->first("<", array());
    $Paginator->last(">", array());
  1. 引数
$title
(string)リンク文字。デフォルトはfirstとかlastとかじゃないですかね。あとで調べます。
$options
(array)リンクのオプション。オプション詳細については後述。


★paginationのoptions

$options['sort']
ソートキー
$options['direction']
ソートの方向(デフォルトはASC)
$options['format']
カウンターのフォーマット。range、pages、custom(デフォルトはcustom)

customでは定数を仕様できます。(上記view項目カウンター名の項を参照)

$options['separator']
1 of 20 pages みたいな表示の「of」にあたる部分(デフォルトは「of」)
$options['url']
アクションのURL
$options['model']
使用するモデルの名前
$options['escape']
リンクのタイトルがエスケープできるか否か(デフォルトは「true」)
$options['update']
Ajaxで呼び出された結果のDOM id 未指定なら普通のHTMLリンク使います。
$options['indicator']
Ajaxのリクエスト時に参照する(インジケーターの役割)DOM IDの要素

paginationの注意
引数付きのfunctionの中でpaginationを使うとhoge.jp/cont/func1/arg/page:2になってほしくても、hoge.jp/cont/func1/page:2になってしまいます。
funcにも「そんな引数イラネ」と怒られる事もしばしば。じゃあ、どうしろというのか。
cake/libs/router.phpをいじるという男気溢れるやり方以外で思いつくのは

勝手にオプション大作戦
optionでarray('url' => '/controller/action/param1/')と指定するくらいです。
paginatorヘルパー使用時にオプションでurlにパラメーターを渡してしまいましょうという魂胆です。

スマートなやり方教わりましたよ。

$paginator->options = array('url' => $this->passedArgs ); 

id:e-eg9さんありがとうございます。


Ajaxでおしゃれにページネーション
Ajaxを使うとオシャレにページネイションできます。
参考はココ→http://bakery.cakephp.org/articles/view/advanced-pagination-1-2

★おしゃれページネーションのビューで書く事

まず、layoutで以下のように記述し、ajaxを使っていたらprototype.jsを読み込む設定をします。

    link('prototype');

お次に任意のViewです。読み込み中に表示させる「now loading」的な画像を用意しておきます。これは好きなものでかまいません。
ここやここでおしゃれ画像を探すといいでしょう。

    image('ajax-loader.gif'); 
    renderElement('cnt/paging');

この時点で、ページングはエレメントの中で行っております。
読み込み用エレメントを作っておけば、いろんなページで使いまわせて経済的ですね。
という訳で、エレメントを作らないといけません
この例では、エレメントはコントローラーと同じ名前のフォルダに入れてます。
ちなみに置き場は「elements/cnt/paging.ctp

    //paginatorのオプションは上記参照で。
    $paginator->options(
      array(
       'update' => 'CntPaging',
       'url' => array(
      'controller' => 'Cnt',
        'action' => 'display'
       ),
       'indicator' => 'LoadingDiv'
      )
    );
    //カウンターを表示させます。
    Showing Page counter();

    //ソート機能使ってます。
    sort('Name', 'name');
  sort('Id', 'id');
    	
    //次へ、とか、もどる、とか。
    prev(戻る); 
    numbers(array('separator'=>' - '));
    next('次へ'); 

★おしゃれページネーションのコントローラーで書く事

Ajaxで呼ばれた時の挙動などを記述。 Ajaxで呼ばれたかどうかの判断は、RequestHandlerというコンポーネントを使います。
こいつがまたイイやつですが後日ご紹介します。

    class CntController extends Controller {

     var $name = 'Cnt';
     var $components = array('RequestHandler');

     var $paginate = array(
      'limit' => 15,
      'page' => 1,
      'order' => array (
       'name'=>'asc'
      )
     );

     function display() {

     $this->set('datas', $this->paginate('data'));
     //Ajaxだったら、$this->viewPathを先程作成したエレメントに変更。
     if($this->RequestHandler->isAjax()) {
      $this->viewPath = 'elements'.DS.'Cnt';
      $this->render('paging');
      }
     }
    }


力尽きました。続き(修正)後日。
というかですね。JUGEMじゃなくてwikiを借りようと思っていますよ*1
だって書き辛いんだもの!

*1:結果はてなを借りました