Search code examples
cakephpcakephp-2.0modelscontainable

Cakephp find all query on multiple models


I try the following to get al the Articles That belong to MenuItem 6 and have an Article content_type of 'blog'. It does find all the articles with content_type='blog'. But I only want it to return the Article if it belongs to Menuitem 7. And now it return an empty value for MenuItem when not 7.

How can I accomplish that it'll only load the articles from MenuItem 7?

MenuItem has a HABTM relationship with Article

code:

 $d=$this->Article->find('all' , array('contain' => array(
        'MenuItem' => array(
            'conditions' => array(
                'MenuItem.id ' => 7,        
             ),
                'fields'=>'id'
        ),
        'Tag'=>array(
            'conditions'=>array(
                'Tag.name'=>'tag1'
            ),
            'fields'=>'name'
        )
      ),
      'conditions'=>array('Article.content_type' => 'blog'),
      'fields'=>array('id','content_type'),
      'recursive'=>1
     ));

     debug($d);

array:

 array(
      (int) 10 => array(
    'Article' => array(
        'id' => '15',
        'content_type' => 'blog'
    ),
    'Tag' => array(),
    'MenuItem' => array()
),
     (int) 11 => array(
    'Article' => array(
        'id' => '16',
        'content_type' => 'blog'
    ),
    'Tag' => array(),
    'MenuItem' => array(
        (int) 0 => array(
            'id' => '7',
            'MenuItemsArticle' => array(
                'id' => '18',
                'title' => '',
                'article_id' => '16',
                'menu_item_id' => '7'
            )
        )
    )
      )
 )

Solution

  • I think your best bet for this type of find condition is to modify your models to use hasMany through (The Join Model). Here's an example I tested that does what you want:

    Article.php

    class Article extends AppModel {
        public $hasMany = array('ArticleMenuItem');
    }
    

    MenuItem.php

    class MenuItem extends AppModel {
        public $hasMany = array('ArticleMenuItem');
    }
    

    ArticleMenuItem.php

    class ArticleMenuItem extends AppModel {
        public $useTable = 'articles_menu_items';
    
        public $belongsTo = array(
            'Article',
            'MenuItem'
        );
    }
    

    The Find Call

    $articles = $this->ArticleMenuItem->find('all', array(
        'conditions' => array(
            'menu_item_id' => 7,
            'Article.content_type' => 'blog'
        ),
        'contain' => array(
            'Article' => array(
                'fields' => array(
                    'id',
                    'title'
                )
            ),
            'Tag'
        )
    ));
    

    Here's what it produces:

    array(
        (int) 0 => array(
            'ArticleMenuItem' => array(
                'article_id' => '1',
                'menu_item_id' => '7'
            ),
            'Article' => array(
                'id' => '1',
                'content_type' => 'blog',
                'title' => 'test blog'
            )
        ),
        (int) 1 => array(
            'ArticleMenuItem' => array(
                'article_id' => '4',
                'menu_item_id' => '7'
            ),
            'Article' => array(
                'id' => '4',
                'content_type' => 'blog',
                'title' => 'another'
            )
        )
    )
    

    And here's the query it generates:

    SELECT `ArticleMenuItem`.`article_id`, `ArticleMenuItem`.`menu_item_id`, `Article`.`id`, `Article`.`content_type`, `Article`.`title` FROM `caketest`.`articles_menu_items` AS `ArticleMenuItem` LEFT JOIN `caketest`.`articles` AS `Article` ON (`ArticleMenuItem`.`article_id` = `Article`.`id`) WHERE `menu_item_id` = 7 AND `Article`.`content_type` = 'blog'
    

    I've set $recursive = -1 in my AppModel as well. I would suggest doing the same since you are using the containable behavior, it's much more efficient because it only pulls back the data that you need. :)

    Hope this helps, any questions just let me know.