生まれて初めて、CakePHPのHABTMを書いてみたの♪ ITかあさん

ITかあさん

生まれて初めて、CakePHPのHABTMを書いてみたの♪

生まれて初めて、CakePHPのHABTMを書いてみたの♪

生まれて初めて、CakePHPのHABTMを書いてみたの♪
Bakeに頼らず自分でHABTAMのアソシエーションを書いたのは初めてだったかも。
正直わかりにくいのでどうしても避けてきたのですが、比較的仕事に余裕があったので、ゆっくりやってみて、
今日やっとこさ理解することができました

HABTMの構造

HABTAMとはHasAndBelongToMany(HABTM..ハビタムで呼び方あってる?)の略で、多対多のデータ構造です。

多対多のデータ構造の例

多対多のデータ構造の典型的な例はブログですかね。記事はたくさんあって、必ずどれかのカテゴリーに入っているけれど、一つの記事は複数のカテゴリーに分類されるケースもある。
そういうのが多対多のHABTMです。

・ブログの記事(Post 多のデータ)とカテゴリー(Category 多のデータ)とその中間テーブル(CategoryPost 中間テーブルのデータ)

HABTMアソシエーションをPostModelに書いてみる

Post.php

  1. class Post extends AppModel {  
  2.     public $name = 'Post';  
  3.   
  4.     public $hasAndBelongsToMany = array(  
  5.         'Category' => array(  
  6.             'className' => 'Category',  
  7.                 'join_table' => 'categories_posts',//中間テーブルの名称(Model名ではなくテーブル名)  
  8.                 'foreignKey' => 'post_id',//categories_postsの中のCategoryとのforeignKey  
  9.                 'associationForeignKey' => 'category_id',//アソシエーションしている中のforeignKey.ここではCategoryPostのcategory_id  
  10.             ),  
  11.         );  
  12. }  
categories_postsという中間テーブル、当初はposts_categoriesでした。でもなぜかこれだとcategories_postsっていうテーブルが無いよ!というエラーが発生してしまい、
結局中間テーブルの名称そのものをposts_categories→categories_postsに変更しました。ナゼ?why?

recursiveで深度を設定していなくても中間データまで一発で取得できているところが非常にナイスです!

PostsControllerで、Postデータをfind Allした結果

