Laravel雄辩地“继承”了父项的字段

时间:2019-08-19 19:05:02

标签: laravel eloquent relationship

在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'

在某处必须有一种模式,使一个表行的值“压倒”另一个表行的值,我似乎无法找到要搜索的内容。

1 个答案:

答案 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;
            }
        }
    }
}