LARAVEL如何从特质改变模型中的$ fillable?

时间:2016-02-25 09:16:17

标签: php laravel laravel-5 laravel-5.1

我有模特:

use seoTrait;

protected $fillable = [
    'name', 'title', 'description'
];

我创造了特质" seoTrait"需要" seoMeta"在$ fillable。

现在我添加:

protected $fillable = [
    'name', 'title', 'description', 'seoMeta'
];

但它是否有可能在特质" seoTrait"添加一些东西到$ fillable?

5 个答案:

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