我有模特:
use seoTrait;
protected $fillable = [
'name', 'title', 'description'
];
我创造了特质" seoTrait"需要" seoMeta"在$ fillable。
现在我添加:
protected $fillable = [
'name', 'title', 'description', 'seoMeta'
];
但它是否有可能在特质" seoTrait"添加一些东西到$ fillable?
答案 0 :(得分:6)
我有同样的要求。但是,我不想在我的特征中声明一个构造函数,因为这会导致非常意外的行为 - 如果另一个特征也声明了构造函数会怎么样?
正如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
特征包含以下设置器:
/**
* Set the fillable attributes for the model.
*
* @param array $fillable
* @return $this
*/
public function fillable(array $fillable)
{
$this->fillable = $fillable;
return $this;
}
因此,我们可以在$fillable
事件中为我们的模型实例设置retrieved
受保护的属性。
答案 1 :(得分:3)
对于任何来这里寻找答案的人;我相信有比构造函数重载更好的方法。
其他人指出,Laravel支持可启动模型特征,使用boot<TraitName>
方法可以设置特征以供使用。但是,boot<TraitName>
方法必须是静态的,因此您不能更改模型的任何非静态属性。
但是,我发现有一个与boot<TraitName>
方法等效的非静态方法; initialize<TraitName>
方法。
内部,当Eloquent启动模型时,它还会基于模型使用的特征中找到的方法,注册该模型的所有初始化方法。然后,在实例化该模型后,将初始化方法初始化。
基于此问题中所述问题的用法示例:
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';
}
}
可悲的是,官方文档中没有关于可引导或可初始化特征的任何信息。但是,我仍然觉得这两个功能同时存在真的很酷。
答案 2 :(得分:1)
你应该可以像这样使用Traits的启动方法
public static function bootSeoTrait()
{
$this->fillable[] = 'seoMeta';
}
这样,只要您的模型启动,您的Trait的这种方法将被称为ans 'seoMeta'
应添加到$fillable
修改强>
此答案无效,因为bootSeoTrait
是静态方法,$this
将无法使用。
请参阅@DokiCRO回答here
由于此答案已被接受,我无法将其删除。
编辑2
Laravel现在支持initialize*
方法来初始化模型特征。请参阅@OneBigOwnage回答here
答案 3 :(得分:1)
您可以在特征中使用构造函数,但将可填充属性发送到父构造函数Illuminate \ Database \ Eloquent \ Modal
非常重要。 parent::__construct($attributes);
以下是示例代码:
public function __construct(array $attributes = []) {
parent::__construct($attributes);
$this->fillable[] = 'seoMeta';
}
答案 4 :(得分:0)
正如@DokiCRO所说,你可以在你的特质中实现一个构造函数。然后,您必须考虑不会有任何其他特征能够覆盖该构造。
除此之外,我建议使用静态bootTraitClassName()。但在这种特定情况下,我们需要覆盖非静态受保护属性,这在静态上下文中是无法实现的。
所以这证明构造函数重载是正确的。也许使用一个特性负责为所有模型重载$ fillable数组,这将使你的生活更加轻松。
确保在调用父结构之前包含代码。
public function __construct(array $attributes = []) {
$this->fillable[] = 'seoMeta';
parent::__construct($attributes);
}