Documentation Index
Fetch the complete documentation index at: https://kawax.biz/llms.txt
Use this file to discover all available pages before exploring further.
ファクトリとは
テストやデータベースシーディングでは、データベースにレコードを挿入する必要があります。
手動で各カラムの値を指定する代わりに、Laravelのモデルファクトリを使うと各Eloquentモデルのデフォルト属性セットを定義できます。
すべての新しいLaravelアプリケーションには database/factories/UserFactory.php が付属しています。
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
class UserFactory extends Factory
{
// 同じパスワードを毎回再ハッシュしないためにキャッシュする
protected static ?string $password;
public function definition(): array
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => static::$password ??= Hash::make('password'),
'remember_token' => Str::random(10),
];
}
}
fake() ヘルパーを通じて Faker ライブラリが利用でき、様々なランダムデータを生成できます。
Fakerのロケールは config/app.php の faker_locale オプションで変更できます。
ファクトリの生成
make:factory Artisanコマンドでファクトリを作成します。
php artisan make:factory PostFactory
新しいファクトリクラスは database/factories ディレクトリに配置されます。
モデルとファクトリの自動検出
モデルに HasFactory トレイトを使用すると、Laravelが自動的に対応するファクトリを見つけます。
Database\Factories 名前空間で、モデル名に Factory を付けたクラス名を検索します。
命名規則が合わない場合は UseFactory 属性で明示的に指定できます。
use Illuminate\Database\Eloquent\Attributes\UseFactory;
use Database\Factories\Administration\FlightFactory;
#[UseFactory(FlightFactory::class)]
class Flight extends Model
{
// ...
}
ファクトリの定義
definition() メソッド
ファクトリの中心となる definition() メソッドでデフォルト属性を定義します。
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
class PostFactory extends Factory
{
public function definition(): array
{
return [
'user_id' => \App\Models\User::factory(),
'title' => fake()->sentence(),
'content' => fake()->paragraphs(3, true),
'published_at' => fake()->optional()->dateTimeBetween('-1 year', 'now'),
];
}
}
Fakerがよく使われるメソッドの一覧:
| メソッド | 生成されるデータ例 |
|---|
fake()->name() | John Doe |
fake()->email() | [email protected] |
fake()->sentence() | ランダムな文 |
fake()->paragraph() | ランダムな段落 |
fake()->numberBetween(1, 100) | 1〜100の整数 |
fake()->dateTime() | ランダムな日時 |
fake()->boolean() | true / false |
ファクトリステート (States)
ステートメソッドを使うと、ファクトリに対して個別の変更を定義できます。
use Illuminate\Database\Eloquent\Factories\Factory;
class UserFactory extends Factory
{
public function definition(): array
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'account_status' => 'active',
];
}
// 停止中ユーザーのステート
public function suspended(): static
{
return $this->state(fn (array $attributes) => [
'account_status' => 'suspended',
]);
}
// 管理者ユーザーのステート
public function admin(): static
{
return $this->state(fn (array $attributes) => [
'is_admin' => true,
]);
}
}
ステートは組み合わせて使えます。
$user = User::factory()->suspended()->create();
$admin = User::factory()->admin()->create();
ソフトデリートのステート
ソフトデリート対応のモデルには、ビルトインの trashed() ステートが利用できます。
$user = User::factory()->trashed()->create();
ファクトリコールバック (Callbacks)
afterMaking と afterCreating でモデル生成後の追加処理を定義します。
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
class UserFactory extends Factory
{
public function configure(): static
{
return $this->afterMaking(function (User $user) {
// make() 後に実行(DBには保存されていない)
})->afterCreating(function (User $user) {
// create() 後に実行(DBに保存済み)
});
}
// ...
}
ステートメソッド内でもコールバックを登録できます。
public function withProfile(): static
{
return $this->state(fn (array $attributes) => [])
->afterCreating(function (User $user) {
$user->profile()->create([
'bio' => fake()->paragraph(),
]);
});
}
モデルの生成
make() — DBに保存しない
use App\Models\User;
// 1件生成
$user = User::factory()->make();
// 3件生成(コレクションで返る)
$users = User::factory()->count(3)->make();
create() — DBに保存する
// 1件生成してDBに保存
$user = User::factory()->create();
// 3件生成してDBに保存
$users = User::factory()->count(3)->create();
属性の上書き
make() や create() に配列を渡すと、特定の属性だけ上書きできます。
$user = User::factory()->make([
'name' => '山田太郎',
]);
$user = User::factory()->create([
'name' => '鈴木花子',
'email' => '[email protected]',
]);
ステートを使ったインライン上書きも可能です。
$user = User::factory()->state([
'name' => '田中一郎',
])->make();
ファクトリでモデルを生成する際、マスアサインメント保護は自動的に無効になります。
Sequence(シーケンス)
複数モデルを生成する際に属性を交互に変える場合は Sequence を使います。
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Sequence;
$users = User::factory()
->count(10)
->state(new Sequence(
['admin' => 'Y'],
['admin' => 'N'],
))
->create();
// 5件はadmin='Y'、5件はadmin='N'で生成される
sequence() メソッドを使うとより簡潔に書けます。
$users = User::factory()
->count(2)
->sequence(
['name' => '最初のユーザー'],
['name' => '2番目のユーザー'],
)
->create();
クロージャでランダムな値を動的に生成することもできます。
use Illuminate\Database\Eloquent\Factories\Sequence;
$users = User::factory()
->count(10)
->state(new Sequence(
fn (Sequence $sequence) => ['name' => 'ユーザー ' . $sequence->index],
))
->create();
リレーションシップのファクトリ
Has Many(1対多)
has() メソッドで「1対多」リレーションを持つモデルを生成します。
use App\Models\Post;
use App\Models\User;
// 3件のPostを持つUserを生成
$user = User::factory()
->has(Post::factory()->count(3))
->create();
マジックメソッドを使うとより簡潔に書けます(has + リレーション名の複数形)。
$user = User::factory()
->hasPosts(3)
->create();
// 属性を上書き
$user = User::factory()
->hasPosts(3, ['published' => false])
->create();
Belongs To(逆リレーション)
for() メソッドで「属する」親モデルを指定します。
use App\Models\Post;
use App\Models\User;
// 特定ユーザーに属する3件のPostを生成
$posts = Post::factory()
->count(3)
->for(User::factory()->state(['name' => '田中花子']))
->create();
// 既存モデルを親として使用
$user = User::factory()->create();
$posts = Post::factory()->count(3)->for($user)->create();
マジックメソッド版:
$posts = Post::factory()
->count(3)
->forUser(['name' => '田中花子'])
->create();
Many to Many(多対多)
hasAttached() メソッドで多対多リレーションを扱います。中間テーブルの属性も指定できます。
use App\Models\Role;
use App\Models\User;
$user = User::factory()
->hasAttached(
Role::factory()->count(3),
['active' => true] // 中間テーブルの属性
)
->create();
マジックメソッド版:
$user = User::factory()
->hasRoles(1, ['name' => 'Editor'])
->create();
ポリモーフィックリレーション
通常の「1対多」と同様に has() またはマジックメソッドが使えます。
use App\Models\Post;
$post = Post::factory()->hasComments(3)->create();
morphTo リレーションにはマジックメソッドは使えません。for() に関係名を明示します。
$comments = Comment::factory()->count(3)->for(
Post::factory(), 'commentable'
)->create();
ファクトリ内でのリレーション定義
definition() 内で外部キーに別のファクトリを割り当てると、モデル生成時に自動的に親モデルも生成されます。
class PostFactory extends Factory
{
public function definition(): array
{
return [
'user_id' => \App\Models\User::factory(),
'title' => fake()->sentence(),
'content' => fake()->paragraph(),
];
}
}
recycle() — 既存モデルの再利用
複数のリレーションで同じモデルインスタンスを再利用したい場合は recycle() を使います。
// 同じAirlineをTicketとFlightの両方で使い回す
Ticket::factory()
->recycle(Airline::factory()->create())
->create();
// コレクションからランダムに選択
$airlines = Airline::factory()->count(3)->create();
Ticket::factory()->count(10)->recycle($airlines)->create();
シーディングでの利用
DatabaseSeeder やシーダークラスからファクトリを呼び出します。
namespace Database\Seeders;
use App\Models\User;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
public function run(): void
{
// 10件のユーザーを生成し、各ユーザーに3件の投稿を持たせる
User::factory()
->count(10)
->hasPosts(3)
->create();
}
}
シーダーの実行:
テストでの利用
テストでは RefreshDatabase トレイトと組み合わせてファクトリを使います。
namespace Tests\Feature;
use App\Models\User;
use App\Models\Post;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class PostTest extends TestCase
{
use RefreshDatabase;
public function test_user_can_view_their_posts(): void
{
$user = User::factory()->create();
$posts = Post::factory()->count(3)->for($user)->create();
$response = $this->actingAs($user)
->get('/dashboard');
$response->assertOk();
$response->assertSee($posts->first()->title);
}
public function test_suspended_user_cannot_post(): void
{
$user = User::factory()->suspended()->create();
$response = $this->actingAs($user)
->post('/posts', ['title' => 'テスト']);
$response->assertForbidden();
}
}
RefreshDatabase はテストごとにデータベースをリセットするため、テスト間でデータが干渉しません。
PestでテストするときもファクトリのAPIは同じです。
uses(RefreshDatabase::class) を使ってデータベースをリセットしてください。
次のステップ
データベースシーディング
シーダーとファクトリを組み合わせて初期データを投入する方法を確認します。
テスト入門
Laravelのテスト機能とRefreshDatabaseトレイトの使い方を確認します。