はじめての CakePHP のアソシエーションで商品データを取り出す時に店舗データも同時に取得する $belongsTo の使い方

CakePHP で Amazon のようなシステムを構築しています。内容としては、まず店舗が登録され、店舗に複数の商品がぶら下がっているような仕組みです。このような場合に商品の個別ページでは、どの店舗の商品なのかを表示したいと思います。今回は、商品個別ページで商品データを取り出す時に、店舗データも同時に取得する方法について紹介します。

CakePHP のアソシエーションについて

CakePHP 2.x 系のアソシエーションについては、この記事を書いている現在では日本語のドキュメントがないため、以下の英語のドキュメントおよびブログなどを参考にさせて頂きました。

商品と店舗データを紐付ける方法

個別の商品データの取り出し時に店舗データを取り出す場合は、$this->Model->belongsTo を設定します。モデルに紐付けの設定を書いて、コントローラでデータ取り出し時に注意すれば、簡単に関連データを取り出すことができます。以下で方法を説明します。

モデル

モデルの設定が重要です。以下のように $this->belongsTo に店舗モデルへの接続について書きます。連想配列でモデル名をキーにし、その下にさらに連想配列を作り、classname にはモデル名、foreignKey には商品テーブル内の店舗テーブル ID に相当する部分 Item.shop_id の部分を設定します。

1
2
3
4
5
6
7
8
9
10
11
class Item extends AppModel
{
    public
        $name = 'Item',
        $belongsTo = Array(
            'Shop' => Array(
                'className'    => 'Shop',
                'foreignKey'   => 'shop_id'
            )
        ),
}

コントローラ

$this->Model->find() でデータを取り出せば良いです。ただし、取り出し時の条件に Item.id のように、テーブル名から書かなければ、どのテーブルの ID なのか CakePHP が判断できないので注意します。条件に Item.id ではなく id のみでとり出そうとすると、SQL エラーになります。

1
2
3
4
5
6
7
8
9
10
11
class ItemController extends AppController
{
    public $uses = Array('Shop', 'Item');
 
    public function index()
    {
        $id = $this->params['id'];
        $data = $this->Item->find('first', Array('conditions' => Array('Item.id' => $id)));
        pr($data);
    }
}

結果

以上の設定で取り出したデータを展開すると以下のようになります。一度に関連するデータを全て取り出すことができるので、大変便利ですしコストがかからないので良いです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Array
(
    [Item] => Array
        (
            [id] => 1
            [shop_id] => 1
            [title] => test
            [description] => test
            [money] => 1000
        )
 
    [Shop] => Array
        (
            [id] => 1
            [name] => 株式会社テスト
        )
)

ちなみに、この時発行される SQL は以下のような内容となります。ご自分の環境でも発行される SQL を確認して必要最低限のデータを取り出す場合はフィールド名を設定するなどしてみましょう。

1
SELECT `Item`.`id`, `Item`.`shop_id`, `Item`.`title`, `Item`.`description`, `Item`.`money`, `Shop`.`id`, `Shop`.`name`  FROM `cp_items` AS `Item` LEFT JOIN `cp_shops` AS `Shop` ON (`Item`.`shop_id` = `Shop`.`id`) WHERE `id` = 1 LIMIT 1

おわりに

SQL を直書きしても良いですが、CakePHP に任せる方法覚えれば SQL を毎回書かなくて良いですし、SQL の間違いなどによる時間の無駄が無くなって良いです。

コメント

コメントは受け付けていません。