【问题标题】:Laravel eloquent unguarded during seedingLaravel 雄辩在播种期间无人看管
【发布时间】:2016-07-30 19:19:51
【问题描述】:

我在 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

编辑

经过进一步测试,我得出的结论是,这只发生在我运行数据库播种器时,我确实在其中使用了这些功能。深入挖掘,我发现这是完全合理的,因为运行种子命令“解除了”基本模型类。所以这是预期的行为。

我的问题是,有没有办法覆盖这个默认值,以便在运行种子命令时模型不会“不受保护”,这样我就可以使用我的辅助函数来填充我的测试数据库,或者我必须在播种器类中手动正确定义每个数据记录?

【问题讨论】:

  • 你的模型中有构造函数吗?您正在向 User 和 Profile 传递一个数组,确保有一个构造函数来处理它。
  • User 和 Profile 都继承自 Model 基类,我没有重写构造函数。我已经缩小了问题的范围(请参阅我的编辑),但不确定如何以干净的方式解决这个问题。
  • 为什么不去 phpmyadmin 或其他什么地方插入数据呢?
  • 一般来说这违背了播种者的目的。

标签: php laravel orm eloquent laravel-artisan


【解决方案1】:

是的,从 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();
    
    }
    

【讨论】:

  • 感谢您的澄清。在播种过程中数据库应该无人看管是有道理的,所以最后我改变了我的种子。我确实尝试过实现我自己的 Seed 命令,但它不起作用,现在我明白了原因——我没有更改任何服务提供商。感谢您的精彩回答!
猜你喜欢
  • 2020-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-08
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
相关资源
最近更新 更多