插入相关模型时忽略可填充列表

问题描述 投票:0回答:6

我正在使用 Ardent,在插入/更新相关模型时遇到了忽略 $fillable 列表的奇怪行为。 我定义了以下模型:

class User extends LaravelBook\Ardent\Ardent
{
    protected $table = 'users';

    public static $relationsData = [
        'contacts' => [self::HAS_MANY, 'Contact'],
    ];    
}

class Contact extends LaravelBook\Ardent\Ardent 
{
    protected $table    = 'user_contacts';
    protected $guarded  = ['*'];
    protected $fillable = [
        'user_id',
        'type',
        'value'
    ];

    public static $relationsData = [
         'user' => [self::BELONGS_TO, 'User'],
    ];
}

现在我正在尝试向用户添加新联系人:

    $user->contacts()->create([
    'type' => 'some type',
    'value' => 'some value',
    'unknown_field' => 'unknown value'
]);

...我收到 SQL 插入错误:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'unknown_field' in 'field list'     (SQL: insert into `user_contacts` (`type`, `value`, `unknown_field`, `user_id`, `updated_at`, `created_at`) values (?, ?, ?, ?, ?, ?)) (Bindings: array ( 0 => 'some type', 1 => 'some value', 2 => 'unknown value', 3 => 2, 4 => '1384854899', 5 => '1384854899', ))

同时,这工作正常:

UserContact::create([
    'user_id'       => 2,
    'type'          => 'some type',
    'value'         => 'some value',
    'unknown_field' => 'unknown value'
]); 

我没有收到任何 SQL 错误,只是忽略了“unknown_field”。

有什么想法为什么在通过构建器工作时可以忽略 $fillable 字段?!

php eloquent laravel-4 ardent
6个回答
3
投票

我不明白为什么HasManyOrOne关系故意忽略fillable。这看起来确实违反直觉。不管怎样,我认为这应该对你有用。

$user->contacts()->save(Contact::create([ ... ]));

1
投票

看来我找到了这种行为的原因。这是在 HasOneOrMany 抽象类中显式实现的。

abstract class HasOneOrMany extends Relation {

    ...

    /**
     * Create a new instance of the related model.
     *
     * @param  array  $attributes
     * @return \Illuminate\Database\Eloquent\Model
     */
    public function create(array $attributes)
    {
        $foreign = array(
            $this->getPlainForeignKey() => $this->parent->getKey()
        );

        // Here we will set the raw attributes to avoid hitting the "fill" method so
        // that we do not have to worry about a mass accessor rules blocking sets
        // on the models. Otherwise, some of these attributes will not get set.
        $instance = $this->related->newInstance();

        $instance->setRawAttributes(array_merge($attributes, $foreign));

        $instance->save();

        return $instance;
    }

    ...
}

我仍在寻找足够的解决方案来控制这种行为。


0
投票

如官方文档所述:

首先,在模型上设置可填充 受保护的属性。

您已设置两者。您应该删除以下行:

protected $guarded  = ['*'];


0
投票

幸运的是,这将在 4.2 版本中得到修复:https://github.com/laravel/framework/pull/2846

除此之外,您还可以手动过滤属性:

$input = [
    'user_id'       => 2,
    'type'          => 'some type',
    'value'         => 'some value',
    'unknown_field' => 'unknown value'
];

$fillable = $user->contacts()->getRelated()->fillableFromArray($input);

$user->contacts()->create($fillable);

请记住,该示例使用的是受保护的

Eloquent\Model\fillableFromArray()
方法,因此有必要,例如,复制它:

class BaseModel extends Eloquent 
{
    public function fillableFromArray(array $attributes)
    {
        return parent::fillableFromArray($attributes);
    }
}

0
投票

使用

protected $guarded  = array();
代替
protected $guarded  = ['*'];

通过使用

[*]
,你告诉 laravel 保护所有实体免受自动水化/质量分配!

array()
将此
$guarded
列表设置为空。

可填充属性指定哪些属性应该是可批量分配的。这可以在类或实例级别设置。

可填充的逆是受保护的,并充当“黑名单”而不是“白名单”:

阅读更多内容Laravel 关于批量分配的文档


0
投票

更新方法不在模型级别,并且不会尊重 $fillable 字段。

您可以使用 Input::only['fillable fields here'] 过滤输入数据

© www.soinside.com 2019 - 2024. All rights reserved.