Laravel eloquent 播种期间无人看管
Laravel eloquent unguarded during seeding
我在使用 eloquent 时遇到了一个奇怪的问题。
我有两个 eloquent 模型,一个用户模型和一个配置文件模型,它们都有单独的表并且具有一对一的关系。
我有一个表单,其中传递了这两个模型的数据。因此属于 User 和 Profile 的数据出现在表单中。
我尝试从控制器尽可能干净地执行插入:
$user = $this->users->createUser($request->all());
createUser
函数定义如下
public function createUser(array $data)
{
$user = new User($data);
// set some non relevant user options here...
$user->save();
$profile = new Profile($data);
$user->profile()->save($profile);
return $user;
}
但这会产生 sql 错误,因为 eloquent 将表单中的所有值分配给两个模型,因此 User 和 Profile 都获得所有相同的属性,所以 eloquent尝试插入给定模型不存在的列。
我以为 $fillable
字段是用来防止这种事情发生的,但我确实在两个模型中都定义了 $fillable
字段:
// User
protected $fillable = ['email', 'password', ...];
// Profile
protected $fillable = ['first_name', 'last_name', ...];
我也试过这个:(new User)->fill($data)
但这不起作用,也不应该,因为 fill
方法也是从 Model
构造函数调用的。
在我看来,这不是预期的行为,但话又说回来,我可能误解了可填充的概念。任何见解将不胜感激。我知道这可以通过声明我想发送给构造函数的每个键来解决,但这对我来说似乎很混乱。另外,我正在使用 laravel v5.2.29
编辑
经过进一步测试,我得出的结论是,这只会在我 运行 数据库播种器内部发生,我确实在其中使用了这些函数。深入挖掘,我发现这是完全合理的,因为 运行 将种子命令 "unguards" 设置为基本模型 class。所以这是预期的行为。
我的问题是,有什么方法可以覆盖此默认值,以便在 运行 执行种子命令时模型不会得到 "unguarded",这样我就可以使用我的辅助函数填充我的测试数据库,还是我必须在播种机中手动正确定义每个数据记录 classes?
是的,从 Laravel 5.2 的某些版本开始,当使用播种模型时,正如您所注意到的那样无人看管。其实不设防也是很合理的,但如果你想改,也可以,但没那么简单。
以下是您应该执行的步骤:
在 config/app.php
行 Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class
中添加注释,添加自定义行 ConsoleSupportServiceProvider
class.
创建与原始 ConsoleSupportServiceProvider
相同的 class(实际上您可以扩展它)但在 $providers
属性 中更改 Illuminate\Database\SeedServiceProvider
进入自定义
再次创建扩展原始 SeedServiceProvider
的自定义 SeedServiceProvider
,现在覆盖 registerSeedCommand
以再次创建自定义 SeedCommand
class
创建扩展原始 SeedCommand
的自定义 SeedCommand
class,现在您只需要更改:
public function fire()
{
if (! $this->confirmToProceed()) {
return;
}
$this->resolver->setDefaultConnection($this->getDatabase());
Model::unguarded(function () {
$this->getSeeder()->run();
});
}
进入
public function fire()
{
if (! $this->confirmToProceed()) {
return;
}
$this->resolver->setDefaultConnection($this->getDatabase());
$this->getSeeder()->run();
}
我在使用 eloquent 时遇到了一个奇怪的问题。
我有两个 eloquent 模型,一个用户模型和一个配置文件模型,它们都有单独的表并且具有一对一的关系。
我有一个表单,其中传递了这两个模型的数据。因此属于 User 和 Profile 的数据出现在表单中。
我尝试从控制器尽可能干净地执行插入:
$user = $this->users->createUser($request->all());
createUser
函数定义如下
public function createUser(array $data)
{
$user = new User($data);
// set some non relevant user options here...
$user->save();
$profile = new Profile($data);
$user->profile()->save($profile);
return $user;
}
但这会产生 sql 错误,因为 eloquent 将表单中的所有值分配给两个模型,因此 User 和 Profile 都获得所有相同的属性,所以 eloquent尝试插入给定模型不存在的列。
我以为 $fillable
字段是用来防止这种事情发生的,但我确实在两个模型中都定义了 $fillable
字段:
// User
protected $fillable = ['email', 'password', ...];
// Profile
protected $fillable = ['first_name', 'last_name', ...];
我也试过这个:(new User)->fill($data)
但这不起作用,也不应该,因为 fill
方法也是从 Model
构造函数调用的。
在我看来,这不是预期的行为,但话又说回来,我可能误解了可填充的概念。任何见解将不胜感激。我知道这可以通过声明我想发送给构造函数的每个键来解决,但这对我来说似乎很混乱。另外,我正在使用 laravel v5.2.29
编辑
经过进一步测试,我得出的结论是,这只会在我 运行 数据库播种器内部发生,我确实在其中使用了这些函数。深入挖掘,我发现这是完全合理的,因为 运行 将种子命令 "unguards" 设置为基本模型 class。所以这是预期的行为。
我的问题是,有什么方法可以覆盖此默认值,以便在 运行 执行种子命令时模型不会得到 "unguarded",这样我就可以使用我的辅助函数填充我的测试数据库,还是我必须在播种机中手动正确定义每个数据记录 classes?
是的,从 Laravel 5.2 的某些版本开始,当使用播种模型时,正如您所注意到的那样无人看管。其实不设防也是很合理的,但如果你想改,也可以,但没那么简单。
以下是您应该执行的步骤:
在
config/app.php
行Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class
中添加注释,添加自定义行ConsoleSupportServiceProvider
class.创建与原始
ConsoleSupportServiceProvider
相同的 class(实际上您可以扩展它)但在$providers
属性 中更改Illuminate\Database\SeedServiceProvider
进入自定义再次创建扩展原始
SeedServiceProvider
的自定义SeedServiceProvider
,现在覆盖registerSeedCommand
以再次创建自定义SeedCommand
class创建扩展原始
SeedCommand
的自定义SeedCommand
class,现在您只需要更改:public function fire() { if (! $this->confirmToProceed()) { return; } $this->resolver->setDefaultConnection($this->getDatabase()); Model::unguarded(function () { $this->getSeeder()->run(); }); }
进入
public function fire() { if (! $this->confirmToProceed()) { return; } $this->resolver->setDefaultConnection($this->getDatabase()); $this->getSeeder()->run(); }