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

问题描述 投票:5回答:5

我有模特:

use seoTrait;

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

我在$ fillable中创建了需要“seoMeta”的特质“seoTrait”。

现在我补充说:

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

但是有可能在特质“seoTrait”中添加一些东西给$ fillable吗?

php laravel laravel-5 laravel-5.1
5个回答
1
投票

你应该可以像这样使用Traits的启动方法

public static function bootSeoTrait()
{
    $this->fillable[] = 'seoMeta';
}

这样,无论何时你的模型启动,你的Trait的这个方法都会被称为ans 'seoMeta'应该添加到$fillable

编辑

这个答案是行不通的,因为bootSeoTrait是一个静态方法,$this将无法使用。

请参阅@DokiCRO答案here

由于这个答案被接受,我无法删除它。

编辑2

Laravel现在支持initialize*方法来初始化模型特征。请参阅@OneBigOwnage回答here


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特征包含以下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属性。


4
投票

对于任何来这里寻找答案的人;我相信有一种比构造函数重载更好的方法。

其他人指出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';
    }
}

遗憾的是,官方文档中没有关于可引导或可初始化特征的任何信息。但是,我仍然觉得两种功能都存在很酷。


1
投票

您可以在特征中使用构造函数,但将可填充属性发送到父构造函数Illuminate \ Database \ Eloquent \ Modal非常重要。

    parent::__construct($attributes);

这是示例代码:

public function __construct(array $attributes = []) {
    parent::__construct($attributes);
    $this->fillable[] = 'seoMeta';
}

0
投票

正如@DokiCRO所说,你可以在你的特质中实现一个构造函数。然后,您必须考虑不会有任何其他特征能够覆盖该构造。

除此之外,我建议使用静态bootTraitClassName()。但在这种特定情况下,我们需要覆盖非静态受保护属性,这在静态上下文中是无法实现的。

所以这证明构造函数重载是正确的。也许使用一个特性负责为所有模型重载$ fillable数组,从长远来看,这将使您的生活更轻松。

只需确保在调用父结构之前包含代码。

public function __construct(array $attributes = []) {
    $this->fillable[] = 'seoMeta';

    parent::__construct($attributes);
}
© www.soinside.com 2019 - 2024. All rights reserved.