解決しました
私はこの問題の解決策をたくさん探しましたが、他の多くの人もそれを経験していることがわかりました。関係のもう一方の端に1つの要素だけが必要な場合は、非常に簡単です 。
「複数列の一意の制限」の追加が、これを複雑にした理由です。私が見つけた唯一の解決策は、「MySQLの制限を忘れて、工場出荷時の作成をPDO例外のtry-catchで囲む」ことでした。他のPDOExceptionもキャッチされるため、これは悪い解決策のように感じられ、「正しい」とは感じられませんでした。
解決策
この作業を行うために、シーダーをImageTableSeederとImageTextTableSeederに分割しましたが、どちらも非常に単純です。それらの実行コマンドは両方とも次のようになります:
public function run()
{
factory(App\Models\ImageText::class, 100)->create();
}
魔法はImageTextFactory内で発生します:
$factory->define(App\Models\ImageText::class, function (Faker\Generator $faker) {
// Pick an image to attach to
$image = App\Models\Image::inRandomOrder()->first();
$image instanceof App\Models\Image ? $imageId = $image->id : $imageId = null;
// Generate unique imageId-languageCode combination
$imageIdAndLanguageCode = $faker->unique()->regexify("/^$imageId-[a-z]{2}");
$languageCode = explode('-', $imageIdAndLanguageCode)[1];
return [
'image_id' => $imageId,
'language' => $languageCode,
'title' => $faker->word,
'text' => $faker->text,
];
});
これです:
$imageIdAndLanguageCode = $faker->unique()->regexify("/^$imageId-[a-z]{2}");
regexify-expressionでimageIdを使用し、この場合は「-」文字で区切って、独自の組み合わせに含まれるものをすべて追加します。これにより、「841-en」、「58-bz」、「96-xx」などの結果が生成されます。ここで、imageIdは常にデータベース内の実際の画像、またはnullです。
一意のタグをimageIdと一緒に言語コードに貼り付けるため、image_idとlanguageCodeの組み合わせが一意になることがわかります 。これがまさに私たちに必要なものです!
これで、作成した言語コード、または生成したいその他の一意のフィールドを次のように簡単に抽出できます。
$languageCode = explode('-', $imageIdAndLanguageCode)[1];
このアプローチには次の利点があります。
- 例外をキャッチする必要はありません
- ファクトリーとシーダーは読みやすくするために分離できます
- コードはコンパクトです
ここでの欠点は、キーの1つを正規表現として表現できるキーの組み合わせしか生成できないことです。それが可能である限り、これはこの問題を解決するための良いアプローチのようです。