Resolvi
Pesquisei muito por uma solução para esse problema e descobri que muitos outros também passaram por isso. Se você só precisa de um elemento do outro lado da sua relação, é muito simples .
A adição da "restrição exclusiva de várias colunas" é o que tornou isso complicado. A única solução que encontrei foi "Esqueça a restrição do MySQL e apenas envolva a criação da fábrica com um try-catch para exceções de PDO". Isso parecia uma solução ruim, já que outras PDOExceptions também seriam capturadas e simplesmente não parecia "certo".
Solução
Para fazer este trabalho eu dividi os seeders em ImageTableSeeder e ImageTextTableSeeder, e ambos são bem diretos. Seus comandos de execução se parecem com isso:
public function run()
{
factory(App\Models\ImageText::class, 100)->create();
}
A mágica acontece dentro da 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,
];
});
É isso:
$imageIdAndLanguageCode = $faker->unique()->regexify("/^$imageId-[a-z]{2}");
Usamos o imageId em uma expressão regexify e adicionamos o que também estiver incluído em nossa combinação exclusiva, separada neste caso com um caractere '-'. Isto irá gerar resultados como "841-en", "58-bz", "96-xx" etc. onde o imageId é sempre uma imagem real em nosso banco de dados, ou nulo.
Como colocamos a tag exclusiva no código de idioma junto com o imageId, sabemos que a combinação de image_id e languageCode será exclusiva . Isso é exatamente o que precisamos!
Agora podemos simplesmente extrair o código do idioma criado, ou qualquer outro campo exclusivo que queiramos gerar, com:
$languageCode = explode('-', $imageIdAndLanguageCode)[1];
Esta abordagem tem as seguintes vantagens:
- Não há necessidade de capturar exceções
- Fábricas e Semeadores podem ser separados para facilitar a leitura
- O código é compacto
A desvantagem aqui é que você só pode gerar combinações de teclas onde uma das chaves pode ser expressa como regex. Enquanto isso for possível, esta parece ser uma boa abordagem para resolver este problema.