我使用CakePHP 3.7.7,并且在我的Posts和Tag模型之间有一个有效的belongsToMany关联。在我的“帖子”视图中,我设法通过包含列出了所有相关的标签,并且一切正常。
但是,在主要帖子内容下方,我需要显示一些“相关帖子”建议。
我一直在寻找答案,我认为解决方案可能是通过使用 matching ,但是我无法获得所需的查询结果。
我的模特:
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来获得正确的数组。
我如何使其起作用?还是会有更好的选择?
答案 0 :(得分:1)
假设$post
是Post
实体,则没有Tags
属性,因此$post->Tags
将返回null
,因此在您尝试访问时会出错返回值的id
属性。
默认情况下,belongsToMany
关联的属性名称是关联名称的复数形式,小写,加下划线的变体,因此在您的情况下为tags
。但是它将是一个数组,所以当然您也不能访问其上的id
属性。
如果您想根据它们共享的标签查找相关的帖子,那么您将需要所有标签ID的列表(而不仅仅是一个),或者您必须使查询更复杂一些,以便示例与获取当前posts标签的子查询匹配。您的代码还有其他问题,例如您没有具体的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
]);
另请参见