2
votes

I have the following code in which I am finding a single tag. I want to contain all Posts that relate to a tag that have not been "deleted." I then want to find all tags that those Posts belong to.

As a test, I have attached two models to Post at a third level recursion, Tag and User, via contain. The containable behavior will retrieve the User model associated with Post but the Tag model that is associated back to posts does not appear. Any idea if this type of recursion (based on the originating model) is allowed in CakePHP?

I've tried the contain with and without the Tag conditions, so I know that's not causing the issue. If that was the issue, then I should get an empty Tag array, but there's nothing.

$tag = $this->Tag->find(
    'first',
    array(
        'conditions' => $conditions,
        'contain' => array(
            'Post' => array(
                'conditions' => array(
                    'Post.deleted' => 0
                ),
                'limit' => 25,
                'User',
                'Tag' => array(
                    'conditions' => array(
                        'Tag.deleted' => 0
                    )
                )
            )
        )
    )
);

I know there are ways around this, but I am specifically interested in why the containable behavior does this. I'm sure that it's more efficient to get all of the tags for a post in this matter rather than looping through the post results and re-querying for the tags. My hope is that someone will have experience with this issue, but I will dig into the CakePHP Containable behavior code today to see if it is something that is intended with the framework or a possible bug.

1

1 Answers

3
votes

This is not a real answer to the question (which is more of why it happens), but I think this is why it happens and how to get around it. I dug into the Containable class and the query is constructed with my Tag model intact, which lead me to believe that the query and association in the Model class is probably removing it because Tag is ambiguous. Tag would appear on both the left and the right side of the Post record, so it probably gets removed to prevent the recursion from looping. I was too lazy to dig into the Model class to get the real answer.

To resolve this, I bound a model alias to post on the fly, called PT. I added that alias to the contain code and voila, my tags were there!

$this->Tag->Post->bindModel(
            array(
                'hasAndBelongsToMany' => array(
                    'PT' => array(
                        'className' => 'Tag'
                    )
                )
            )
        );

And the contain code...

$tag = $this->Tag->find(
            'first',
            array(
                'conditions' => $conditions,
                'contain' => array(
                    'Post' => array(
                        'conditions' => array(
                            'Post.deleted' => 0
                        ),
                        'User',
                        'PT' => array(
                            'conditions' => array(
                                'PT.deleted' => 0
                            )
                        )
                    )
                )
            )
        );