在Eloquent中,有没有一种方法可以使模型具有某种父模型,而这两种模型都有相同的字段,并且在子对象上可以为null。如果我得到的值为$child->field
,如果不是null
,则得到子级的值,否则我得到父级的值?像这样:
$parent = new Parent();
$parent->info = 'parent';
$parent->save();
$child = new Child();
$child->info = 'child';
$child->parent()->associate($parent);
$child->save();
echo $child->info
Prints 'child'
相反:
$parent = new Parent();
$parent->info = 'parent';
$parent->save();
$child = new Child();
$child->parent()->associate($parent);
$child->info = null;
$child->save();
echo $child->info
Prints 'parent'
在某处必须有一种模式,使一个表行的值“压倒”另一个表行的值,我似乎无法找到要搜索的内容。
答案 0 :(得分:1)
您只需要在所选模型上使用自定义访问器即可:
class Child
{
public function getInfoAttribute($value)
{
if ($value === null) {
return $this->parent->info;
}
return $value;
}
}
这将使您仍然可以通过$child->info
访问该属性。
请注意,这不会根据$casts
数组强制转换属性值。如果还需要这种转换逻辑,则应使用自定义的getter方法而不是魔术访问器:
class Child
{
public function getInfo()
{
$info = $this->info;
if ($info === null) {
$info = $this->parent->info;
}
return $info;
}
}
如果需要多个属性,则可以复制代码并将其放入特征以从模型中消除混乱。或者,您可以尝试改写神奇的__get($key)
方法:
class Child
{
$parentInheritedAttributes = ['info', 'description'];
// solution 1: using normal model properties like $child->info
public function __get($key)
{
if (in_array($key, $this->parentInheritedAttributes)) {
$value = parent::__get($key);
if ($value === null) {
// this will implicitely use __get($key) of parent
$value = $this->parent->$key;
}
return $value;
}
return parent::__get($key);
}
// solution 2: using getters like $child->getInfo()
public function __call($method, $parameters)
{
if (\Illuminate\Support\Str::startsWith($method, 'get')) {
$attribute = \Illuminate\Support\Str::snake(lcfirst(substr($method, 3)));
in_array($attribute, $this->parentInheritedAttributes)) {
$value = $this->$attribute;
if ($value === null) {
$value = $this->parent->$attribute;
}
return $value;
}
}
}
}