问题
I have a model, Comment, that belongsto Module, Photo, Review, Article, and User. In turn, each of those models havemany Comment.
User belongsto Avatar and Avatar hasmany User
In the code below I successfully retrieve the latest 5 comments regardless of what model they come from (Photo, Article, Review) and I display some information about the User (username, online status).
$recentComments = $this->find('all',
array(
'limit' => '5',
'order' => array('Comment.id' => 'desc'),
'conditions' => array(
'Comment.page_id' => $page_id
),
'contain' => array(
'Photo' => array(
'fields' => array('Photo.id'),
'conditions' => array(
'Comment.module_id' => 8
),
),
'Review' => array(
'fields' => array('Review.title', 'Review.id'),
'conditions' => array(
'Comment.module_id' => 2
),
),
'Article' => array(
'fields' => array('Article.title', 'Article.id'),
'conditions' => array(
'Comment.module_id' => 3
),
),
'Module' => array(
'fields' => array('Module.model', 'Module.post_title'),
),
'User' => array(
'fields' => array('User.username', 'User.online'),
),
)
));
Unfortunately there are some issues with this. As you can see above I don't contain User->Avatar and all expected data is retrieved successfully.
$recentComments = Array
(
[0] => Array
(
[Comment] => Array
(
[id] => 179
[page_id] => 2
[module_id] => 3
[page] =>
[user_id] => 29
[post_id] => 9
[title] => test comment for article 9
[content] => here is the content for the comment
[created] => 2013-04-24 00:00:00
[redeemed] => 0
[status] => 0
)
[User] => Array
(
[username] => bowlerae
[online] => 0
)
[Module] => Array
(
[model] => Article
[post_title] => title
)
[Article] => Array
(
[title] => Test title for article 9
[id] => 9
[likes] => 0
[dislikes] => 0
[comments] => 2
)
[Photo] => Array
(
[id] =>
)
[Review] => Array
(
[title] =>
[id] =>
)
)
However, if I DO contain User->Avatar like this...
'User' => array(
'fields' => array('User.username', 'User.online'),
'Avatar' => array(
'fields' => array('Avatar.file')
)
),
Then the recursion basically becomes unlimited, ALL models related to Comment, User, Module, Article, Photo and Review are also retrieved which is A LOT.
Can anyone explain why this is happening? I will be happy to submit more code from some of the models if needed but I don't see any issues there.
Take a look at another example that works successfully...Below I am retrieving the 5 most recent articles. All information including the user Avatar is successfully retreived.
$this->set('articles_sidebar', ClassRegistry::init('Article')->find('all',
array(
'limit' => '5',
'order' => array('Article.id' => 'desc'),
'conditions' => array('
Article.page_id' => $page_id
),
'contain' => array(
'User' => array(
'fields' => array('User.username', 'User.online'),
'Avatar' => array(
'fields' => array('Avatar.file')
)
),
)
)));
Please note these two finds are performed in the AppController in the beforeRender given that $page_id > 0. $page_id is set in whatever the current controller is. I know people would probably ask about it but that's not what the issue is as I mentioned that example 2 retrieving the recent articles currently works.
EDIT: I discovered that it has something to do with my afterfind callback in the Article model. Is there a way I can tweak the queries in the afterfind and/or the $recentComments query so that they still work without breaking my contain? I don't need the likes, dislikes or comments virtual fields in my $recentComments query which is why they are not listed as one of the contained fields.
function afterFind($results, $primary = false) {
parent::afterFind($results, $primary);
foreach($results as $key => $val){
if (isset($val['Article']['id'])){
$results[$key]['Article']['likes'] = $this->Like->find('count', array('conditions' => array('Like.post_id' => $results[$key]['Article']['id'], 'Like.module_id' => 3, 'Like.status' => 0)));
$results[$key]['Article']['dislikes'] = $this->Like->find('count', array('conditions' => array('Like.post_id' => $results[$key]['Article']['id'], 'Like.module_id' => 3, 'Like.status' => 1)));
$results[$key]['Article']['comments'] = $this->Comment->find('count', array('conditions' => array('Comment.post_id' => $results[$key]['Article']['id'], 'Comment.module_id' => 3, 'Comment.status < 2')));
}
} // end for each
return $results;
} // end afterfind
回答1:
My guess is your problem is this:
When using ‘fields’ and ‘contain’ options - be careful to include all foreign keys that your query directly or indirectly requires.
Make sure you're including whatever field(s) are used to join User and Avatar models.
(read here)
回答2:
For now I changed (in the Article model afterFind)
if (isset($val['Article']['id']))
to
if (isset($val['Article']['id']) && $val == "article")
Seems to be working in current controller but need further testing. Is there a better solution?
来源:https://stackoverflow.com/questions/16205520/cakephp-2-4-2-contain-not-working-as-expected