生まれて初めて、CakePHPのHABTMを書いてみたの♪
生まれて初めて、CakePHPのHABTMを書いてみたの♪
Bakeに頼らず自分でHABTAMのアソシエーションを書いたのは初めてだったかも。
正直わかりにくいのでどうしても避けてきたのですが、比較的仕事に余裕があったので、ゆっくりやってみて、
今日やっとこさ理解することができました
HABTMの構造
HABTAMとはHasAndBelongToMany(HABTM..ハビタムで呼び方あってる?)の略で、多対多のデータ構造です。
多対多のデータ構造の例
多対多のデータ構造の典型的な例はブログですかね。記事はたくさんあって、必ずどれかのカテゴリーに入っているけれど、一つの記事は複数のカテゴリーに分類されるケースもある。
そういうのが多対多のHABTMです。
・ブログの記事(Post 多のデータ)とカテゴリー(Category 多のデータ)とその中間テーブル(CategoryPost 中間テーブルのデータ)
HABTMアソシエーションをPostModelに書いてみる
Post.php
class Post extends AppModel { public $name = 'Post'; public $hasAndBelongsToMany = array( 'Category' => array( 'className' => 'Category', 'join_table' => 'categories_posts',//中間テーブルの名称(Model名ではなくテーブル名) 'foreignKey' => 'post_id',//categories_postsの中のCategoryとのforeignKey 'associationForeignKey' => 'category_id',//アソシエーションしている中のforeignKey.ここではCategoryPostのcategory_id ), ); }
categories_postsという中間テーブル、当初はposts_categoriesでした。でもなぜかこれだとcategories_postsっていうテーブルが無いよ!というエラーが発生してしまい、
結局中間テーブルの名称そのものをposts_categories→categories_postsに変更しました。ナゼ?why?
結局中間テーブルの名称そのものをposts_categories→categories_postsに変更しました。ナゼ?why?
recursiveで深度を設定していなくても中間データまで一発で取得できているところが非常にナイスです!
PostsControllerで、Postデータをfind Allした結果
hasAndBelongsToManyのアソシエーションをPostModelにしただけで、投稿した記事(Post)が、どのカテゴリーに属しているか、さらにその中間データであるCategoriesPostのデータも取得ができました
PostModelにちょっと書いただけで、複雑なアソシエーションをしてくれるなんて、ちょっとうれしい。。。
array( (int) 0 => array( 'Post' => array( 'id' => '9e8c4ef7-33d0-11e4-a724-3417eba238af', 'title' => '記事タイトル', 'text' => '記事本文', 'created' => '2014-09-04 10:12:45', 'modified' => '2014-09-04 10:12:47' ), 'Category' => array( (int) 0 => array( 'id' => '4b056148-33d0-11e4-a724-3417eba238af', 'slug' => 'category_1', 'name' => 'カテゴリー1', 'created' => '2014-09-04 10:10:29', 'modified' => '2014-09-04 10:10:32', 'CategoriesPost' => array( 'id' => 'e6dd311a-33f3-11e4-a724-3417eba238af', 'post_id' => '9e8c4ef7-33d0-11e4-a724-3417eba238af', 'category_id' => '4b056148-33d0-11e4-a724-3417eba238af', 'created' => '2014-09-04 14:25:32', 'modified' => '2014-09-04 14:25:35' ) ), (int) 1 => array( 'id' => '4b055c33-33d0-11e4-a724-3417eba238af', 'slug' => 'data_input', 'name' => 'category_2', 'created' => '2014-09-04 10:10:24', 'modified' => '2014-09-04 10:10:27', 'CategoriesPost' => array( 'id' => 'fd4f31a0-33d0-11e4-a724-3417eba238af', 'post_id' => '9e8c4ef7-33d0-11e4-a724-3417eba238af', 'category_id' => '4b055c33-33d0-11e4-a724-3417eba238af', 'created' => '2014-09-04 10:15:36', 'modified' => '2014-09-04 10:15:38' ) ) ) ),
今度は逆に、もう一方の多のデータであるCategoryModelをHABTMしてみる
foreignKeyとassociationForeignKeyが逆になっているだけで後は全く同じことに注目してください。
class Category extends AppModel { public $hasAndBelongsToMany = array( 'Post' => array( 'className' => 'Post', 'join_table' => 'categories_posts', 'foreignKey' => 'category_id',//categories_postsの中のPostとのforeignKey 'associationForeignKey' => 'post_id',//アソシエーションしている中のforeignKey.ここではCategoryPostのpost_id ), ); }
Categoryデータをfind Allした結果
先ほどと同様に、PostModelの下にCategoriesPost(中間データ)がアソシエーションされたデータが返ってきました。
array( (int) 0 => array( 'Category' => array( 'id' => '4b055c33-33d0-11e4-a724-3417eba238af', 'slug' => 'data_input', 'name' => 'データ入力', 'created' => '2014-09-04 10:10:24', 'modified' => '2014-09-04 10:10:27' ), 'Post' => array( (int) 0 => array( 'id' => '9e8c4ef7-33d0-11e4-a724-3417eba238af', 'title' => '記事タイトル', 'text' => '記事本文', 'created' => '2014-09-04 10:12:45', 'modified' => '2014-09-04 10:12:47', 'CategoriesPost' => array( 'id' => 'fd4f31a0-33d0-11e4-a724-3417eba238af', 'post_id' => '9e8c4ef7-33d0-11e4-a724-3417eba238af', 'category_id' => '4b055c33-33d0-11e4-a724-3417eba238af', 'created' => '2014-09-04 10:15:36', 'modified' => '2014-09-04 10:15:38' ) ), (int) 1 => array( 'id' => 'c672c872-33d0-11e4-a724-3417eba238af', 'title' => '記事タイトル', 'text' => '記事本文', 'created' => '2014-09-04 10:13:52', 'modified' => '2014-09-04 10:13:54', 'CategoriesPost' => array( 'id' => 'fd4f3512-33d0-11e4-a724-3417eba238af', 'post_id' => 'c672c872-33d0-11e4-a724-3417eba238af', 'category_id' => '4b055c33-33d0-11e4-a724-3417eba238af', 'created' => null, 'modified' => null ) ) ) ), (int) 1 => array( 'Category' => array( 'id' => '4b056148-33d0-11e4-a724-3417eba238af', 'slug' => 'category_2', 'name' => 'カテゴリー2', 'created' => '2014-09-04 10:10:29', 'modified' => '2014-09-04 10:10:32' ), 'Post' => array( (int) 0 => array( 'id' => '9e8c4ef7-33d0-11e4-a724-3417eba238af', 'title' => '記事タイトル', 'text' => '記事本文', 'link' => 'http://www.atsoho.com/jobinfo/detail/no-59201.html', 'created' => '2014-09-04 10:12:45', 'modified' => '2014-09-04 10:12:47', 'CategoriesPost' => array( 'id' => 'e6dd311a-33f3-11e4-a724-3417eba238af', 'post_id' => '9e8c4ef7-33d0-11e4-a724-3417eba238af', 'category_id' => '4b056148-33d0-11e4-a724-3417eba238af', 'created' => '2014-09-04 14:25:32', 'modified' => '2014-09-04 14:25:35' ) ) ) ) )
わかり難いからいやだとずっと避けて別々にデータを取得していたのですが、recursiveを設定しなくても、一発で中間データまで取ってきてくれるのはいいですね。
ちょっとわかり難い部分もありましたが、今後は使って生きたいと思います。