I often have two models in a 1:x relationship:
class Child extends Model
{
public function parent()
{
return $this->belongsTo(Parent::class);
}
}
Now there are times when I already have an instance of one of the related models within a function:
function f(Parent $parent): Child
{
// ...
$child = $parent->createChild();
// ...
return $child
}
A different function takes Child as a parameter and requires an attribute of the Parent class:
function g(Child $child)
{
$child->update([
'attribute' => h($child->parent->attribute)
]);
}
Now if g is called with the Child instance returned from f, then the Parent instance will be retrieved from the DB twice. Unless we add a Parent parameter and pass in the instance to g, or alternatively modify f as follows:
function f(Parent $parent): Child
{
// ...
$child = $parent->createChild();
// ...
$child->parent = $parent;
return $child
}
I prefer this second approach to adding another parameter because the context from which g is called might not have access to the Parent instance. And it often works fine. However, it fails on the update statement in g:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'parent' in 'field list' (SQL: update `children`...
So my question is:
Calling
$child->parent = $parentattempts to set aparentfield attribute on the$childobject. However, you want to set theparentrelationship attribute. In order to do this, you need to use thesetRelation()method:At this point, however, you will want to be careful that you're not creating a circular reference. If the
$parent->childrelationship is set to the$childinstance, and then you set the$child->parentrelationship to the$parentinstance, you've created a circular reference that will blow up if you attempt to convert either instance to json (or an array).That is, if
$parent->child->parent === $parent, then a circular reference exists, and creating the json/array for that will be an infinite loop.In this case, if you want to be extra careful, you can use the
withoutRelations()method to assign the relationship to a clone of the parent, which will not have any relationships loaded.After this, then
$parent->is($parent->child->parent)will be true, but$parent->child->parent === $parentwill be false, so no circular reference.