• WEB

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

  • まーしー
    まーしー システムちーむ
  • このエントリーをはてなブックマークに追加
CakePHPのアソシエーションについて

CakePHPのアソシエーションについて触れる機会がありましたので、簡単ですがまとめてみます。

はじめに

アソシエーションとはモデル同士のつながりのことです。

アソシエーションには4つの種類があります。

  • hasOne
  • hasMany
  • belongsTo
  • hasAndBelongsToMany

hasOne

モデルが別のモデルのデータを1件だけ所有するという関係です。
相手が外部キーをひとつだけもっています。

ユーザとプロフィールのテーブルを作成してみます。
※コードや実行結果はイメージです


CREATE TABLE users(
    id int unsigned auto_increment primary key,
    name varchar(30) NOT NULL,
);

CREATE TABLE profiles(
    id int unsigned auto_increment primary key,
    user_id int unsigned unique,
    hobby varchar(256),
);

profilesテーブルの外部キーにuser_idが設定されています。
外部キーはほかのテーブルと関連付けるためフィールドです。

CakePHPでは User モデルと Profile モデルという2つのモデルがそれぞれのテーブルに連携されます。

1人のユーザはひとつのプロフィールを持つので、この2つのモデルの関係は1対1の関係になります。

この2つのモデルの関係をコードで書くと次のようになります。


class User extends AppModel {
    public $hasOne = array('Profile');
}

このアソシエーションを定義して、$this->User->find()とfindすると、


Array
(
    [User] => Array
        (
            [id] => 1
            [nickname] => まーしー
        )
    [Profile] => Array
        (
            [id] => 1
            [hobby] => music
        )
);

User モデルだけでなく、Profile モデルの情報も同時に取得することができます。
このようにアソシエーションを利用すると、関連したモデルの情報も同時に取得することができます。

hasMany

相手のモデルに自分のIDが複数あるかもというもので、一対多の関係と呼ばれます。

ブログのサービスを例に考えます。

ユーザには複数の記事がひもづきますが、特定の記事は複数のユーザにひもづくことはなく1つの記事にひもづきます。

これが、1対多の関係です。

belongsTo

モデルが別のモデルのデータに所属しているという関係です。
先程のhasOneの項目でもあったプロフィールや、ブログの記事に対するコメントなど、データが所有者のIDを保持しているようなデータ構造です。


class Profile extends AppModel {
    public $belongsTo = array('User');
}

プロフィールをfindすると、ユーザモデルの情報も取得します。

hasAndBelongsToMany

記事とタグの関係

先程は、hasManyの項目で考えたブログの記事とコメントの一対多の関係でした。

記事とタグ(Tag)の関係を考えます。

記事には複数のタグがつきます。
ここまでは、記事とコメントの関係と同じですが、記事Aに追加されたタグが、別の記事Bに追加されることもあるので、コメントとは違い、あるタグは複数の記事にひもづく可能性があります。

このような関係を多対多の関係と呼び、CakePHPではモデルで表現するために、hasAndBelongsToManyを使うことができます。

中間テーブル

このデータ構造を使うには2つのテーブルを中継する、中間テーブルを作成します。

テーブル名を2つのモデル名をアンダースコアでつないだ形にします。(post_tags)

中間テーブルにはそれぞれのテーブルのidに該当する項目を外部キーとして用意しておきます。


CREATE TABLE IF NOT EXISTS `post_tags` (
  `id` int(10) unsigned NOT NULL,
  `post_id` int(10) unsigned NOT NULL DEFAULT '0',
  `tag_id` int(10) unsigned NOT NULL DEFAULT '0',
);

hasAndBelongsToManyを定義

Postモデル側


public $hasAndBelongsToMany = array(
  'Tag' => 
    array(
      'className'              => 'tag',
      'joinTable'              => 'post_tags',
      'foreignKey'             => 'post_id',
      'associationForeignKey'  => 'tag_id',
    )
);

Tagモデル側


public $hasAndBelongsToMany = array(
  'Post' =>
    array(
      'className'              => 'post',
      'joinTable'              => 'post_tags',
      'foreignKey'             => 'tag_id',
      'associationForeignKey'  => 'post_id',
    )
);

findしてみる

Post側から$this->Post->find()とすると、


array(
    'Post' => array(
        'id' => '1',
        'title' => 'タイトルA',
        'body' => '本文A',
    ),
    'Tag' => array(
        (int) 0 => array(
            'id' => '1',
            'tag' => 'タグ1',
            'PostTag' => array(
                'id' => '1',
                'post_id' => '1',
                'tag_id' => '1',
            )
        ),
        (int) 1 => array(
            'id' => '2',
            'tag' => 'タグ2',
            'PostTag' => array(
                'id' => '2',
                'post_id' => '1',
                'tag_id' => '2',
            )
        )
    )
)

このような感じに、タイトルAの記事につけられたタグのデータも取得しています。
中間テーブル(PostTag)のデータも出力されていますね。

Tag側から$this->Tag->find()とすると、


array(
    'Tag' => array(
        'id' => '1',
        'tag' => 'タグ1',
    ),
    'Post' => array(
        (int) 0 => array(
            'id' => '1',
            'title' => 'タイトルA',
            'body' => '本文1',
            'PostTag' => array(
                'id' => '1',
                'post_id' => '1',
                'tag_id' => '1',
            )
        ),
        (int) 1 => array(
            'id' => '2',
            'title' => 'タイトルB',
            'body' => '本文2',
            'PostTag' => array(
                'id' => '3',
                'post_id' => '2',
                'tag_id' => '1',
            )
        )
    )
)

タグ1とタグ1がつけられた記事を取得しています。

このエントリーをはてなブックマークに追加

まーしーが最近書いた記事

WRITERS POSTS もっと見る

他にもこんな記事が読まれています!

  • WEB
  • マーケティング
  • サーバー・ネットワーク
  • ライフスタイル
  • お知らせ