I have 3 blog tables in my CakePHP application that are linked with a HABTM association following the CakePHP naming conventions: posts - post_tag_links - tags.
I try to get an array with all the posts that are linked to a specific tag (e.g. "design"). This query works for me:
$this->Post->query("
SELECT
Post.id, Post.title FROM posts AS Post
LEFT JOIN
post_tag_links AS PostTagLink ON Post.id = PostTagLink.post_id
LEFT JOIN
tags AS Tag ON Tag.id = PostTagLink.tag_id
WHERE
Tag.slug = 'design'
GROUP BY
Post.id"
);
CakePHP then generates the following query and gave me 4 results:
SELECT
Post.id,
Post.title
FROM
posts AS Post
LEFT JOIN
post_tag_links AS PostTagLink
ON Post.id = PostTagLink.post_id
LEFT JOIN
tags AS Tag
ON Tag.id = PostTagLink.tag_id
WHERE
Tag.slug = 'design'
GROUP BY
Post.id
BUT... to do some best practice, it's better to not use the "query" method. So I tried the "find all" method:
$this->Post->find('all', array(
'fields' => array(
'Post.id',
'Post.title'
),
'joins' => array(
array(
'table' => 'post_tag_links',
'alias' => 'PostTagLink',
'type' => 'LEFT',
'conditions' => array(
'Post.id' => 'PostTagLink.post_id'
)
),
array(
'table' => 'tags',
'alias' => 'Tag',
'type' => 'LEFT',
'conditions' => array(
'Tag.id' => 'PostTagLink.tag_id',
)
)
),
'conditions' => array(
'Tag.slug' => 'design'
),
'group' => 'Post.id'
)
));
CakePHP then generates the following query and gave NO single result:
SELECT
`Post`.`id`,
`Post`.`title`
FROM
`kattenbelletjes`.`posts` AS `Post`
LEFT JOIN
`kattenbelletjes`.`post_tag_links` AS `PostTagLink`
ON (
`Post`.`id` = 'PostTagLink.post_id'
)
LEFT JOIN
`kattenbelletjes`.`tags` AS `Tag`
ON (
`Tag`.`id` = 'PostTagLink.tag_id'
)
WHERE
`Tag`.`slug` = 'design'
GROUP BY
`Post`.`id
After a lot of trial and error, I discovered the problem is the backticks that CakePHP creates when building up that last query.
My question is: what's the difference between the query with the backticks and the one without the backticks? And how can you leave those backticks in CakePHP?
Thanks ;)
The backticks most probably aren't the problem, as all they do is escaping the identifiers. This is a pretty easy find btw.
The actual problem is more likely that you've defined the conditions in the wrong way, what you are doing there is creating string literal comparision conditions, ie
`Post`.`id` = 'PostTagLink.post_id'
Comparing the id
column value to the string PostTagLink.post_id
will of course fail.
The correct way to define identifier comparisons is to supply the conditon fragment as a single value instead of a key => value set, ie
'conditions' => array(
'Post.id = PostTagLink.post_id'
)
and
'conditions' => array(
'Tag.id = PostTagLink.tag_id'
)
See also