Laravel8から Eloquent を利用した ModelFactory が刷新され、使いやすくなりました。
Class化したおかげでメソッドチェーンで予め定義したデータの状態を簡単にCreateすることが出来るようになりました。
便利になったのでしっかりと使いこなしていきましょう。
環境
- PHP v7.4
- Laravel v8.31
詳細
まずは EloquentModel を作成しましょう。Eloquent\Model を継承して WorkModel を作成しましょう。リファレンス通りに HasFactory トレイトを使って Factory 機能を実装することで Factory を使う準備をします。
public function testWork() { $companyId = 12345; // デフォルト値で生成する。ループを回して値を取得したりsave()することも出来る $works = Work::factory()->make(); // 作成と同時にDBに挿入 $works = Work::factory()->count(3)->companyId($companyId)->paid()->create(); }
基本的なEloquentModelを作成したら次はFactoryを作成しましょう。
Factoryモデルの作成
database/factoriesフォルダ配下が基本的な配置場所となります。最初から存在するUserFactoryを元に作成するのも良いでしょう。$modelプロパティでEloquentModelクラスを指定します。
definition
メソッドで返却する値がWork::factory()->create()などで呼び出した時のデフォルト値となります。ここではFakerを使ってランダムにしていますが、固定値が必要であれば固定値を指定しましょう。
<?php namespace Database\Factories; use App\Models\Work; use App\Domain\Model\Status; use Illuminate\Database\Eloquent\Factories\Factory; class WorkFactory extends Factory { /** * The name of the factory's corresponding model. * * @var string */ protected $model = Work::class; /** * Define the model's default state. * * @return array */ public function definition() { return [ 'work_id' => $this->faker->unique()->randomNumber(), 'company_id' => $this->faker->unique()->randomNumber(), 'status' => Status::CLOSE, ]; } }
基本形はこのような形で記載します。
状態を定義する
基本形を作成しましたが、このままでは応用が利かないので作成したいデータには状態を定義してあげましょう。
有効や無効、有料無料などを定義してあげることで作成したいデータをメソッドチェーンを使って作成することができます。
<?php namespace Database\Factories; use App\Models\Work; use App\Domain\Model\Status; use Illuminate\Database\Eloquent\Factories\Factory; class WorkFactory extends Factory { /** * The name of the factory's corresponding model. * * @var string */ protected $model = Work::class; /** * Define the model's default state. * * @return array */ public function definition() { return [ 'work_id' => $this->faker->unique()->randomNumber(), 'company_id' => $this->faker->unique()->randomNumber(), 'status' => Status::CLOSE, ]; } public function companyId($companyId): Factory { return $this->state(function () use ($companyId) { return ['company_id' => $companyId,]; }); } public function free(): Factory { return $this->state(function () { return ['status' => Status::FREE,]; }); } public function paid(): Factory { return $this->state(function () { return ['status' => Status::PAID,]; }); } }
呼び出し方
作成したEloquentModelからfactory()メソッドから生成します。UnitTestやSeederなどで使えるでしょう
public function testWork() { $companyId = 12345; // デフォルト値で生成する。ループを回して値を取得したりsave()することも出来る $works = Work::factory()->make(); // 作成と同時にDBに挿入 $works = Work::factory()->count(3)->companyId($companyId)->paid()->create(); }
これでLaravel8標準的なFactoryを使用することが出来ました。
お疲れ様でした。
おまけ
標準のFactoryModelの配置場所はEloquentModelのnamespaceに応じて決定されます。DDDなどのドメインパターンを採用している場合、ディレクトリ構成が冗長になってしまったりFactoryModelの置き場所を指定したい場合があるでしょう。
そのときはHasFactoryトレイトのnewFactoryメソッドをオーバーライドします。
Eloquentoモデル内に以下のように記載してあげましょう。
protected static function newFactory():Factory { return \Database\Factories\Effect\WorkFactory::new(); }