LoginSignup
0
0

More than 3 years have passed since last update.

CakePHP - Finderを使ったJOINの仕方

Posted at

この記事について

CakePHPであるテーブルにWHERE句付きのテーブルをJOINさせたい場合、いろいろやり方があると思います。が、今回はAssociationを使ってなるべくCakePHPが推奨するやり方でデータを取得する方法を示したいと思います。

CakePHPの推奨するやり方

CakePHPでは、AssociationでObjectごとの関係を示し、contain()またはmatching()を使ってデータを取得するやり方がおすすめされています。

公式によれば、matching()はprimary modelのデータを制限したい時に使われ、contain()はassociationでprimary modelのものではないデータを取りたい時に使うように設計されています。場合によって使い分けましょう。

ケーススタディ

例を使った方がしっくりくると思うので、以下のようなシチュエーションを想定します。
作りたい機能:「アクセスしたユーザーの書いた記事のカテゴリ一覧」
テーブル:categories, articles (以下参照)
image.png

例えばアクセスしたユーザーのIDが「1」である場合、赤字のカテゴリーのみが取得されるようにFinderやテーブルを定義していきます。

アプローチ

STEP1. ArticlesTableでログインユーザーに紐づく記事だけを取得されるようなFinderを定義。
STEP2. CategoriesControllerで、ログインユーザーに紐づく記事のカテゴリを取得。

STEP1

STEP1はメインではないので割愛します。ぶっちゃけこのケーススタディ程単純な例であれば、Dynamic Findersを使ってArticlesを絞ることもできます。
public function findArticlesOfUser(Query $query, array $options)のような物を定義したとします。

STEP2

STEP1で作ったFinderを使えば、ログインユーザーに紐づく記事だけを取得できるので、そこで絞られたArticlesに紐づくカテゴリを取得します。今回の目的は「Primary ModelであるCategoryをSecondary ModelのArticleを使って絞りこむ」ことであるため、matching()を使用するのが適切です。「Primary ModelであるCategoryからSecondary ModelのArticleを取得する」であればcontain()が適切でしょう。正直、仕様によってはどちらでも問題なく動くことがありますが、CakePHPを理解した上でコードを書く分にはどちらが良いかを考えた方が良いでしょう。
CategoriesControllerは以下のようになります。

CategoriesController.php

    public function index()
    {
        $categories = $this->Categories->find()
            ->matching('Articles', function (Query $q) {
                 return $q->find(
                     'findArticlesOfUser',
                     ['user' => $this->Authentication->getIdentity()]
                 );
            });

         //...あとは省略

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0