Eloquent の Factory で関連モデルも同時に生成する方法
こんにちは。 SAW です。
最近、 Gran Turismo 7 の National B Lincense をすべてゴールドでクリアしました。
結構難しくて苦戦しました (笑)
Laravel で Faker と Eloquent の Factory を使うと、簡単にダミーデータを大量に生成できます。
関連モデルのダミーデータを生成したい場合、参照先の FOREIGN KEY の値を知っている必要があります。
しかし、 参照先のモデルのダミーデータがテーブルに挿入するまで FOREIGN KEY の値は確定しません。
本記事では、 Eloquent の Factory を使ってダミーデータを生成する際に、同時に関連モデルのダミーデータも生成する方法を紹介します。
なお、本記事では Laravel のバージョンが 10.x 系 を前提としています。
対象読者
本記事で想定する読者層は次の通りです。
- Laravel の基本的な知識を有している
- Factory を利用した seeding についての基本的な知識を有している
前準備: テーブルのスキーマと Eloquent Model の定義
テーブルのスキーマ定義
まず、 posts
と comments
テーブルのスキーマを以下のように定義します。
Schema::create('posts', function (Blueprint $table) {
$table->ulid('id')->primary();
$table->string('title');
$table->string('content');
$table->timestamps();
});
Schema::create('comments', function (Blueprint $table) {
$table->ulid('id')->primary();
$table->foreignUlid('post_id');
$table->string('reply');
$table->timestamps();
});
posts
と comments
の関連は以下の ER 図の通りです。
Eloquent Model の定義
テーブルに対応する Post
クラスと Comment
クラスの定義はそれぞれ以下の通りです。
Eloquent Model で関連を表すために、 comments()
を Post
クラスに定義します。
class Post extends Model
{
use HasFactory, HasUlids;
public function comments(): HasMany
{
return $this->hasMany(Comment::class);
}
}
class Comment extends Model
{
use HasFactory, HasUlids;
}
Factory クラスの定義
Post
と Comment
のモデルを生成する PostFactory
クラスと CommentFactory
クラスをそれぞれ以下のように定義します。
class PostFactory extends Factory
{
public function definition(): array
{
return [
'id' => Str::ulid(),
'title' => fake()->sentence(),
'content' => fake()->text(),
];
}
}
class CommentFactory extends Factory
{
public function definition(): array
{
return [
'id' => Str::ulid(),
'reply' => fake()->text(),
];
}
}
Factory で関連モデルも生成する方法
モデルを factory()
を利用して生成する場合、 has()
を利用することで関連モデルもあわせて生成できます。
has()
を利用することで、事前に参照先の FOREIGN KEY を知らなくても、自動的に関連づけをしてモデルが生成されます。
has()
を利用する際には、引数に関連モデルの Factory オブジェクトを渡します。
例えば、 前準備: テーブルのスキーマと Eloquent Model の定義 で定義した Post
モデルと関連モデルの Comment
を生成する場合、 has()
の引数に CommentFactory
オブジェクトを渡します。
CommentFactory
オブジェクトは Comment::factory()
で生成できます。
以下は 3 つの Comment
を持つ Post
を 5 つ生成するコード例です。
Post
は 5 個、 Comment
は 15 個生成されます。
Post::factory(5)
->has(Comment::factory(3))
->create();
tinker などで確認してみると、 Post
が 5 個、 Comment
が 15 個生成されていることが確認できます。
> Post::count()
= 5
> Comment::count()
= 15
また、以下の実行結果から、それぞれの Post
が Comment
を 3 つ持っていることも確認できます。
> Post::all()->map(fn($x) => $x->comments->count())
= Illuminate\Support\Collection {#7300
all: [
3,
3,
3,
3,
3,
],
}
まとめ
本記事のまとめは次の通りです。
- Factory の
has()
を利用することで関連モデルも同時に生成できる- 参照先のモデルの FOREIGN KEY を知らなくても自動的に関連づけしてモデルが生成される
Eloquent の Factory と少し仲良くなれた気がします (笑)
参考文献
Discussion