0

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

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

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

我的模型:

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 对应的正确数组。

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

4

1 回答 1

1

假设$post是一个Post实体,没有Tags属性,所以$post->Tags会 return 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);

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

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

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

也可以看看

于 2019-07-06T11:37:16.937 回答