如何将已有的模型插入到关系中



我经常有两个1:x关系的模型:

class Child extends Model 
{
public function parent() 
{
return $this->belongsTo(Parent::class);
}
}

现在,有时我已经有一个相关模型的实例在一个函数中:

function f(Parent $parent): Child
{
// ...
$child = $parent->createChild();
// ...
return $child
}

另一个函数以Child为参数,需要Parent类的属性:

function g(Child $child)
{
$child->update([
'attribute' => h($child->parent->attribute)  
]);
}

现在,如果使用从f返回的Child实例调用g,那么将从DB检索两次Parent实例。除非我们添加Parent参数并将实例传递给g,或者按照如下方式修改f:

function f(Parent $parent): Child
{
// ...
$child = $parent->createChild();
// ...
$child->parent = $parent;
return $child
}

我更喜欢第二种方法,而不是添加另一个参数,因为调用g的上下文可能没有访问Parent实例的权限。而且通常效果很好。但是,它在g中的update语句上失败了:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'parent' in 'field list' (SQL: update `children`...

我的问题是:

是否有一种方法可以插入一个现有的模型实例到适当的关系中,而不需要模型将分配注册为列更新?

调用$child->parent = $parent尝试设置parent字段属性在$child对象上。但是,您希望设置parent关系属性。为此,您需要使用setRelation()方法:

function f(Parent $parent): Child
{
// ...
$child = $parent->createChild();
// ...
$child->setRelation('parent', $parent);
return $child;
}
然而,在这一点上,您需要注意不要创建循环引用。如果将$parent->child关系设置为$child实例,然后将$child->parent关系设置为$parent实例,则创建了一个循环引用,如果试图将任一实例转换为json(或数组),该引用将爆炸。

也就是说,如果$parent->child->parent === $parent,那么存在一个循环引用,并且为它创建json/数组将是一个无限循环。

在这种情况下,如果您想要特别小心,您可以使用withoutRelations()方法将关系分配给父节点的克隆,该克隆不会加载任何关系。

function f(Parent $parent): Child
{
// ...
$child = $parent->createChild();
// ...
$child->setRelation('parent', $parent->withoutRelations());
return $child;
}

在此之后,$parent->is($parent->child->parent)将为真,但$parent->child->parent === $parent将为假,因此没有循环引用。

相关内容

  • 没有找到相关文章

最新更新