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

时间:2013-11-19 10:05:34

标签: laravel-4 eloquent ardent

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

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字段的任何想法?!

6 个答案:

答案 0 :(得分:3)

我不明白为什么HasManyOrOne关系故意忽略可填写。这看起来非常直观。无论哪种方式,我认为这应该适合你。

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

答案 1 :(得分: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;
    }

    ...
}

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

答案 2 :(得分:0)

正如官方文件中所述:

  

要开始使用,请在模型上设置可填写的 防护属性。

你已经设置了两个。您应该删除以下行:protected $guarded = ['*'];

答案 3 :(得分: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);
    }
}

答案 4 :(得分:0)

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

使用[*]你告诉laravel防止所有实体进行自动水合/质量分配!

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

  

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

     

可填写的反面被保护,并作为“黑名单”而不是“白名单”:

Laravel documentation on mass assignment

了解详情

答案 5 :(得分:0)

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

您可以使用Input :: only ['此处可填写字段']

来过滤输入数据