Laravelのバージョンを色々使ってると細かい所で、このバージョンの時は出来て、このバージョンのときは出来ないみたいな状況になるので、思った所を復習して置こうと思います。
今回は、テストコードを書く時に不可欠なfactory系でrelationのfactoryを使用時です。
まず、Model Factories が入ったのは、バージョン5.1からになります。
良くあるサンプルで、ブログとコメントのfactory例を上げてみます。
$factory->define(App\Post::class, function ($faker) {
return [
'title' => $faker->sentence,
'body' => $faker->sentence
];
});
$factory->define(App\Comment::class, function ($faker) {
return [
'post_id' => factory(App\Post::class)->create()->id,
'body' => $faker->sentence,
];
});
v5.1.2では、上記のfactory定義を行い、post_id
をパラメーターで渡したとしても、元々Factoryで定義してあるModelも作られる現象が発生します。
その問題はこちらで述べています:https://github.com/laravel/framework/issues/9245
Factory::create(App\Comment::class, [
'post_id' => $someGivenPostId
]);
その後 https://github.com/laravel/framework/pull/9387 のPull Reqestで5.1.3にマージされて、以下の形式で対応可能になりました。
// v5.1.3以降に$attributesが追加
$factory->define(App\Comment::class, function ($faker, $attributes) {
$post_id = isset($attributes['post_id']) ? $attributes['post_id']: factory(App\Post::class)->create()->id;
return [
'post_id' => $post_id,
'body' => $faker->sentence,
];
});
しかし、上記だと複雑なRelationに対応出来たいとの事で https://github.com/laravel/framework/pull/12231/ のpull reqestでLaravel v5.2.2 で最終的な現在(書いてる時点でv5.7です)の形になってます。
// v5.2.16以降Clousreでrelationを定義
$factory->define(App\Post::class, function (Faker $faker) {
return [
'post_id' => function() {
return factory(App\Post::class)->create()->id;
},
'body' => $faker->sentence,
];
});
これで以下の方法でも、余計なデーターが作られない様になりました。
factory(App\Comment::class, 10)->create(['post_id' => App\Post::find(1)]);
v5.1.3で追加された、$attribites
もそのまま残されていますので、必要に応じて$attributesを元に分岐しても大丈夫です。