我正在考虑将我的修改器和访问器更新为 Laravel 9 中引入的新语法,但我似乎无法使其工作。
我目前有一个模型,与充当键值存储的
MorphMany
对象具有 Settings
关系。作为简写,我使用变异器来设置一些更常用的设置。非常简单,看起来像这样:
class Item extends Model
public function setSomeSettingAttribute($value)
{
$key = "some_setting";
Setting::updateOrCreate(
["settable_id" => $this->id, "settable_type" => self::class, "key" => $key],
["value" => $value]
);
}
}
$m = Item::find(1);
// typically in a controller this would be $request->all()
$arr = ["some_setting" => 234];
$m->update($arr);
这工作正常并且设置已更新。需要注意的重要一点是,数据库中没有名为
some_setting
的列。
在新代码中,突变器看起来应该是这样的:
public function someSetting(): Attribute
{
$key = "some_setting";
return Attribute::make(
set: function ($value) use ($key): void {
Setting::updateOrCreate(
["settable_id" => $this->id, "settable_type" => self::class, "key" => $key],
["value" => $value]
);
}
);
}
但这不起作用; Laravel 试图将某些内容插入到
some_setting
列中,导致 SQL“未找到列”错误。
有没有一种方法可以解决这个问题,而不需要编辑我的所有控制器代码来删除假列?或者,如果不是,旧的变元语法是否以任何方式被弃用?
Mutators 与强制类型转换类似,旨在在设置 Eloquent 属性值时对其进行转换。严格来说,写入数据库并不是 mutator 的工作。相反,
Attribute
的 setter 函数的结果会添加到模型的内部 $attributes
数组中。在您的情况下,由于 setter 函数没有返回任何内容,因此 'some_setting'
数组中的 $attributes
键被设置为 null
,导致 Laravel 在执行更新时尝试将 null
写入此列。
也就是说,可以返回属性名称和值的数组,如文档的改变多个属性部分中所述。当您从 setter 返回一个 empty 数组时,Laravel 会将其视为属性数组,并且根本不会向
$attributes
属性添加任何内容。这允许您应用副作用而不改变模型本身的任何属性:
public function someSetting(): Attribute
{
$key = 'some_setting';
return Attribute::make(
set: function ($value) use ($key): void {
Setting::updateOrCreate(
['settable_id' => $this->id, 'settable_type' => self::class, 'key' => $key],
['value' => $value]
);
return [];
}
);
}
通常,当您想要编辑这样的设置时,您需要定义一个
settings
关系(在本例中为 morphToMany)并执行如下更新:
$model->settings()->updateOrCreate(['key' => 'some_setting', 'value' => $value]);