我正在使用 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 字段?!
我不明白为什么HasManyOrOne关系故意忽略fillable。这看起来确实违反直觉。不管怎样,我认为这应该对你有用。
$user->contacts()->save(Contact::create([ ... ]));
看来我找到了这种行为的原因。这是在 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;
}
...
}
我仍在寻找足够的解决方案来控制这种行为。
如官方文档所述:
首先,在模型上设置可填充 或 受保护的属性。
您已设置两者。您应该删除以下行:
protected $guarded = ['*'];
幸运的是,这将在 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);
}
}
使用
protected $guarded = array();
代替 protected $guarded = ['*'];
通过使用
[*]
,你告诉 laravel 保护所有实体免受自动水化/质量分配!
array()
将此 $guarded
列表设置为空。
可填充属性指定哪些属性应该是可批量分配的。这可以在类或实例级别设置。
可填充的逆是受保护的,并充当“黑名单”而不是“白名单”:
阅读更多内容Laravel 关于批量分配的文档
更新方法不在模型级别,并且不会尊重 $fillable 字段。
您可以使用 Input::only['fillable fields here'] 过滤输入数据