『CakePHP』を使ってみる 〜10〜 タグ機能を作ってみる

タグ機能を作ってみることに。

テーブルを作る

ドキュメントの『6.4.5. hasAndBelongsToMany の定義と問い合わせ』あたりがちょうど似たような話なので、テーブル構成を参考に。
http://cakephp.jp/doc/ch06s04.html#id4803164

CREATE TABLE `tuto_tags` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`tag` INT NOT NULL
) TYPE = MYISAM ;


CREATE TABLE `tuto_posts_tags` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`post_id` INT NOT NULL ,
`tag_id` INT NOT NULL
) TYPE = MYISAM ;

Tag モデルを作る

  • /home/theworld/cake/project/tutorial/models/tag.php
<?php
class Tag extends AppModel
{
	var $name = 'Tag';
	var $hasAndBelongsToMany = array(
			'Tag' => array(
				'className' => 'Post',
				'joinTable' => 'posts_tags',
				'foreignKey' => 'tag_id',
				'associationForeignKey'=> 'post_id',
			),
		);
}
?>

Post モデルにもアソシエーションを追加

  • /home/theworld/cake/project/tutorial/models/post.php
<?php
class Post extends AppModel
{
	var $name = "Post";
	var $validate = array(
			'title' => array('required' => VALID_NOT_EMPTY),
			'body' => array('required' => VALID_NOT_EMPTY),
	);

	var $hasMany = array(
			'Comment' => array(
				'className' => 'Comment',
				'conditions' => '',
				'order' => '',
				'dependent' => true,
				'foreignKey' => 'post_id',
			),
	);
	
	// ココから
	var $hasAndBelongsToMany = array(
			'Tag' => array(
				'className' => 'Tag',
				 'joinTable' => 'posts_tags',
				 'foreignKey' => 'post_id',
				 'associationForeignKey'=> 'tag_id',
				 'conditions' => '',
				 'order' => '',
				 'limit' => '',
				 'unique' => true,
				 'finderQuery' => '',
				 'deleteQuery'=> '',
			)
		);
}
?>

Post の add ビューにタグ用のフォームを追加

  • /home/theworld/cake/project/tutorial/views/posts/add.thtml
<p>Tag:(カンマ区切りで入力)
<?php echo $form->input('Post.tag', array('type' => 'text'))?>
<p>

Post コントローラ の add ファンクションにタグ登録の処理を追加

  • /home/theworld/cake/project/tutorial/controllers/posts_controller.php
処理の流れ
  1. 入力されたカンマ区切りのデータをばらす
  2. バラしたタグが tuto_tags に登録されているされている確認
  3. 無かったら登録。登録idを取得。すでにある場合はその id を取得。
  4. post_id と tag_id を tuto_posts_tags に記録
<?php
class PostsController extends AppController {

	var $name = 'Posts';
	var $uses = array('Tag','Post');

	function add()
	{
		if(!empty($this->data))
		{
			$id_array = array(); // ここから
			if($this->data['Post']['tag'])
			{
				$tags_array = explode(',', $this->data['Post']['tag']);
				foreach($tags_array as $k => $v)
				{
					$tagdata = $this->Tag->findByTag(trim($v));
					if(empty($tagdata))
					{
						$tmp['Tag'][] = array('tag' => trim($v), 'id' => '');
						$id_array[] = $this->Tag->getLastInsertId();
					}
					else
					{
						$id_array[] = $tagdata['Tag']['id'];
					}
				}
			} //ここまで

			if(!empty($id_array))
			{
				$this->data['Tag']['Tag'] = $id_array;
			}

			if($this->Post->save($this->data))
			{
				$this->flash('Your post has been saved', '/posts/');
			}
		
		}
	}
}
?>

//ここから、//ここまで、とコメントつけた部分は、データベースの処理になるからモデルの方に切り出すのが正しいのだろうか?


tuto_tags に登録する前データを作る以下の部分は、

$tmp['Tag'][] = array('tag' => trim($v), 'id' => '');

最初下のように書いていてうまくいかなかった。

$tmp['Tag'][] = array('tag' => trim($v));

最初のように空文字をつめないといけなかった。


とりあえず上記でタグの登録はできるようになった。
編集する場合は、タグのリストを持ってきてカンマ区切りでつなげて復元してあげて、というカンジになるかな。時間が無いので後で試してみることに。


記憶を呼び覚ましながら書いているので全然だめだ。
やりながらもっとメモしないと後で見て参考にならない!


データベースのアソシエーションについては今後も課題。


セッション、キャッシュについても試さなくては。