HOME>WEBプログラム覚書>[CakePHP2.X] hasAndBelongsToMany(HABTM)関係にあるモデルのconditions

[CakePHP2.X] hasAndBelongsToMany(HABTM)関係にあるモデルのconditions

つい最近わかった。

ブログを例にして投稿(Post)とタグ(Tag)がhasAndBelongsToManyの関係にあるとします。
でもってタグ「iPad」のページに「iPad」のタグが付いた投稿を表示させることは簡単ですよね。

Controller/TagsController.php

  1. <?php
  2. class TagsController extends AppController {
  3.         public function view()
  4.     {
  5.         if (isset($this->request->params['slug'])) {
  6.             $tag = $this->Tag->find(
  7.                 'first',
  8.                 array(
  9.                     'conditions' => array(
  10.                         'Tag.slug'   => $this->request->params['slug'],
  11.                     ),
  12.                 )
  13.             );
  14.             $this->set('posts', $tag['Post']);
  15.         }
  16.         }
  17. }
  18. ?>

こんな感じでアクションを作成して /tags/view/ipad にアクセスすると iPad のタグがついた投稿を表示することができます。

では「iPad」のタグが付いていて、投稿のステータスが「公開」になっている
投稿を表示させるにはどうすればよいでしょう?

Controller/TagsController.php

  1. <?php
  2. class TagsController extends AppController {
  3.         public function view()
  4.     {
  5.         if (isset($this->request->params['slug'])) {
  6.             $tag = $this->Tag->find(
  7.                 'first',
  8.                 array(
  9.                     'conditions' => array(
  10.                         'Tag.slug'     => $this->request->params['slug'],
  11.                         'Post.publish' => 1,
  12.                     ),
  13.                 )
  14.             );
  15.             $this->set('posts', $tag['Post']);
  16.         }
  17.         }
  18. }
  19. ?>

こんな感じに書きたくなりますが、これはエラーになります。なので、

Controller/TagsController.php

  1. <?php
  2. class TagsController extends AppController {
  3.  
  4.         public function view()
  5.     {
  6.         if (isset($this->request->params['slug'])) {
  7.             $tag = $this->Tag->find(
  8.                 'first',
  9.                 array(
  10.                     'conditions' => array(
  11.                         'Tag.slug'   => $this->request->params['slug'],
  12.                     ),
  13.                 )
  14.             );
  15.  
  16.             // 公開の投稿のみ取得する
  17.             $posts = array();
  18.             foreach ($tag['Post'] as $post) {
  19.                 if ($post['publish'] == 1) {
  20.                     $posts[] = $post;
  21.                 }
  22.             }
  23.  
  24.             $this->set(compact('tag', 'posts'));
  25.         }
  26.         }
  27. }
  28. ?>

のようにコントローラーでforeachするとか
最悪なことにビューでif文とかやっちゃってましたw

でも実は下記のようにモデルの hasAndBelongsToMany プロパティに条件を追加することで
hasAndBelongsToMany相手の検索条件を設定できるようです。

Controller/TagsController.php

  1. <?php
  2. class TagsController extends AppController {
  3.         public function view()
  4.     {
  5.         if (isset($this->request->params['slug'])) {
  6.  
  7.             // Postの条件追加
  8.             $this->Tag->hasAndBelongsToMany['Post']['conditions'] = array('Post.publish' => 1);
  9.  
  10.             $tag = $this->Tag->find(
  11.                 'first',
  12.                 array(
  13.                     'conditions' => array(
  14.                         'Tag.slug'   => $this->request->params['slug'],
  15.                     ),
  16.                 )
  17.             );
  18.  
  19.             // foreach 不要
  20.             $this->set('posts', $tag['Post']);
  21.         }
  22.         }
  23. }
  24. ?>

注意点としてはパフォーマンスは調べてないのでわかりませんが、変なクエリ発行して遅くなるかもしれませんw
また再度findする場合、Model::$hasAndBelongsToMany に設定した検索条件は残るので不要であれば初期化しましょう。
実行Verは2.3.8です。

以下は上記の例での各モデルのサンプルです。特に何もしてません。

Model

Model/Post.php

  1. <?php
  2. class Post extends AppModel {
  3.     public $hasAndBelongsToMany = array(
  4.         'Tag' => array(
  5.             'className'             => 'Tag',
  6.             'joinTable'             => 'posts_tags',
  7.             'foreignKey'            => 'post_id',
  8.             'associationForeignKey' => 'tag_id',
  9.             'unique'                => 'keepExisting',
  10.             'conditions'            => '',
  11.             'fields'                => '',
  12.             'order'                 => '',
  13.             'limit'                 => '',
  14.             'offset'                => '',
  15.             'finderQuery'           => '',
  16.             'deleteQuery'           => '',
  17.             'insertQuery'           => ''
  18.         )
  19.     );
  20. }
  21. ?>

Model/Tag.php

  1. <?php
  2. class Tag extends AppModel {
  3.     public $hasAndBelongsToMany = array(
  4.         'Post' => array(
  5.             'className'             => 'Post',
  6.             'joinTable'             => 'posts_tags',
  7.             'foreignKey'            => 'tag_id',
  8.             'associationForeignKey' => 'post_id',
  9.             'unique'                => 'keepExisting',
  10.             'conditions'            => '',
  11.             'fields'                => '',
  12.             'order'                 => '',
  13.             'limit'                 => '',
  14.             'offset'                => '',
  15.             'finderQuery'           => '',
  16.             'deleteQuery'           => '',
  17.             'insertQuery'           => ''
  18.         )
  19.     );
  20. }
  21. ?>

Model/PostsTag.php

  1. <?php
  2. class PostsTag extends AppModel {
  3. /**
  4.  * belongsTo associations
  5.  *
  6.  * @var array
  7.  */
  8.     public $belongsTo = array(
  9.         'Post' => array(
  10.             'className'  => 'Post',
  11.             'foreignKey' => 'post_id',
  12.             'conditions' => '',
  13.             'fields'     => '',
  14.             'order'      => ''
  15.         ),
  16.         'Tag'  => array(
  17.             'className'  => 'Tag',
  18.             'foreignKey' => 'tag_id',
  19.             'conditions' => '',
  20.             'fields'     => '',
  21.             'order'      => ''
  22.         )
  23.     );
  24. }
  25. ?>
投稿日 2013年11月14日 00:39
カテゴリ PHP
タグ CakePHP
トラックバック URL http://www.kantenna.com/cgi-bin/mt504/mt-tb.cgi/1333

コメント

フィードバック

2016年3月 3日 12:53 | 返信

参考になりました。ありがとうございます。

コメントする
Name
Email Address
URL