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();
}
![[Laravel]クエリビルダーを使わずに生SQL(素のSQL)を実行する](https://biotope.work/wp-content/uploads/2021/01/laravel_logo_230r-300x196.jpg)
![[Laravel]Controller入門: 基本的な使い方と実践例](https://biotope.work/wp-content/uploads/2021/01/laravel.jpg)