CakePHP 3.x:查询相关帖子

时间:2015-11-26 15:00:57

标签: cakephp cakephp-3.0

我有PostsTags模型,与"相关,属于许多"关联。

因此,在我的数据库中,我有poststags个表以及一个包含posts_tagspost_id字段的tag_id表。 tags表格包含post_count字段,显示属于该标记的帖子数。

当我收到帖子时,我会收到与之相关的标签。

$this->Posts->find()
    ->contain(['Tags'])
    ->where(['Posts.id' => $id])
    ->first());

现在,对于每个标记,我想获得一个包含该标记的帖子,不包括初始帖子,排序创建日期(created字段)。 重要的是,每个标签都会获得一个非已经获得的帖子。

我可以使用foreach并为每个标记获取包含它的帖子,排除初始帖子的ID和已经获取的帖子。

我想知道我是否可以使用单个查询执行此操作,并有一个可以使用的示例。

感谢。

修改
临时解决方案,对每个标记使用查询

首先,我得到主要帖子:

$post = $this->Posts->find()
    ->contain(['Tags'])
    ->where(['Posts.id' => $id])
    ->first();

在这种情况下,帖子通过其ID进行恢复,但您可以采用不同的方式。您也可以使用缓存 重要的事情$post变量。

现在(这是一个使用缓存的好主意......):

//Tries to gets related posts from cache
$related = Cache::read($cache = sprintf('related_posts_for_%s', $post->id), 'posts');

if(empty($related)) {
    $tags = $post->tags;

    //Re-orders tags, using the "post_count" field, then based on the popularity of tags
    usort($tags, function($a, $b) { return $b['post_count'] - $a['post_count']; });

    //Gets only the first 5 tags
    $tags = array_slice($tags, 0 , 5);

    //This array will be contain the ID to be excluded
    $exclude = [$post->id];

    //Gets a related post for each tag
    //Reveres the tags order, because the tags less popular have less chance to find a related post
    foreach(array_reverse($tags) as $tag) {
        $post = $this->Posts->find('active')
            ->select(['id', 'title', 'slug'])
            ->matching('Tags', function($q) use($tag) {
                return $q->where(['Tags.id' => $tag->id]);
            })
            ->where(['Posts.id NOT IN' => $exclude])
            ->first();

        //Adds the post to the related posts and its ID to the IDs to be excluded for the next query
        if(!empty($post)) {
            $related[] = $post;
            $exclude[] = $post->id;
        }
    }

    Cache::write($cache, $related, 'posts');
}

//Related posts
debug($related);

注意:在此代码之后,$post变量不再包含原始帖子。注意或使用不同的变量名称作为相关帖子。

1 个答案:

答案 0 :(得分:1)

试试这个(未经测试)

$this->Posts->find()
->contain([
    'Tags',
    'Tags.Posts' => function($q) use($id) {
        $q->where(['id !=' => $id])
            ->order(['created' => 'desc'])
            ->limit(1);
        return $q;
     }
   ])
->where(['Posts.id' => $id])
->first());

但是通过这种方式,你可以两次获得一个帖子(我现在看到你不想要这个)