让我们考虑下面的例子:一个线程有帖子,而这些帖子也有一个"线程"关系。每篇文章的标题必须包含父线程的标题。
class Thread extends Model
{
public function posts()
{
return $this->hasMany(Post::class);
}
}
class Post extends Model
{
public function thread()
{
return $this->belongsTo(Thread::class);
}
public function getTitleAttribute(string $title): string
{
return $this->thread->title . ': ' . $title;
}
}
我想要达到的目标:
//when we load the posts using the thread...
$posts = $thread->posts;
//...I want the "thread" relation of each post to be automatically set to $thread, so that:
$posts->first()->thread === $thread //true
默认不为真。如果我们这样做:
$array = $thread->posts->toArray();
这将导致每个帖子一个接一个地从DB加载线程,这是超级非最佳的。是否有一些优雅的Laravel技术来建立刚刚加载的模型之间的关系?
您可以像这样延迟加载它们
$posts = $thread->posts()->with('thread')->get();
如果你不想要额外的查询,你可以使用map()
$thread->posts->map(function($post) use ($thread) {
return $post->setRelation('thread', $thread);
});
这将导致相同数量的对象,但也将导致引用循环。
//this is defined and doesn't use more object or launch other queries
$thread->posts->first()->thread->posts()->first()->thread;
如果你想自动化它,我建议你在Thread模型上创建一个函数来让帖子线程化。
public function loadThreadedPosts()
{
$this->posts->map(function($post) {
return $post->setRelation('thread', $this);
});
return $this;
}
//then you can
$thread->loadThreadedPosts()->posts;
如果你想在调用"post "关系时自动完成在Thread::class
模型上,将此方法添加到您的Thread::class
中以覆盖特性HasAttributes
中存在的功能,风险由您自己承担
/**
* Get a relationship value from a method.
*
* @param string $method
* @return mixed
*
* @throws LogicException
*/
protected function getRelationshipFromMethod($method)
{
$relation = $this->$method();
if (! $relation instanceof Relation) {
if (is_null($relation)) {
throw new LogicException(sprintf(
'%s::%s must return a relationship instance, but "null" was returned. Was the "return" keyword used?', static::class, $method
));
}
throw new LogicException(sprintf(
'%s::%s must return a relationship instance.', static::class, $method
));
}
return tap($relation->getResults(), function ($results) use ($method) {
if ($method == "posts") {
$results->map(function($post) {
return $post->setRelation('thread', $this);
});
}
$this->setRelation($method, $results);
});
}
希望你明白,这覆盖了一个供应商的方法,并可能导致未来的问题,我也不认为这一个方法工作与急切加载(例如:Thread::with('posts')->get()
),我不知道还有什么可能会被打破/有意外的行为。
正如我所说,风险由你自己承担(打赌/希望->loadThreadedPosts()
现在看起来更有趣)