hasAndBelongsToManyのアソシエーションをPostModelにしただけで、投稿した記事(Post)が、どのカテゴリーに属しているか、さらにその中間データであるCategoriesPostのデータも取得ができました
PostModelにちょっと書いただけで、複雑なアソシエーションをしてくれるなんて、ちょっとうれしい。。。

  1. array(  
  2.     (int) 0 => array(  
  3.         'Post' => array(  
  4.             'id' => '9e8c4ef7-33d0-11e4-a724-3417eba238af',  
  5.             'title' => '記事タイトル',  
  6.             'text' => '記事本文',  
  7.             'created' => '2014-09-04 10:12:45',  
  8.             'modified' => '2014-09-04 10:12:47'  
  9.         ),  
  10.         'Category' => array(  
  11.             (int) 0 => array(  
  12.                 'id' => '4b056148-33d0-11e4-a724-3417eba238af',  
  13.                 'slug' => 'category_1',  
  14.                 'name' => 'カテゴリー1',  
  15.                 'created' => '2014-09-04 10:10:29',  
  16.                 'modified' => '2014-09-04 10:10:32',  
  17.                 'CategoriesPost' => array(  
  18.                     'id' => 'e6dd311a-33f3-11e4-a724-3417eba238af',  
  19.                     'post_id' => '9e8c4ef7-33d0-11e4-a724-3417eba238af',  
  20.                     'category_id' => '4b056148-33d0-11e4-a724-3417eba238af',  
  21.                     'created' => '2014-09-04 14:25:32',  
  22.                     'modified' => '2014-09-04 14:25:35'  
  23.                 )  
  24.             ),  
  25.             (int) 1 => array(  
  26.                 'id' => '4b055c33-33d0-11e4-a724-3417eba238af',  
  27.                 'slug' => 'data_input',  
  28.                 'name' => 'category_2',  
  29.                 'created' => '2014-09-04 10:10:24',  
  30.                 'modified' => '2014-09-04 10:10:27',  
  31.                 'CategoriesPost' => array(  
  32.                     'id' => 'fd4f31a0-33d0-11e4-a724-3417eba238af',  
  33.                     'post_id' => '9e8c4ef7-33d0-11e4-a724-3417eba238af',  
  34.                     'category_id' => '4b055c33-33d0-11e4-a724-3417eba238af',  
  35.                     'created' => '2014-09-04 10:15:36',  
  36.                     'modified' => '2014-09-04 10:15:38'  
  37.                 )  
  38.             )  
  39.         )  
  40.     ),  

今度は逆に、もう一方の多のデータであるCategoryModelをHABTMしてみる

foreignKeyとassociationForeignKeyが逆になっているだけで後は全く同じことに注目してください。

  1. class Category extends AppModel {  
  2.     public $hasAndBelongsToMany = array(  
  3.         'Post' => array(  
  4.             'className' => 'Post',  
  5.                 'join_table' => 'categories_posts',  
  6.                 'foreignKey' => 'category_id',//categories_postsの中のPostとのforeignKey  
  7.                 'associationForeignKey' => 'post_id',//アソシエーションしている中のforeignKey.ここではCategoryPostのpost_id  
  8.             ),  
  9.         );  
  10. }  

Categoryデータをfind Allした結果

先ほどと同様に、PostModelの下にCategoriesPost(中間データ)がアソシエーションされたデータが返ってきました。

  1. array(  
  2.     (int) 0 => array(  
  3.         'Category' => array(  
  4.             'id' => '4b055c33-33d0-11e4-a724-3417eba238af',  
  5.             'slug' => 'data_input',  
  6.             'name' => 'データ入力',  
  7.             'created' => '2014-09-04 10:10:24',  
  8.             'modified' => '2014-09-04 10:10:27'  
  9.         ),  
  10.         'Post' => array(  
  11.             (int) 0 => array(  
  12.                 'id' => '9e8c4ef7-33d0-11e4-a724-3417eba238af',  
  13.                 'title' => '記事タイトル',  
  14.                 'text' => '記事本文',  
  15.                 'created' => '2014-09-04 10:12:45',  
  16.                 'modified' => '2014-09-04 10:12:47',  
  17.                 'CategoriesPost' => array(  
  18.                     'id' => 'fd4f31a0-33d0-11e4-a724-3417eba238af',  
  19.                     'post_id' => '9e8c4ef7-33d0-11e4-a724-3417eba238af',  
  20.                     'category_id' => '4b055c33-33d0-11e4-a724-3417eba238af',  
  21.                     'created' => '2014-09-04 10:15:36',  
  22.                     'modified' => '2014-09-04 10:15:38'  
  23.                 )  
  24.             ),  
  25.             (int) 1 => array(  
  26.                 'id' => 'c672c872-33d0-11e4-a724-3417eba238af',  
  27.                 'title' => '記事タイトル',  
  28.                 'text' => '記事本文',  
  29.                 'created' => '2014-09-04 10:13:52',  
  30.                 'modified' => '2014-09-04 10:13:54',  
  31.                 'CategoriesPost' => array(  
  32.                     'id' => 'fd4f3512-33d0-11e4-a724-3417eba238af',  
  33.                     'post_id' => 'c672c872-33d0-11e4-a724-3417eba238af',  
  34.                     'category_id' => '4b055c33-33d0-11e4-a724-3417eba238af',  
  35.                     'created' => null,  
  36.                     'modified' => null  
  37.                 )  
  38.             )  
  39.         )  
  40.     ),  
  41.     (int) 1 => array(  
  42.         'Category' => array(  
  43.             'id' => '4b056148-33d0-11e4-a724-3417eba238af',  
  44.             'slug' => 'category_2',  
  45.             'name' => 'カテゴリー2',  
  46.             'created' => '2014-09-04 10:10:29',  
  47.             'modified' => '2014-09-04 10:10:32'  
  48.         ),  
  49.         'Post' => array(  
  50.             (int) 0 => array(  
  51.                 'id' => '9e8c4ef7-33d0-11e4-a724-3417eba238af',  
  52.                 'title' => '記事タイトル',  
  53.                 'text' => '記事本文',  
  54.                 'link' => 'http://www.atsoho.com/jobinfo/detail/no-59201.html',  
  55.                 'created' => '2014-09-04 10:12:45',  
  56.                 'modified' => '2014-09-04 10:12:47',  
  57.                 'CategoriesPost' => array(  
  58.                     'id' => 'e6dd311a-33f3-11e4-a724-3417eba238af',  
  59.                     'post_id' => '9e8c4ef7-33d0-11e4-a724-3417eba238af',  
  60.                     'category_id' => '4b056148-33d0-11e4-a724-3417eba238af',  
  61.                     'created' => '2014-09-04 14:25:32',  
  62.                     'modified' => '2014-09-04 14:25:35'  
  63.                 )  
  64.             )  
  65.         )  
  66.     )  
  67. )  

わかり難いからいやだとずっと避けて別々にデータを取得していたのですが、recursiveを設定しなくても、一発で中間データまで取ってきてくれるのはいいですね。
ちょっとわかり難い部分もありましたが、今後は使って生きたいと思います。