【问题标题】:Using PHP Faker in Laravel to generate "unique with" entry when seeding a database using a factory在使用工厂为数据库播种时使用 Laravel 中的 PHP Faker 生成“唯一的”条目
【发布时间】:2018-11-11 03:12:27
【问题描述】:

所以类似于唯一性验证规则(参见:https://github.com/felixkiss/uniquewith-validator),我想知道如何生成一个条目,其中一列与另一列是唯一的。我想按如下方式播种我的数据库。

例子:

“步骤”表中有 12 个步骤。每个步骤应该有 5 个类别,每个类别都存储在“step_categories”表中。这些类别中的每一个都分配有一个唯一的订单号 1 到 5,每个“step_id”都是唯一的。

请在此处查看此图片,了解数据库的外观示例:https://imgur.com/a/XYA5yyn

我必须手动为上述图像示例在数据库中创建条目。我不想每次都手动生成这个,比如说我犯了一个错误并且不得不回滚迁移。

我正在使用工厂来生成这些数据。所以工厂名称是StepCategoriesFactory.php,显然我正在使用DatabaseSeeder.php 文件中的create() 方法调用工厂。

我曾想过在 for 循环中执行此操作,然后我意识到当我调用 'step_id' => App\Model::all()->random()->id 来获取一个新的 id 时,我无法确保我没有获取那个 id我刚刚生成了 5 个条目。我对 Laravel 真的很陌生,我什至不知道从哪里开始。没有关于 SO 的真实信息,faker 可以将唯一性与另一列一起使用。我该怎么办?

注意:步骤 id 并不总是 1-12。步骤 ID 可能会有所不同,具体取决于步骤是否被删除和重新制作。因此,仅将 step_id 分配为等于 1-12 是行不通的。

更新:这是我刚刚编写的一些代码,我认为我在正确的轨道上。可能是。我已经通过它的number 字段抓取了step_id,因为它始终是1-12,并且我已经从条目中抓取了IID。但现在我被困在如何生成订单 1-5 而不会重复。我还没有运行它,因为它不完整,我知道如果没有正确的订单号它会抛出错误。

更新 2:我认为我在正确的轨道上。但是我收到一个未定义的变量错误。当我从匿名函数中放入第一行时,它会将每个条目的顺序重置为“1”。如何使 $autoIncrement 变量可用于匿名函数?播种机在更新之间保持不变。

错误图片:https://imgur.com/a/ywkd0Lb 终端中出现 Die/Dump 错误的第二张图片:https://imgur.com/a/rOGRv32

在此处参考这篇文章:https://laracasts.com/discuss/channels/laravel/model-factory-increment-value-faker?page=1

更新 3: 我忘记了匿名函数的 use ($autoIncrement) 代码行。下面的代码已更新,但现在我收到一个不同的错误,指出订单列具有空值并且无法插入。显然它应该是'1'。即使在我调用我的$autoIncrement->next(); 之后,它应该将它增加到'1',它仍然根据终端返回 null。但是,当我在 $autoIncrement->current() 上执行 dieump 时,它返回 1. Weird。

更新 3 错误:https://imgur.com/a/STOmIjF

StepCategoriesFactory.php

use Faker\Generator as Faker;

$autoIncrement = autoIncrement();

$factory->define(App\StepCategory::class, function (Faker $faker) use ($autoIncrement) {
    // Generate Created At and Updated at DATETIME
    $DateTime = $faker->dateTime($max = 'now');
    $autoIncrement->next();
    $order = (int) $autoIncrement->current();

    return [
        // Generate Dummy Data
        'order' =>  $order,
        'name' => $faker->words(4, true),
        'created_at' => $DateTime,
        'updated_at' => $DateTime,
    ];
});

function autoIncrement()
{
    for ($i = 0; $i < 5; $i++) {
        yield $i;
    }
}

编辑:悬赏这个问题,因为我认为这将有助于社区获得详细的答案。我正在寻求帮助来解释如何确保我在每个循环中抓取相同的条目。

【问题讨论】:

  • 只需在播种机中循环foreach(range(1, 12) as $i)
  • 你能给出一些代码示例并实际将其放入答案中吗?

标签: php laravel faker laravel-seeding factories


【解决方案1】:

终于解决了!

所以我听取了每个人的答案,并苦苦思索了如何使用 for 循环来创建订单号。 1-5。我最后遇到的问题是 $i 变量没有重置。所以在收益率之后,我必须检查 $i 变量是否等于 5,然后将其重置为零。

这是代码!

StepCategories.php

use Faker\Generator as Faker;

$autoIncrement = autoIncrement();

$factory->define(App\StepCategory::class, function (Faker $faker) use ($autoIncrement) {
    // Generate Created At and Updated at DATETIME
    $DateTime = $faker->dateTime($max = 'now');

    // Get the next iteration of the autoIncrement Function
    $autoIncrement->next();
    // Assign the current $i value to a typecast variable.
    $order = (int) $autoIncrement->current();


    return [
        // Generate Dummy Data
        'order' =>  $order,
        'name' => $faker->words(4, true),
        'created_at' => $DateTime,
        'updated_at' => $DateTime,
    ];
});

function autoIncrement()
{
    // Start a loop
    for ($i = 0; $i <= 5; $i++) {
        // Yield the current value of $i
        yield $i;
        // If $i is equal to 5, that must mean the start of a new loop
        if($i == 5) {
            // Reset $i to 0 to start over.
            $i = 0;
        }
    }
}

DatabaseSeeder.php

// Generate Dummy Categories
// Run the factory 12 times
foreach(range(1, 12) as $i) {
    // Generate 5 entries each time
    factory(App\StepCategory::class, 5)->create([
        // Since all steps have a number 1-12 grab the step by the number column and get it's ID
        'step_id' => App\Step::where('number', '=', $i)->first()->id,
    ]);
}

感谢所有帮助过的人!

【讨论】:

    【解决方案2】:

    对不起,如果你不明白我的意思,我会尝试用代码解释它

        use Illuminate\Database\Seeder;
    
    
    $factory->define(App\StepCategory::class, function (Faker $faker) {
        // Generate Created At and Updated at DATETIME
        $DateTime = $faker->dateTime($max = 'now');
        $step_id = function () {
                return factory('App\Step')->create()->id;
            };
    
        return [
            // Generate Dummy Data
           'step_id' => $step_id,
            'order' => uniqueOrder($step_id),
            'name' => $faker->words(4, true),
            'created_at' => $DateTime,
            'updated_at' => $DateTime,
        ];
    });
    
    function uniqueOrder($step_id)
    {
        $unique = rand(1,5);
        do {
           $unique = rand(1,5);
         }
         while(StepCategory::where('step_id', $step_id)->andWhere( 'order', $unique)->exists())
    
      return $unique;
    
    }
    

    【讨论】:

    • 我已经建立了我的 hasMany 关系。所以这部分很好。但是,我对您的代码感到困惑,因为我没有名为 title、close 等的列。我也对 rand 函数的工作原理感到困惑。它是独一无二的吗?我不能有重复的值。 $categoryIndex 变量在哪里使用,如果不使用,为什么必须在 for 循环中定义它?
    • 我还在为这些步骤创建一个类别。不是步骤本身。我已经把工厂设置好了。仅供参考。 Step Model 也有一个称为“category”的 hasMany 关系。
    • 忽略它对 foreach 循环很重要
    • 只关注while -> 做代码我认为这是你在找什么?但定义它更多我没有你的桌子,所以我不知道真的
    • 我使用的表是stepsstep_categories。我认为我的代码在我的问题中工作,但是它只是没有“重置”计数器并在它增加到“4”之后将 0 放入所有订单中。可以在此处找到每个屏幕截图:imgur.com/a/qv5idfG 以及我运行 db:seed 命令后的表格屏幕截图:imgur.com/a/PMFOyxR
    【解决方案3】:

    例如,如果您的 Step 模型名称是 Steps:

    $allSteps = Steps::all();
    foreach($allSteps as $step){
       for($i=1;$i<6;$i++){
         //insert to table $step->id , $i  for example 
         DB::table('yourTableName')->insert([
               'name'=>'Step '.$step->id.'- Category '.$i , 
               'order'=>$i , 
              'step_id'=>$step->id
         ]);
        }
    }
    

    【讨论】:

    • 我想我已经使用我创建的 autoIncrement 函数解决了这个问题。但是,在运行 db:seed 命令时,我收到未定义的变量错误。一秒更新以上内容。
    • 不是说什么变量吗?
    猜你喜欢
    • 2017-08-29
    • 1970-01-01
    • 2021-06-11
    • 2018-09-03
    • 2017-02-10
    • 2023-03-03
    • 2020-01-17
    • 2016-09-16
    • 2017-03-22
    相关资源
    最近更新 更多