ファクトリ(ためしのデータを作る)
テストや最初のデータ入れに使う、ためしのデータを自動で作るファクトリの書き方と、状態・連番・リレーションの作り方を説明します。
ファクトリは、ためしのデータ(名前やメールアドレスなど)を、自動で作るしくみです。アプリのテストをするときや、データベースに最初のデータを入れる(シーディング)とき、1つ1つ値を書くのは大変です。そこで、Eloquent のモデルごとに、「ふつうはこういう値」という既定の値の組を決めておきます。
書き方の例は、新しい Laravel アプリに最初から入っている database/factories/UserFactory.php を見るのが早いです。
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
*/
class UserFactory extends Factory
{
/**
* The current password being used by the factory.
*/
protected static ?string $password;
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
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),
];
}
/**
* Indicate that the model's email address should be unverified.
*/
public function unverified(): static
{
return $this->state(fn (array $attributes) => [
'email_verified_at' => null,
]);
}
}
ファクトリは、いちばん簡単な形では、Laravel の基本のファクトリのクラスを受け継いで、definition メソッドを書いたクラスです。definition は、モデルを作るときに入れる「ふつうの値」の組を返します。
ファクトリの中では、fake ヘルパー関数(どこからでも呼べる便利な関数)で、Faker という PHP のライブラリ(便利な部品のまとまり)を使えます。Faker を使うと、テストや最初のデータ入れに使うランダムなデータを、かんたんに作れます。
補足
Faker の言語(ロケール)は、config/app.php の faker_locale で変えられます。
ファクトリを書く#
ファクトリを作る#
ファクトリを作るには、make:factory という Artisan コマンド(php artisan で動かす Laravel のコマンド)を使います。
php artisan make:factory PostFactory
新しいファクトリのクラスは、database/factories に置かれます。
モデルとファクトリの結びつけ#
ファクトリを書いたら、モデルから User::factory() のように呼ぶと、そのモデルのファクトリが手に入ります。この factory メソッドは、モデルに付けた Illuminate\Database\Eloquent\Factories\HasFactory トレイト(クラスに機能を足す部品)が用意する、静的なメソッド(クラス名から直接呼べるメソッド)です。
factory は、名前の決まりから、そのモデルに合うファクトリを探します。探すのは、Database\Factories の名前空間(クラスの置き場所の名前)にある、「モデルの名前 + Factory」という名前のクラスです。この決まりに合わないときは、モデルに UseFactory 属性(PHP の属性。クラスの前に書く印)を付けて、使うファクトリを自分で決めます。
use Illuminate\Database\Eloquent\Attributes\UseFactory;
use Database\Factories\Administration\FlightFactory;
#[UseFactory(FlightFactory::class)]
class Flight extends Model
{
// ...
}
別のやり方として、モデルの newFactory メソッドを上書きして、使うファクトリをそこから直接返すこともできます。
use Database\Factories\Administration\FlightFactory;
/**
* Create a new factory instance for the model.
*/
protected static function newFactory()
{
return FlightFactory::new();
}
そのうえで、ファクトリの側に UseModel 属性を付けて、モデルを決めます。
use App\Administration\Flight;
use Illuminate\Database\Eloquent\Factories\Attributes\UseModel;
use Illuminate\Database\Eloquent\Factories\Factory;
#[UseModel(Flight::class)]
class FlightFactory extends Factory
{
// ...
}
状態(ステート)#
状態(ステート)は、ファクトリの「ふつうの値」を少しだけ変えた版です。いくつも用意しておけば、好きなように組み合わせて使えます。たとえば、Database\Factories\UserFactory に、suspended(利用停止)という状態を書いておけます。値の1つだけを「停止中」に変えたものです。
状態のメソッドの中では、ふつう、基本のファクトリが持つ state メソッドを呼びます。state には、クロージャ(名前のない関数)を渡します。クロージャは、ファクトリの元の属性の配列を受け取り、変えたい属性だけを配列で返します。
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* Indicate that the user is suspended.
*/
public function suspended(): Factory
{
return $this->state(function (array $attributes) {
return [
'account_status' => 'suspended',
];
});
}
「trashed」の状態#
Eloquent のモデルが、ソフトデリート(消さずに印を付ける消し方)できるなら、trashed という、最初から用意された状態のメソッドを呼べます。作ったモデルは、すでに「ソフトデリート」された状態になります。trashed は、どのファクトリでも自動で使えるので、自分で書く必要はありません。
use App\Models\User;
$user = User::factory()->trashed()->create();
ファクトリのコールバック#
コールバック(あとで呼んでもらう処理)を登録すると、モデルを作った(make)あとや、保存した(create)あとに、ほかの処理を足せます。登録には afterMaking と afterCreating を使います。登録する場所は、ファクトリのクラスに書く configure メソッドの中です。configure は、ファクトリが作られるときに Laravel が自動で呼びます。
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
class UserFactory extends Factory
{
/**
* Configure the model factory.
*/
public function configure(): static
{
return $this->afterMaking(function (User $user) {
// ...
})->afterCreating(function (User $user) {
// ...
});
}
// ...
}
状態のメソッドの中でもコールバックを登録できます。その状態だけの、ほかの処理をしたいときに使います。
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* Indicate that the user is suspended.
*/
public function suspended(): Factory
{
return $this->state(function (array $attributes) {
return [
'account_status' => 'suspended',
];
})->afterMaking(function (User $user) {
// ...
})->afterCreating(function (User $user) {
// ...
});
}
| メソッド | 働き |
|---|---|
definition |
属性の既定の値の組を返す |
state |
属性の一部を変える |
configure |
ファクトリを作るときに、コールバックを登録する場所 |
afterMaking |
モデルを作った(保存はしない)あとの処理を決める |
afterCreating |
モデルを保存したあとの処理を決める |
ファクトリでモデルを作る#
モデルを作る(保存しない)#
ファクトリを書いたら、モデルの factory メソッド(HasFactory トレイトが用意するもの)でファクトリを取り出し、モデルを作れます。いくつか例を見てみましょう。まずは make で、データベースに保存せずにモデルを作ります。
use App\Models\User;
$user = User::factory()->make();
count を使うと、たくさんのモデルのコレクションを作れます。
$users = User::factory()->count(3)->make();
状態を当てはめる#
作るモデルに、状態も当てはめられます。いくつもの状態を当てはめたいときは、状態のメソッドを、そのまま続けて呼びます。
$users = User::factory()->count(5)->suspended()->make();
属性を上書きする#
モデルの既定の値の一部を変えたいときは、make に値の配列を渡します。決めた属性だけが置き換えられ、ほかは、ファクトリの既定の値のままです。
$user = User::factory()->make([
'name' => 'Abigail Otwell',
]);
別のやり方として、ファクトリに state を直接呼んで、その場で状態を変えることもできます。
$user = User::factory()->state([
'name' => 'Abigail Otwell',
])->make();
補足
ファクトリでモデルを作るときは、マスアサインメント(一括代入)の保護が、自動で止まります。
モデルを保存する#
create は、モデルを作って、Eloquent の save で、データベースに保存します。
use App\Models\User;
// Create a single App\Models\User instance...
$user = User::factory()->create();
// Create three App\Models\User instances...
$users = User::factory()->count(3)->create();
create に属性の配列を渡すと、ファクトリの既定の値を上書きできます。
$user = User::factory()->create([
'name' => 'Abigail',
]);
シーケンス#
作るモデルごとに、ある属性の値を、順番に入れ替えたいことがあります。状態の変更を「シーケンス」として書けます。たとえば、作るユーザーごとに、admin カラムの値を Y と N で交互にします。
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Sequence;
$users = User::factory()
->count(10)
->state(new Sequence(
['admin' => 'Y'],
['admin' => 'N'],
))
->create();
この例では、admin が Y のユーザーが5人、N のユーザーが5人できます。
必要なら、シーケンスの値にクロージャも使えます。シーケンスが新しい値を必要とするたびに、クロージャが呼ばれます。
use Illuminate\Database\Eloquent\Factories\Sequence;
$users = User::factory()
->count(10)
->state(new Sequence(
fn (Sequence $sequence) => ['role' => UserRoles::all()->random()],
))
->create();
シーケンスのクロージャの中では、渡されるシーケンスの $index プロパティ(クラスの中の変数)が使えます。$index は、シーケンスをここまで何回くり返したかの数です。
$users = User::factory()
->count(10)
->state(new Sequence(
fn (Sequence $sequence) => ['name' => 'Name '.$sequence->index],
))
->create();
便利な書き方として、sequence でもシーケンスを当てはめられます。中で state を呼んでいるだけです。クロージャか、順番に使う属性の配列を渡します。
$users = User::factory()
->count(2)
->sequence(
['name' => 'First User'],
['name' => 'Second User'],
)
->create();
| メソッド | 働き |
|---|---|
make |
モデルを作る(保存しない) |
create |
モデルを作って、保存する |
count |
作る数を決める |
state |
属性を変える |
sequence |
属性を順番に入れ替える(state と Sequence の便利な書き方) |
ファクトリでリレーションを作る#
「1対多」のリレーション#
ここからは、ファクトリで、つながったモデルどうし(リレーション。表どうしのつながり)をまとめて作る方法を見ます。アプリに App\Models\User と App\Models\Post があるとします。User には、Post との hasMany(1人が複数の投稿を持つ)のリレーションがあります。このとき、ファクトリの has メソッドに投稿のファクトリを渡すと、投稿を3つ持つユーザーを作れます。
use App\Models\Post;
use App\Models\User;
$user = User::factory()
->has(Post::factory()->count(3))
->create();
has に Post を渡すと、Laravel は名前の決まりから、「User の posts メソッドがこのリレーションだ」と考えます。必要なら、2つ目の引数でリレーションの名前をはっきり書けます。
$user = User::factory()
->has(Post::factory()->count(3), 'posts')
->create();
作る投稿に、状態を当てはめることもできます。状態を決めるのに親のモデル(ここではユーザー)を見たいときは、クロージャを渡します。クロージャは、2つ目の引数で親のモデルを受け取ります。
$user = User::factory()
->has(
Post::factory()
->count(3)
->state(function (array $attributes, User $user) {
return ['user_type' => $user->type];
})
)
->create();
マジックメソッドを使う#
リレーションを作るときは、Laravel の「マジックメソッド」(名前から自動で動くメソッド)も使えて便利です。たとえば次の hasPosts は、名前から「User の posts リレーションで投稿を作る」と判断されます。
$user = User::factory()
->hasPosts(3)
->create();
マジックメソッドでリレーションを作るとき、関連するモデルで上書きしたい属性の配列も渡せます。
$user = User::factory()
->hasPosts(3, [
'published' => false,
])
->create();
属性の配列をいくつも渡すと、作るモデルごとに別の値を付けられます。Laravel は、配列を1つずつ順に当てはめます。
$user = User::factory()
->hasPosts(
['title' => 'First Post'],
['title' => 'Second Post'],
['title' => 'Third Post'],
)
->create();
状態を決めるのに親のモデルを見たいときは、クロージャも渡せます。
$user = User::factory()
->hasPosts(3, function (array $attributes, User $user) {
return ['user_type' => $user->type];
})
->create();
「多対1」のリレーション#
「1対多」のリレーションの作り方を見たので、次は、その反対を見ます。for を使うと、ファクトリで作るモデルが属する、親のモデルを決められます。たとえば、1人のユーザーに属する、3つの App\Models\Post を作れます。
use App\Models\Post;
use App\Models\User;
$posts = Post::factory()
->count(3)
->for(User::factory()->state([
'name' => 'Jessica Archer',
]))
->create();
作るモデルに結びつけたい親のモデルがすでにあるときは、そのモデルを for に渡せます。
$user = User::factory()->create();
$posts = Post::factory()
->count(3)
->for($user)
->create();
マジックメソッドを使う#
「多対1」のリレーションも、マジックメソッドで作れます。たとえば次の例は、名前から「3つの投稿は、Post の user リレーションで1人のユーザーに属する」と判断されます。
$posts = Post::factory()
->count(3)
->forUser([
'name' => 'Jessica Archer',
])
->create();
「多対多」のリレーション#
「1対多」のリレーションと同じように、「多対多」のリレーションも、has で作れます。
use App\Models\Role;
use App\Models\User;
$user = User::factory()
->has(Role::factory()->count(3))
->create();
中間表の属性#
モデルをつなぐ、中間表(pivot)に入れる属性を決めたいときは、hasAttached を使います。2つ目の引数に、中間表の属性の名前と値の配列を渡します。
use App\Models\Role;
use App\Models\User;
$user = User::factory()
->hasAttached(
Role::factory()->count(3),
['active' => true]
)
->create();
状態を決めるのに関連するモデルを見たいときは、クロージャも渡せます。
$user = User::factory()
->hasAttached(
Role::factory()
->count(3)
->state(function (array $attributes, User $user) {
return ['name' => $user->name.' Role'];
}),
['active' => true]
)
->create();
中間表の配列の配列を渡すと、関連するモデルごとに、別々の中間表のデータを入れられます。
$user = User::factory()
->hasAttached(
Role::factory(),
[
['active' => true],
['active' => false],
]
)
->create();
作るモデルにつなぎたい、すでにあるモデルがあるときは、そのモデルを hasAttached に渡せます。次の例では、同じ3つの役割(ロール)が、3人のユーザー全員につながります。
$roles = Role::factory()->count(3)->create();
$users = User::factory()
->count(3)
->hasAttached($roles, ['active' => true])
->create();
マジックメソッドを使う#
「多対多」のリレーションも、マジックメソッドで作れます。たとえば次の例は、名前から「User の roles リレーションで役割を作る」と判断されます。
$user = User::factory()
->hasRoles(1, [
'name' => 'Editor'
])
->create();
ポリモーフィックなリレーション#
ポリモーフィックなリレーション(1つの表が、いろいろな表につながるしくみ。くわしくはリレーションのページ)も、ファクトリで作れます。ポリモーフィックな「morph many」は、ふつうの「has many」と同じように作ります。たとえば、App\Models\Post が、App\Models\Comment と morphMany のリレーションを持つときです。
use App\Models\Post;
$post = Post::factory()->hasComments(3)->create();
「morph to」のリレーション#
morphTo のリレーションは、マジックメソッドでは作れません。代わりに、for を直接使い、リレーションの名前をはっきり書く必要があります。たとえば、Comment に、morphTo のリレーションを書いた commentable メソッドがあるとします。このとき、for を直接使って、1つの投稿に属する3つのコメントを作れます。
$comments = Comment::factory()->count(3)->for(
Post::factory(), 'commentable'
)->create();
ポリモーフィックな「多対多」のリレーション#
ポリモーフィックな「多対多」(morphToMany / morphedByMany)のリレーションも、ポリモーフィックでない「多対多」と同じように作れます。
use App\Models\Tag;
use App\Models\Video;
$video = Video::factory()
->hasAttached(
Tag::factory()->count(3),
['public' => true]
)
->create();
マジックメソッドの has 系も、ポリモーフィックな「多対多」に使えます。
$video = Video::factory()
->hasTags(3, ['public' => true])
->create();
| メソッド | 働き |
|---|---|
has |
「1対多」「多対多」で、関連するモデルを作る |
has + モデルの名前(hasPosts など) |
決まりでリレーションを選ぶ、短い書き方 |
for |
属する親のモデルを決める(「多対1」や morphTo) |
for + モデルの名前(forUser など) |
決まりで親を選ぶ、短い書き方(morphTo には使えない) |
hasAttached |
中間表の属性を付けて、「多対多」でつなぐ |
ファクトリの中でリレーションを決める#
モデルのファクトリの中でリレーションを決めるときは、ふつう、リレーションの外部キーに、新しいファクトリを入れます。多くは、belongsTo や morphTo のような「逆向き」のリレーションで使います。たとえば、投稿を作るときに、新しいユーザーも作りたいなら、次のようにします。
use App\Models\User;
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'user_id' => User::factory(),
'title' => fake()->title(),
'content' => fake()->paragraph(),
];
}
リレーションのカラムの値を、同じファクトリのほかの属性から決めたいときは、その属性にクロージャを入れます。クロージャは、ほかの属性の値が決まったあとの配列を受け取ります。
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'user_id' => User::factory(),
'user_type' => function (array $attributes) {
return User::find($attributes['user_id'])->type;
},
'title' => fake()->title(),
'content' => fake()->paragraph(),
];
}
すでにあるモデルを使い回す(recycle)#
いくつかのモデルが、同じ相手のモデルとつながっていることがあります。recycle にその相手のモデルを渡すと、ファクトリが作るどのリレーションでも、渡した1つを使い回します。
たとえば、Airline(航空会社)、Flight(便)、Ticket(チケット)のモデルがあり、チケットは航空会社と便に属し、便も航空会社に属すとします。チケットを作るとき、チケットと便で、同じ航空会社を使いたいはずです。そこで、航空会社を recycle に渡します。
Ticket::factory()
->recycle(Airline::factory()->create())
->create();
recycle は、共通のユーザーやチームに属するモデルがあるときに、とくに便利です。
recycle には、すでにあるモデルのコレクションも渡せます。コレクションを渡すと、ファクトリがその種類のモデルを必要とするたびに、コレクションからランダムに1つが選ばれます。
Ticket::factory()
->recycle($airlines)
->create();
関連するページ#
公式ドキュメント(英語)
2026年10月5日時点の内容をもとに、日本語でまとめています。