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

ITかあさん

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

生まれて初めて、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?

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を設定しなくても、一発で中間データまで取ってきてくれるのはいいですね。
ちょっとわかり難い部分もありましたが、今後は使って生きたいと思います。

初夏のJavaScript祭 in サーキュレーションビル ForPro