【CAKEPHP】ケース別、検索用サンプルコードまとめ
目次
環境
今回はCAKEPHP3系で行います。
準備
はじめに、サンプルで3つのテーブルを用意します。
postsテーブル:id、name、status、type、seq、created、modified
categoriesテーブル:id、seq、created、modified
categories_postsテーブル:category_id、post_id
ケース別サンプルコード
postに条件を課して一覧を取得する
ページングなしの場合
この場合、find()を使用した一般的なコードは次のようになるでしょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
$posts = $this->Posts->find() ->contain([ 'Categories' => [ 'conditions' => [ 'Categories.name' => 'サンプル' ], 'sort' => [ 'Categories.seq' => 'ASC' ] ] ]) ->where([ ['Posts.status' => 1], ['Posts.type' => 2], ['OR' => [ ['Posts.name LIKE' => '%サンプル%'], ['Posts.name LIKE' => '%テスト%'], ]] ]) ->order(['Posts.seq' => 'DESC']); |
contain()でcategoriesテーブルを結合して、さらにその中で条件や順序を指定しています。where()では複数の条件を指定しています。並列の条件はANDで繋がり、ORの中の条件はORで繋がります。また、LIKE検索する場合はキーワードの前後に%をつけます。order()で順序を指定しています。
この時に実行されるSQLは次のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
SELECT Posts.id AS `Posts__id`, Posts.name AS `Posts__name`, Posts.status AS `Posts__status`, Posts.type AS `Posts__type`, Posts.seq AS `Posts__seq`, Posts.created AS `Posts__created`, Posts.modified AS `Posts__modified` FROM posts Posts WHERE ( Posts.status = 1 AND Posts.type = 2 AND ( Posts.name like '%サンプル%' OR Posts.name like '%テスト%' ) ) ORDER BY Posts.seq DESC |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
SELECT CategoriesPosts.category_id AS `Categories_CJoin__category_id`, CategoriesPosts.post_id AS `Categories_CJoin__post_id`, Categories.id AS `Categories__id`, Categories.name AS `Categories__name`, Categories.seq AS `Categories__seq`, Categories.created AS `Categories__created`, Categories.modified AS `Categories__modified` FROM categories Categories INNER JOIN categories_posts CategoriesPosts ON Categories.id = (CategoriesPosts.category_id) WHERE ( Categories.name = 'サンプル' AND CategoriesPosts.post_id in (22, 13, 4) ) ORDER BY Categories.seq ASC |
ページングありの場合
この場合、paginate()を使用した一般的なコードは次のようになるでしょう。
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 |
$this->paginate = [ 'contain' => [ 'Categories' => [ 'conditions' => [ 'Categories.name' => 'サンプル' ], 'sort' => [ 'Categories.seq' => 'ASC' ] ] ], 'conditions' => [ ['Posts.status' => 1], ['Posts.type' => 2], ['OR' => [ ['Posts.name LIKE' => '%サンプル%'], ['Posts.name LIKE' => '%テスト%'], ]] ], 'order' => [ 'Posts.seq' => 'DESC' ] ]; $posts = $this->paginate( $this->Posts ); |
基本的な構造はページングなしの場合と同じです。
この時に実行されるSQLは次のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
SELECT Posts.id AS `Posts__id`, Posts.name AS `Posts__name`, Posts.status AS `Posts__status`, Posts.type AS `Posts__type`, Posts.seq AS `Posts__seq`, Posts.created AS `Posts__created`, Posts.modified AS `Posts__modified` FROM posts Posts WHERE ( Posts.status = 1 AND Posts.type = 2 AND ( Posts.name like '%サンプル%' OR Posts.name like '%テスト%' ) ) ORDER BY Posts.seq DESC LIMIT 20 OFFSET 0 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
SELECT CategoriesPosts.category_id AS `Categories_CJoin__category_id`, CategoriesPosts.post_id AS `Categories_CJoin__post_id`, Categories.id AS `Categories__id`, Categories.name AS `Categories__name`, Categories.seq AS `Categories__seq`, Categories.created AS `Categories__created`, Categories.modified AS `Categories__modified` FROM categories Categories INNER JOIN categories_posts CategoriesPosts ON Categories.id = (CategoriesPosts.category_id) WHERE ( Categories.name = 'サンプル' AND CategoriesPosts.post_id in (22, 13, 4) ) ORDER BY Categories.seq ASC |
ページングありの場合、postsテーブルの取得にLIMITがついています。この数はlimitを指定してあげることで変更が可能です。
特定のcategoryに属するpostを取得する
ページングなしの場合
この場合、find()を使用した一般的なコードは次のようになるでしょう。
1 2 3 4 5 6 7 8 9 |
$posts = $this->Posts->find() ->leftJoin( ['CategoriesPosts' => 'categories_posts'], ['CategoriesPosts.post_id = Posts.id'] ) ->where([ ['CategoriesPosts.category_id' => 1] ]) ->order(['Posts.seq' => 'DESC']); |
leftJoin()でcategoriesテーブルをLEFT JOINしてwhere()でpostが属するcategoryを指定しています。
この時に実行されるSQLは次のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
SELECT Posts.id AS `Posts__id`, Posts.name AS `Posts__name`, Posts.status AS `Posts__status`, Posts.type AS `Posts__type`, Posts.seq AS `Posts__seq`, Posts.created AS `Posts__created`, Posts.modified AS `Posts__modified` FROM posts Posts LEFT JOIN categories_posts CategoriesPosts ON CategoriesPosts.post_id = Posts.id WHERE CategoriesPosts.category_id = '1' ORDER BY Posts.seq DESC |
ページングありの場合
この場合、paginate()を使用した一般的なコードは次のようになるでしょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$this->paginate = [ 'join' => [ 'type' => 'LEFT', 'table' => 'categories_posts', 'alias' => 'CategoriesPosts', 'conditions' => 'CategoriesPosts.post_id = Posts.id' ], 'conditions' => [ ['CategoriesPosts.category_id' => 1] ], 'order' => [ 'Posts.seq' => 'DESC' ] ]; $posts = $this->paginate( $this->Posts ); |
基本的な構造はページングなしの場合と同じです。
この時に実行されるSQLは次のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
SELECT Posts.id AS `Posts__id`, Posts.name AS `Posts__name`, Posts.status AS `Posts__status`, Posts.type AS `Posts__type`, Posts.seq AS `Posts__seq`, Posts.created AS `Posts__created`, Posts.modified AS `Posts__modified` FROM posts Posts LEFT JOIN categories_posts CategoriesPosts ON CategoriesPosts.post_id = Posts.id WHERE CategoriesPosts.category_id = '1' ORDER BY Posts.seq DESC LIMIT 20 OFFSET 0 |
結び
私がCAKEPHPを使用しているときよくあるのは、公式のドキュメントでなかなか見つけられないメソッドがあったりして、いろいろとググって発見することです。今回はこれまでいろいろと調べてわかった検索の方法をまとめて掲載しました。
実際の開発ではもっと多くのテーブルが結合したり、条件が複雑だったりすることもありますが、基本的には今回掲載したものを組み合わせて大部分は対応可能かなと思います。