この記事を三行にまとめると
基本形findメソッドと組み合わせる
finderを使う
今日はCakePHP3でページネーションをやってみたいと思います。いくつか書き方があるので順番に見ていきましょう。
今回はpostsというテーブルにブログ記事が入っていて、ページネーションを使ってその一覧を取得するという想定でやってみます。
これでオッケーです。「post_date」というフィールドに投稿日が入ってると思ってください。
CakePHP2系の時とほとんど同じ書き方ですね。CakePHP3ではfindのとき、「conditions」や「fields」の部分が「where」や「select」に変わりましたが、paginateを使用する場合は今まで通りにconditionsとfieldsを使います。むしろこの書き方だとwhereやselectは効かない。エラーにはならないようですがSQL文の作成には使われないっぽいです。
こんな感じです。findメソッドを使えるってのは便利かもしれません。クエリ作成部分をテーブル側で作成すればコントローラーがすっきりするしね。
finderってのはえーと……実際にコードを書いた方が早いかな。ページネーションじゃなくて通常のfindの時にfinderを使うと以下のようになります。
テーブルに「find〇〇」というメソッドを作っておくと、findの引数に「〇〇」の部分を渡すだけで「find〇〇」の中に書いた取得条件が適用されます。「find〇〇」の方の先頭は大文字で、findの引数の方は小文字です。上記の例だと「post」と書いてますが、自分はスカートが大好きだからメソッド名にもスカートを使いたいって場合はこうなる。
同じことがページネーションでもできます。ちょびっとだけ書き方が違うけど。
「[‘finder’ => ‘〇〇’]」と書くことで先ほどと同じように「find〇〇」が使えます。
finderを指定する際、配列の階層を一つ深くすることでfindPostメソッドの第二引数(上の例だと$options)に値が渡ります。
こんな感じですかねー。
さっきもちょろっと言いましたが、個人的にfindメソッドを組み合わせたりfinderが使えるのは便利だと思います。CakePHP2を使ってた頃、普通のfindに関する処理は基本的にモデルに書いてたのに、ページネーションの時だけコントローラーに処理を書くってのがちょっと気に入らなかったんですよね。どうせならページネーションもモデルに書いてコントローラーで呼び出せればコードがもっとすっきりするのにって思ってた。
あ、テンプレート側の書き方は2と同じで大丈夫そうです。なのでここでは省略。
その他のCakePHP3を触ってみましたの記事はこちら
まとめという名の箸休め
今回はpostsというテーブルにブログ記事が入っていて、ページネーションを使ってその一覧を取得するという想定でやってみます。
基本形
まずは一番基本的な形。例えば今年の一月一日以降に投稿された記事の一覧を、投稿日の新しい順に取ってきたいとする。//PostsController.php
class PostsController extends AppController {
public $paginate = [];
public index() {
$this->paginate = [
'conditions' => ['post_date >=' => '2017-01-01'],
'fields' => ['id', 'title', 'text', 'post_date'],
'order' => ['post_date' => 'DESC']
];
$data = $this->paginate('Posts');
}
}
これでオッケーです。「post_date」というフィールドに投稿日が入ってると思ってください。
CakePHP2系の時とほとんど同じ書き方ですね。CakePHP3ではfindのとき、「conditions」や「fields」の部分が「where」や「select」に変わりましたが、paginateを使用する場合は今まで通りにconditionsとfieldsを使います。むしろこの書き方だとwhereやselectは効かない。エラーにはならないようですがSQL文の作成には使われないっぽいです。
//PostsController.php
class PostsController extends AppController {
public $paginate = [];
public index() {
//order以外は反映されない
$this->paginate = [
'where' => ['post_date >=' => '2017-01-01'],
'select' => ['id', 'title', 'text', 'post_date'],
'order' => ['post_date' => 'DESC']
];
$data = $this->paginate('Posts');
}
}
findメソッドと組み合わせる
じゃあwhereやselectを使って書くことはできないのかってーとそんなことはない。3系では通常のfindメソッドを引数に渡してページングつきのデータを取ってくることもできます。2でも似たようなことはできますがね。//PostsController.php
class PostsController extends AppController {
public $paginate = [];
public index() {
//findメソッドでクエリを作成
$query = $this->Posts->find();
$query->where(['post_date >=' => '2017-01-01']);
$query->select(['id', 'title', 'text', 'post_date']);
$query->order(['post_date' => 'DESC']);
//$queryを渡してデータを取得
$data = $this->paginate($query);
}
}
こんな感じです。findメソッドを使えるってのは便利かもしれません。クエリ作成部分をテーブル側で作成すればコントローラーがすっきりするしね。
//PostsController.php
class PostsController extends AppController {
public $paginate = [];
public index() {
$query = $this->Posts->getQuery();
$data = $this->paginate($query);
}
}
//PostsTable.php
class PostsTable extends Table {
public function getQuery() {
$query = $this->find();
$query->where(['post_date >=' => '2017-01-01']);
$query->select(['id', 'title', 'text', 'post_date']);
$query->order(['post_date' => 'DESC']);
return $query;
}
}
finderを使う
findメソッドとの組み合わせに少し似ているのですが、テーブルにデータの取得条件を書いたfinderを作成しておくというやり方もあります。finderってのはえーと……実際にコードを書いた方が早いかな。ページネーションじゃなくて通常のfindの時にfinderを使うと以下のようになります。
//PostsController.php
class PostsController extends AppController {
public index() {
$data = $this->Posts->find('post');
}
}
//PostsTable.php
class PostsTable extends Table {
public function findPost(Query $query) {
$query->where(['post_date >=' => '2017-01-01']);
$query->select(['id', 'title', 'text', 'post_date']);
$query->order(['post_date' => 'DESC']);
return $query;
}
}
テーブルに「find〇〇」というメソッドを作っておくと、findの引数に「〇〇」の部分を渡すだけで「find〇〇」の中に書いた取得条件が適用されます。「find〇〇」の方の先頭は大文字で、findの引数の方は小文字です。上記の例だと「post」と書いてますが、自分はスカートが大好きだからメソッド名にもスカートを使いたいって場合はこうなる。
//PostsController.php
$this->Posts->find('skirt');
//PostsTable.php
public function findSkirt(Query $query) {}
同じことがページネーションでもできます。ちょびっとだけ書き方が違うけど。
//PostsController.php
class PostsController extends AppController {
public $paginate = [];
public index() {
$this->paginate = ['finder' => 'skirt'];
$data = $this->paginate('Posts');
}
}
//PostsTable.php
class PostsTable extends Table {
public function findSkirt(Query $query) {
$query->where(['post_date >=' => '2017-01-01']);
$query->select(['id', 'title', 'text', 'post_date']);
$query->order(['post_date' => 'DESC']);
return $query;
}
}
「[‘finder’ => ‘〇〇’]」と書くことで先ほどと同じように「find〇〇」が使えます。
finderに値を渡す
「find〇〇」メソッドにコントローラーから値を渡したい場合。//PostsController.php
class PostsController extends AppController {
public $paginate = [];
public index() {
$this->paginate = [
'finder' => [
'skirt' => ['date' => '2017-01-01']
]
];
$data = $this->paginate('Posts');
}
}
//PostsTable.php
class PostsTable extends Table {
public function findPost(Query $query, $options) {
$query->where(['post_date >=' => $options['date']]);
$query->select(['id', 'title', 'text', 'post_date']);
$query->order(['post_date' => 'DESC']);
return $query;
}
}
finderを指定する際、配列の階層を一つ深くすることでfindPostメソッドの第二引数(上の例だと$options)に値が渡ります。
URLのパラメータ
CakePHP2の時は「page:2」みたいな書き方をしてましたが、3では通常のGETパラメータと同じ感じです。//CakePHP2
/posts/index/page:2
//CakePHP3
/posts/index?page=2
こんな感じですかねー。
さっきもちょろっと言いましたが、個人的にfindメソッドを組み合わせたりfinderが使えるのは便利だと思います。CakePHP2を使ってた頃、普通のfindに関する処理は基本的にモデルに書いてたのに、ページネーションの時だけコントローラーに処理を書くってのがちょっと気に入らなかったんですよね。どうせならページネーションもモデルに書いてコントローラーで呼び出せればコードがもっとすっきりするのにって思ってた。
あ、テンプレート側の書き方は2と同じで大丈夫そうです。なのでここでは省略。
その他のCakePHP3を触ってみましたの記事はこちら
まとめという名の箸休め