【发布时间】:2017-08-29 09:32:06
【问题描述】:
简介
伙计们,我有一个关于模型工厂和多个独特列的问题:
背景
我有一个名为 Image 的模型。此模型具有存储在单独模型 ImageText 中的语言支持。 ImageText 有一个 image_id 列、一个语言列和一个文本列。
ImageText 在 MySQL 中有一个约束,即 image_id 和语言的组合必须是唯一的。
class CreateImageTextsTable extends Migration
{
public function up()
{
Schema::create('image_texts', function ($table) {
...
$table->unique(['image_id', 'language']);
...
});
}
...
现在,我希望每个 Image 在播种完成后都有几个 ImageText 模型。使用模型工厂和这个播种机很容易:
factory(App\Models\Image::class, 100)->create()->each(function ($image) {
$max = rand(0, 10);
for ($i = 0; $i < $max; $i++) {
$image->imageTexts()->save(factory(App\Models\ImageText::class)->create());
}
});
问题
但是,当使用模型工厂和 faker 播种时,您通常会收到以下消息:
[PDOException]
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '76-gn' for key 'image_texts_image_id_language_unique'
这是因为在某个时候,在 for 循环内,faker 会为一张图像随机两次使用相同的 languageCode,从而打破 ['image_id', 'language'] 的唯一约束。
您可以更新您的 ImageTextFactory 来说明:
$factory->define(App\Models\ImageText::class, function (Faker\Generator $faker) {
return [
'language' => $faker->unique()->languageCode,
'title' => $faker->word,
'text' => $faker->text,
];
});
但是,你会得到一个问题,即在创建了足够的 imageTexts 后,faker 将用完 languageCodes。
当前解决方案
目前通过为 ImageText 设置两个不同的工厂来解决这个问题,其中一个为 languageCodes 重置唯一计数器,播种器调用工厂在进入 for 循环之前重置唯一计数器以创建更多 ImageText。但这是代码重复,应该有更好的方法来解决这个问题。
问题
有没有办法将您保存的模型发送到工厂?如果是这样,我可以在工厂内部检查一下当前图像是否已经附加了任何 ImageTexts,如果没有,则重置语言代码的唯一计数器。我的目标是这样的:
$factory->define(App\Models\ImageText::class, function (Faker\Generator $faker) {
$firstImageText = empty($image->imageTexts());
return [
'language' => $faker->unique($firstImageText)->languageCode,
'title' => $faker->word,
'text' => $faker->text,
];
});
当然目前提供:
[ErrorException]
Undefined variable: image
有没有可能以某种方式实现这一目标?
【问题讨论】:
标签: php mysql laravel laravel-5.4 laravel-seeding