0

I am following example documented at http://book.cakephp.org/view/83/hasAndBelongsToMany-HABTM

I am trying to retrieve associated data using hasOne.

I created 3 tables posts, tags and posts_tags. I wrote following code to debug Posts.

$this->Post->bindModel(array(
    'hasOne' => array(
        'PostsTag',
        'FilterTag' => array(
            'className' => 'Tag',
            'foreignKey' => false,
            'conditions' => array('FilterTag.id = PostsTag.tag_id')
))));
$output=$this->Post->find('all', array(
        'fields' => array('Post.*')
));
debug($output);

I was expecting output something like below.

Array
(  
    0 => Array
        {
        [Post] => Array
            (
                [id] => 1
                [title] => test post 1
            )
    [Tag] => Array
        (
            [0] => Array
                (
                    [id] => 1
                    [name] => php
                )
           [1] => Array
                (
                    [id] => 2
                    [name] => javascript
                )
           [2] => Array
                (
                    [id] => 3
                    [name] => xml
                )
        )
}

But my output do not have Tags at all. Here is what I got.

Array
(
    [0] => Array
        (
            [Post] => Array
                (
                    [id] => 1
                    [title] => test post1
                )

        )

    [1] => Array
        (
            [Post] => Array
                (
                    [id] => 2
                    [title] => test post2
                )

        )
)

How do I get associated tags along with the post.

I know I am missing something, but unable to figure out. Any help would be highly appreciated.


Edit 1:

Ok I tried few more variants.

I tried:

$this->Post->bindModel(array(
'hasOne' => array(
        'PostsTag',
        'FilterTag' => array(
            'className' => 'Tag',
            'foreignKey' => false,
            'conditions' => array('FilterTag.id = PostsTag.tag_id')
))));
$output=$this->Post->find('all');

I got:

Array
(
    [0] => Array
        (
            [Post] => Array
                (
                    [id] => 1
                    [title] => test post1
                )

            [PostsTag] => Array
                (
                    [id] => 1
                    [post_id] => 1
                    [tag_id] => 1
                )

            [FilterTag] => Array
                (
                    [id] => 1
                    [name] => php
                )

        )

    [1] => Array
        (
            [Post] => Array
                (
                    [id] => 1
                    [title] => test post1
                )

            [PostsTag] => Array
                (
                    [id] => 2
                    [post_id] => 1
                    [tag_id] => 2
                )

            [FilterTag] => Array
                (
                    [id] => 2
                    [name] => javascript
                )

        )

    [2] => Array
        (
            [Post] => Array
                (
                    [id] => 1
                    [title] => test post1
                )

            [PostsTag] => Array
                (
                    [id] => 3
                    [post_id] => 1
                    [tag_id] => 3
                )

            [FilterTag] => Array
                (
                    [id] => 3
                    [name] => xml
                )

        )
)

I tried:

$output=$this->Post->find('all', array(
        'fields' => array('Post.*', 'FilterTag.*'),
        'recursive' => 1
));

I got:

Array
(
    [0] => Array
        (
            [Post] => Array
                (
                    [id] => 1
                    [title] => test post1
                )

            [FilterTag] => Array
                (
                    [id] => 1
                    [name] => php
                )

        )

    [1] => Array
        (
            [Post] => Array
                (
                    [id] => 1
                    [title] => test post1
                )

            [FilterTag] => Array
                (
                    [id] => 2
                    [name] => javascript
                )

        )

    [2] => Array
        (
            [Post] => Array
                (
                    [id] => 1
                    [title] => test post1
                )

            [FilterTag] => Array
                (
                    [id] => 3
                    [name] => xml
                )

        )
)

Just in case I am missing something, here is my Posts controller:

class PostsController extends AppController {
    var $name = 'Posts';
    var $helpers = array('Html','Ajax','Javascript');
    var $components = array( 'RequestHandler' );

    function index() {
        $this->Post->bindModel(array(
            'hasOne' => array(
                'PostsTag',
                'FilterTag' => array(
                    'className' => 'Tag',
                    'foreignKey' => false,
                    'conditions' => array('FilterTag.id = PostsTag.tag_id')
        ))));

        $output=$this->Post->find('all', array(
                'fields' => array('Post.*', 'FilterTag.*'),
                'recursive' => 1
        ));

    }
}

And here is my Posts model:

class Post extends AppModel {
    var $name = 'Post';
}

I still wonder why is the example from cookbook not working.

Mosu
  • 51
  • 1
  • 4

1 Answers1

0

I would recommend checking 3 things:

  1. See if you have set your associations right (hasMany, hasAndBelongsToMany)

    Make sure you have set the Post HABTM Tag and Tag HABTM Post relationships correctly.

  2. Check the value of $recursive

    Most of the examples in the CakePHP book require that you have your $recursive property set to 1.

  3. Remove the fields restriction: 'fields' => array('Post.*')

    It's possible that Cake is restricting only the Post fields, which is why no Tag fields are showing up. Remove this restriction and try it again.

Let us know if this works for you.

RabidFire
  • 6,280
  • 1
  • 28
  • 24
  • I tried recursive inside find params, didn't work. I tried removing fields restriction, didn't work. I didn't understand what you meant by setting Post HABTM Tag because I am trying to dynamically bind the models. Do we need to set HABTM relationships separately even if we use bindModel? Any example would be helpful. – Mosu Dec 31 '10 at 06:27
  • If you look at the example, it returns `Tag` and not `FilterTag`. I suggested removing the whole `fields` property. In any case, if none of the above worked, then add the `var $hasAndBelongsToMany = array('Tag')` to your Post model and give it a shot. CakePHP works in weird ways. Eventually, it's best to stop using bindModel altogether and use the Containable behaviour instead: http://book.cakephp.org/view/474/Containable I haven't used bindModel and unbindModel ever since I discovered it. :-) – RabidFire Dec 31 '10 at 07:21
  • Its not working even after removing whole fields property. Sometimes we will have variable table names. For example, if we have `$t='Tag';` and we want to associate $t table with Post table. How do we do it? We cannot declare var $hasAndBelongsToMany beforehand as we don't know what $t going to be. – Mosu Dec 31 '10 at 07:53
  • You generally set up all of the "default" relations in your models. You can bind and unbind accordingly. The Containable behavior basically does this for you. – RabidFire Dec 31 '10 at 13:07
  • Yes. I checked containable behavior. Its working great if I hardcode `var $hasAndBelongsToMany = array('Tag')` in my Post Model. What I want is different. I am looking for a way to dynamically bind HABTM associations inside controller action without declaring `$hasAndBelongsToMany` beforehand. I believe `bindModel()` is meant for that. But somehow the example at cookbook itself is not working. If you feel containable behavior can do that without any prior declarations, please post some example or point me to some resource. – Mosu Dec 31 '10 at 15:26
  • Seems like no replies from the community. As the `bindModel()` example from cookbook is not working, should I assume this as a bug and report to cakephp dev team...? I am confused. – Mosu Jan 02 '11 at 19:04
  • @Moin - It makes no sense that you would want to "dynamically bind HABTM associations inside controller action without declaring $hasAndBelongsToMany beforehand". The example from the book definitely works. You need to set up all the associations properly if you want to retrieve related models in the find. If you DON'T want to retrieve that particular related model, then use `$recursive` or Containable to do that! You shouldn't be making new binds for every association. As your program grows in complexity, it will become clearer. – RabidFire Jan 03 '11 at 04:25
  • @RabidFire - I am working on a huge COMPLEX project where I don't know associated model names beforehand. That is why I cannot declare `$hasAndBelongsToMany`. The Posts example I posted is just a recreation of my problem. You said the example from the book definitely works. But it is not working for me. I posted my controller and model code above. Am I missing some point in the book? or can you point out which line is causing the problem? – Mosu Jan 03 '11 at 05:11