0

我有两个正在尝试为其编写工厂的模态。LineItems 和发票。问题是它们是基于彼此动态的。

Table: line_items
id | amount | invoice
1  | 15     | 1 
2  | 10     | 1 
3  | 15     | 2
4  | 5      | null

Table: invoices
id | total
1  | 25   
2  | 15   

LineItems 知道它们被分配到哪个 Invoice,Invoices 保存分配给它们的 LineItems 的总值。

LineItems 看起来像这样:

$factory->define(\App\Models\LineItems::class, function (Faker $faker) {
  return [
    'amount' => $faker->numberBetween(1, 15),
    'invoice' => null
  ];
});

然后为 Invoices 建立一个工厂,我需要汇总 LineItems 的金额,没什么大不了的,我可以在工厂内部创建 LineItems 并总计:

$factory->define(\App\Models\Invoice::class, function (Faker $faker) {
  $total = 0;

  $line_items = $factory(\App\Models\LineItems::class, 3);

  foreach($line_items as $l) {
    $total += $l->amount;
  }

  return [
    'total' => $total
  ];
});

但现在的问题是,如何将 Invoiceid编号保存回刚刚创建的 LineItems?显然,在工厂被保存之前,我没有id,也就是在 Closure 回调完成之后。我无法将 LineItems 从 Closure 中退回,因为工厂需要使用退货,因此它实际上可以保存 Invoice。

我知道这似乎是一个 X/Y 问题。但是我已经在 SO 上查看了一些类似的问题,我不喜欢这些变通方法,因为它们非常脆弱,依赖于不明显的操作顺序或某些数据在你可以运行之前已经存在一个工厂。我宁愿找到使用工厂的解决方案,并尽可能将所有问题都保留在本地。

另外,如果有解决方案,这意味着工厂可以自我维持,这对所有相关人员来说都更好。但如果这是不可能的,那将是一个可以接受的答案,因为它允许我寻求其他(尽管更脆弱)保存测试数据的方法。

4

1 回答 1

1

方法 1 - 使用种子

一、LineItems工厂设置一些随机发票

$factory->define(\App\Models\LineItems::class, function (Faker $faker) {
    return [
        'amount' => $faker->numberBetween(1, 15),
        'invoice' => function () {
             return factory(\App\Models\Invoice::class)->create()->id;
        },
    ];
});

然后创建一个没有依赖关系的 Invoice

$factory->define(\App\Models\Invoice::class, function (Faker $faker) {
    return [
        'total' => 0
    ];
});

然后你创建一个种子来填充你想要的方式

class InvoiceSeederClass extends Seeder
{
    public function run()
    {
        $invoice = factory(App\Models\Invoice::class)->create();

        $lineItems = factory(App\Models\LineItems::class, 3)->create([
            'invoice' => $invoice->id,
        ]);

        $total = 0;
        foreach($lineItems as $item) {
            $total += $item->amount;
        }

        $invoice->amount = $total;
        $invoice->save();
    }
}

$seeder = new InvoiceSeederClass();
$seeder->run();

现在工厂的逻辑是隔离的,你可以用自己的业务逻辑来创建。


方法 2 - 使用虚拟工厂

创建 LineItems 工厂

$factory->define(\App\Models\LineItems::class, function (Faker $faker) {
    return [
        'amount' => $faker->numberBetween(1, 15),
        'invoice' => function () {
             return factory(\App\Models\Invoice::class)->create()->id;
        },
    ];
});

创建发票工厂

$factory->define(\App\Models\Invoice::class, function (Faker $faker) {
    return [
        'total' => 0
    ];
});

创建虚拟工厂

$factory->define(\App\Models\DummyFactory::class, function () use($faker) {
    $invoice = factory(App\Models\Invoice::class)->create();

    $lineItems = factory(App\Models\LineItems::class, 3)->create([
        'invoice' => $invoice->id,
    ]);

    $total = 0;
    foreach($lineItems as $item) {
        $total += $item->amount;
    }

    $invoice->amount = $total;
    $invoice->save();

    return []; // you can return any array you want, ex. $invoice
});

用法。重要提示:使用 MAKE 而不是 CREATE:

$invoiceWithItems = factory(App\Models\DummyFactory::class)->make();

现在你的逻辑在工厂里

于 2018-08-16T18:05:19.637 回答