我有模特:
use seoTrait;
protected $fillable = [
'name', 'title', 'description'
];
我在$ fillable中创建了需要“seoMeta”的特质“seoTrait”。
现在我补充说:
protected $fillable = [
'name', 'title', 'description', 'seoMeta'
];
但是有可能在特质“seoTrait”中添加一些东西给$ fillable吗?
我有同样的要求。但是,我不想在我的特征中声明一个构造函数,因为这会导致非常意外的行为 - 如果另一个特征也声明了构造函数呢?
正如PeterPan666所指出的,我们不能使用静态特性boot()
方法直接设置非静态fillable
属性 - 但我们可以使用Laravel Model Events,它接收模型的一个实例。
例如:
public static function bootSeoTrait() : void
{
static::retrieved(function($model) {
$model->fillable = array_merge($model->fillable, ['seoMeta']);
});
}
更新
虽然$fillable
属性受到保护,但是GuardsAttributes
使用的Illuminate\Database\Eloquent\Model
特征包含以下setter:
/**
* Set the fillable attributes for the model.
*
* @param array $fillable
* @return $this
*/
public function fillable(array $fillable)
{
$this->fillable = $fillable;
return $this;
}
因此,我们可以在$fillable
事件中从我们的模型实例设置retrieved
protected属性。
对于任何来这里寻找答案的人;我相信有一种比构造函数重载更好的方法。
其他人指出Laravel支持可启动模型特征,使用boot<TraitName>
方法可以设置特征用于使用。但是,boot<TraitName>
方法必须是静态的,因此您无法更改模型的任何非静态属性。
但是,我发现有一个非静态等价于boot<TraitName>
方法; initialize<TraitName>
方法。
在内部,当Eloquent启动模型时,它还会根据模型使用的特征中找到的方法注册模型的所有初始化方法。然后在实例化该模型时,将触发initialize方法。
基于此问题中陈述的问题的使用示例:
trait SEOTrait
{
/**
* This method is called upon instantiation of the Eloquent Model.
* It adds the "seoMeta" field to the "$fillable" array of the model.
*
* @return void
*/
public function initializeSEOTrait()
{
$this->fillable[] = 'seoMeta';
}
}
遗憾的是,官方文档中没有关于可引导或可初始化特征的任何信息。但是,我仍然觉得两种功能都存在很酷。
您可以在特征中使用构造函数,但将可填充属性发送到父构造函数Illuminate \ Database \ Eloquent \ Modal非常重要。
parent::__construct($attributes);
这是示例代码:
public function __construct(array $attributes = []) {
parent::__construct($attributes);
$this->fillable[] = 'seoMeta';
}
正如@DokiCRO所说,你可以在你的特质中实现一个构造函数。然后,您必须考虑不会有任何其他特征能够覆盖该构造。
除此之外,我建议使用静态bootTraitClassName()。但在这种特定情况下,我们需要覆盖非静态受保护属性,这在静态上下文中是无法实现的。
所以这证明构造函数重载是正确的。也许使用一个特性负责为所有模型重载$ fillable数组,从长远来看,这将使您的生活更轻松。
只需确保在调用父结构之前包含代码。
public function __construct(array $attributes = []) {
$this->fillable[] = 'seoMeta';
parent::__construct($attributes);
}