Laravel在播种期间雄辩无人看守

时间:2016-04-09 14:23:19

标签: php laravel orm eloquent artisan

我正在经历一个滔滔不绝的奇怪问题。

我有两个雄辩的模型,一个用户模型和一个配置文件模型,它们都有单独的表并且具有一对一的关系。

我有一个表单,其中传递了这两个模型的数据。因此,属于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”基础Model类。所以这是预期的行为。

我的问题是,是否有任何方法可以覆盖此默认值,以便模型在运行种子命令时不会“无人看守”,这样我就可以使用我的帮助函数来填充我的测试数据库,或者我是必须在播种机类内手动正确定义每个数据记录吗?

1 个答案:

答案 0 :(得分:3)

是的,从某些版本的Laravel 5.2中使用播种模型时,您会注意到无人看守。事实上它没有防备是非常合理的,但是如果你想要改变它,那么它是可能的,但不是那么简单。

以下是您应该采取的步骤:

  1. config/app.phpIlluminate\Foundation\Providers\ConsoleSupportServiceProvider::class中发表评论时,请在自定义ConsoleSupportServiceProvider课程中添加添加行。

  2. 创建此类与原始ConsoleSupportServiceProvider相同(实际上您可以扩展它),但在$providers属性更改Illuminate\Database\SeedServiceProvider中自定义

  3. 再次创建扩展原始SeedServiceProvider的自定义SeedServiceProvider,现在覆盖registerSeedCommand以再次创建自定义SeedCommand

  4. 创建扩展原始SeedCommand的自定义SeedCommand类,现在您只需要更改:

    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();
    
    }