【问题标题】:How to implement "related posts" in a HABTM relationship?如何在 HABTM 关系中实现“相关帖子”?
【发布时间】:2019-11-16 09:41:59
【问题描述】:

我使用的是 CakePHP 3.7.7,并且我的 Posts 和 Tags 模型之间有一个有效的 belongsToMany 关联。在我的帖子视图中,我设法通过 contain 列出了所有相关的标签,一切都按预期进行。

但是,在主要帖子内容下方,我需要显示一些“相关帖子”建议。

我一直在寻找答案,我认为解决方案可能是使用匹配,但我无法获得我想要的查询结果。

我的模特:

class PostsTable extends Table
{
    public function initialize(array $config)
    {
        parent::initialize($config);

        $this->setTable('posts');
        $this->setDisplayField('name');
        $this->setPrimaryKey('id');

        $this->belongsToMany('Tags', [
            'foreignKey' => 'post_id',
            'targetForeignKey' => 'tag_id',
            'joinTable' => 'posts_tags',
    'dependant' => false
        ]);
    }
}

class TagsTable extends Table
{
    public function initialize(array $config)
    {
        parent::initialize($config);

        $this->setTable('Tags');
        $this->setDisplayField('title');
        $this->setPrimaryKey('id');

        $this->belongsTo('Tags', [
            'foreignKey' => 'tag_id',
            'joinType' => 'INNER'
        ]);

    $this->belongsToMany('Posts');
    }
}

class PostsTagsTable extends Table
{
    public function initialize(array $config)
    {
        parent::initialize($config);

        $this->setTable('posts_tags');
        $this->setDisplayField('id');
        $this->setPrimaryKey('id');

        $this->belongsTo('Posts', [
            'foreignKey' => 'post_id',
            'joinType' => 'INNER'
        ]);
        $this->belongsTo('Tags', [
            'foreignKey' => 'tag_id',
            'joinType' => 'INNER'
        ]);
    }
}

还有我的控制器:

class PostsController extends AppController
{
    public function view($slug = null)
    {
        $post = $this->Posts->findBySlug($slug)
        ->contain(['Tags'])
        ->first();

        $this->set('post', $post);

    }
}

我尝试在我的视图函数中添加这个:

$relId = $post->Tags->id;

$related = $this->Posts->find('all')
    ->contain(['PostsTags','Tags'])
    ->matching('PostsTags', function(\Cake\ORM\Query $query) use ($post) {
        return $query->where([
            'PostsTags.tag_id' => $relPost
            ]);
        })
    ->limit(3)
    ->execute();

$this->set('relatedPosts', $related);

...但这不起作用。我不断收到错误通知:

注意(8):试图获取非对象的属性

所以我显然无法获得与当前帖子相关的标签 id 对应的正确数组。

我怎样才能让它工作?或者更好的选择是什么?

【问题讨论】:

    标签: cakephp associations query-builder cakephp-3.7


    【解决方案1】:

    假设$postPost 实体,则没有Tags 属性,因此$post->Tags 将返回null,因此当您尝试访问返回值的id 属性时会出错。

    默认情况下,belongsToMany 关联的属性名称是关联名称的复数、小写、下划线变体,因此在您的情况下为 tags。但是它会是一个数组,所以当然你也不能访问它上面的 id 属性。

    如果您想根据他们共享的标签查找相关帖子,那么您要么需要所有标签 ID 的列表(不仅仅是一个),要么您必须使查询更复杂一些示例匹配获取当前帖子标签的子查询。您的代码还有其他一些问题,例如您没有具体的 PostsTags 关联(因此您不能包含或匹配它),您将错误的变量传递给闭包,您需要分组通过帖子主键避免重复,您可能希望排除您已经拥有的帖子。

    这是一个使用已查询标签的快速而肮脏的示例,首先提取所有 ID,然后根据这些 ID 查询帖子,不包括当前帖子:

    $tagIds = collection($post->tags)->extract('id')->toArray();
    
    if (!empty($tagIds)) {
        $relatedPosts = $this->Posts
            ->find()
            ->matching('Tags', function(\Cake\ORM\Query $query) use ($tagIds) {
                return $query->where([
                    'Tags.id IN' => $tagIds
                ]);
            })
            ->where([
                'Posts.id !=' => $post->id
            ])
            ->group('Posts.id')
            ->limit(3);
    } else {
        $relatedPosts = null;
    }
    
    $this->set('relatedPosts', $relatedPosts);
    

    在您看来,在使用它之前,您必须检查 $relatedPosts 是否为 null

    用于获取标签 ID 的子查询可能如下所示:

    $tagIds = $this->Posts->Tags
        ->junction()
        ->find()
        ->select(['PostsTags.tag_id'])
        ->where([
            'PostsTags.post_id' => $post->id
        ]);
    

    另见

    【讨论】:

    • 完美!我仍然不确定联结或组方法是如何工作的,但查询正在按现在应该的方式工作。谢谢!我会继续研究这些东西,但我现在有一个有效的“相关帖子”查询供我查看。
    • @DamiánFraustro junction() 方法是BelongsToMany 关联类的一个方法(PostsTable 对象上的神奇Tags 属性不会返回表对象,而是关联对象),它将返回表示用于Tags 关联的连接表的表对象。查询构建器group() 方法只是配置GROUP BY SQL 语句。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-25
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-28
    相关资源
    最近更新 更多