【CakePHP2】自作SQLでページネーションさせる場合の方法
CakePHP2.xで、ややこしいSQLを自作し、ページネーションさせたいという場合の方法を備忘録としてポストします。
CakePHP2.x 自作SQLでページネーション
サンプルは以下の状態です。
- Sample.php
- SamplesController.php
Sample モデル
Sample.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
<?php class Sample extends AppModel { public $useTable = false; /** * 自作SQLでのページネーション用(1) * */ function paginate() { $extra = func_get_arg(6); $limit = func_get_arg(3); $page = func_get_arg(4); $sql = $extra['extra']['type']; // 元々 $extra['type'] にSQLが格納されている $sql .= ' LIMIT ' . $limit; if ($page > 1){ $sql .= ' OFFSET ' . ($limit * ($page - 1)); } return $this->query($sql); } /** * 自作SQLでのページネーション用(2) * */ function paginateCount() { $extra = func_get_arg(2); return count($this->query( preg_replace( '/LIMIT \d+ OFFSET \d+$/u', '', $extra['extra']['type'] ) )); } /** * SQL作成 * */ public function _male_sql($condition) { // 割愛 return $sql; } } |
コントローラー
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
class SamplesController extends AppController { var $uses = array( 'Sample' ); /** * 一覧作成 * */ public function sample_list() { // SQL取得 $sql = $this->Sample->_male_sql($condition); // Paginateに渡すオプション $query = array( 'limit' => 15, 'extra' => array( 'type' => $sql ), ); // ページ送り付きで取得 $this->Paginator->settings = $query; $list_data = $this->Paginator->paginate('Sample'); // モデル名を指定 $this->set('list_data', $list_data); } } |
個人的に「SQLを作るのはモデル内で」という強迫観念があるので、わざわざモデル内でSQLを作成してリターンしていますが、気にならない場合はコントローラーで作成しても問題はないと思います。
以下、軽く解説
モデル内、自作SQLでのページネーション用(1) 部の
"$extra" には、渡した SQL が代入され、
"$limit" には渡したリミット数値、この場合は 15 が代入され、
"$page" には現在のページ数が代入されています。
なお、PHPの func_get_args() 関数のエイリアスと思われ、func_get_args() をダンプすると、全ての配列が格納されているのが分かります。
なお、SamplesController 内の別アクションから、自作SQLを使わないページネーションを並列で行った場合はキレイにバグるので、どちらかを別モデルに移設するなどの手段が必要です。
モデルのファンクション名を上書きするなどの手段があるとは思いますが、よく分からなかった(調べるのが面倒だった)ので、私は別モデルを新設して逃れました。
冷静に考えると恐らく、
1 |
$list_data = $this->Paginator->paginate('Sample'); // モデル名を指定 |
この部分で、自作SQL用のモデルを指定すれば幸せになれるような気がします。
以上です。