Laravel Factory の新メソッド recycle を使ってみる
前書き
小ネタにはなりますが、Laravel 9.30.1 にて、ダミーデータを作る際などに利用する Factory に recycle() というメソッドが加わりましたので、これを利用して少し恩恵を味わってみたいと思います。
ちなみ今回こちらで見る機能は、Laravel 9.34 以上から実現可能です。(詳しくは下で)
本題
現状の困り所は何かと言うと、A user has many posts (1ユーザーが多数のブログ記事を所有している)という関係の時に、普通な感じでダミーデータを作成すると、posts の所有者が、連番1から綺麗に並んでしまうんですね。こんな感じです。
posts テーブルの中身
いかにもダミーデータという感じで、少しやる気が失われます。(笑
まぁ、考え方によっては、綺麗に並んでいる方が、何かテストし易いとかあるかも知れませんが、それを言ってはブログのネタが切れてしまいますので、今回は recycle() 機能を使って、これをランダム化してより本物っぽいデータにしたいと思います。という事で、改めて具体的にコードで見ていきます。
コマンドで、Post モデルと同時にマイグレーションファイル、ファクトリファイルを作成します。
php artisan make:model Post -mf
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(User::class);
$table->string('title');
$table->longText('body');
$table->timestamps();
});
}
public function definition()
{
return [
'user_id' => User::factory(),
'title' => $this->faker->realText(10),
'body' => $this->faker->realText(10),
];
}
Post モデルには以下を追加。
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
で、DatabaseSeeder に以下のように書きます。
ユーザーを3人作って、その各々に3件の記事を所有させる形です。
public function run()
{
User::factory(3)->create()->each(function (User $user) {
Post::factory(3)->for($user)->create();
});
}
これで、マイグレーション&シーディングを実行すると、
php artisan migrate:fresh --seed
先程の画像と同じですが、いかにもテストっぽい感じの並びになります。
posts テーブルの中身
ちょっとイケてないですよね?
では気を改めて、試しに以下のように書いてみると、、、
public function run()
{
User::factory(3)->create();
Post::factory(10)->create(['user_id' => random_int(1, 3)]);
}
再度、php artisan migrate:fresh --seed してみると、、
posts テーブルの中身
あぁ、切ない事になりました…💦
random_int(1, 3) は確かに走ったのですが、1回走っただけで、その1回の結果が全ての Post 10件分に適用されています。
こうなると、for() とか使って、1件1件ぐるぐる回して処理するしかないのか?と思ったりしますが、正直あまり地味な事はしたくありません。
そこで、今回の recycle() メソッドを使うと、こんな感じでいけます。
public function run()
{
$users = User::factory(3)->create();
Post::factory(10)->recycle($users)->create();
}
すると今度は、こんな感じになります。
posts テーブルの中身
おぉ、より自然な感じで本物っぽくなりましたね。
上記は、下記みたいに書くのもいいかも知れませんね。
public function run()
{
Post::factory(10)->recycle(
User::factory(3)->create()
)->create();
}
recycle メソッドについて
この recycle メソッドですが、元は Ver.9.30.1 の jessarcher さんによるもので、今回の例とは少し違った使い方を意図したものでした。日本語ドキュメントにも載っていますので、興味のある方は、そちら参照して下さい。
ですが、その後、Ver.9.34 にて少し拡張され「モデルを作成する際、recycle() に渡された複数モデルをランダムに利用する」となりましたので、今回はその拡張部分を使った感じになります。
雑感
ちなみに、元のプルリクでは、using() と言う普通な感じのメソッド名でしたが、最後は、Taylor 氏によって recycle() と言うインパクトあり過ぎなメソッド名に変更されました😄
もし良ければ、今回のコード、リサイクルして下さい ♻️
間違い等見つけましたらコメント下さい🙇♂️
Discussion