Laravelのモデルファクトリ 新旧が共存することが可能か検証してみた
Laravel8でモデルファクトリがクラスベースに書き直され、それを楽に修正するために以前こんな記事を書きました。
ただ、ツールを使って一気に修正することが困難なときもあると思うので、あとから修正する場合に新旧の書き方が共存することが可能なのか検証してみました。
環境
- PHP 8.1.2
- Laravel 9.5.1
環境はLaravel Sail
で作っています。
事前準備
Laravel7までの旧モデルファクトリを使うためにlaravel/legacy-factories
パッケージを入れておきます。
./vendor/bin/sail composer req laravel/legacy-factories --dev
さらに検証用のモデルクラスを用意します。
今回はLaravelのドキュメントに書いてある内容を使います。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
use HasFactory;
}
検証1 異なるEloquentモデルクラスが新旧の書き方をしている
新の方は、元々からあるUserクラスを使います。
旧の方は、こちらを使います。
<?php
use App\Models\Flight;
use Faker\Generator as Faker;
$factory->define(Flight::class, function (Faker $faker) {
return [
'name' => $faker->name,
];
});
検証はtinker
を使って新旧それぞれのモデルファクトリを実行してみます。
$ ./vendor/bin/sail artisan tinker
Psy Shell v0.11.2 (PHP 8.1.2 — cli) by Justin Hileman
>>>
>>> use App\Models\User;
>>> $user = User::factory()->make();
=> App\Models\User {#3533
name: "Lew Langosh DDS",
email: "demarcus13@example.net",
email_verified_at: "2022-03-26 13:40:50",
#password: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
#remember_token: "Pz9m6zZmuI",
}
>>>
>>> use App\Models\Flight;
>>> $flight = factory(Flight::class)->make();
=> App\Models\Flight {#3527
name: "Dr. Zetta Kilback",
}
>>>
検証2 同じEloquentモデルクラスが新旧の書き方をしている パターン1
新の方は、こちらを使います。
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Flight>
*/
class FlightFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition()
{
return [
'name' => $this->faker->name,
];
}
}
旧の方は、さきほどの使った内容を使います。
ただし、新の方は次のような条件[1]があるため、旧の方のファイル名を別名に変更しています。
- ネームスペースが
Database\Factories
の中にある - クラス名が
モデル名 + Factory
である
database/factories/FlightFactory.php
↓
database/factories/FlightOldFactory.php
検証はさきほどと同じでtinker
を使って新旧それぞれのモデルファクトリを実行してみます。
$ ./vendor/bin/sail artisan tinker
Psy Shell v0.11.2 (PHP 8.1.2 — cli) by Justin Hileman
>>>
>>>
>>> use App\Models\Flight;
>>> $flight = Flight::factory()->make();
=> App\Models\Flight {#3532
name: "Lora Gorczany",
}
>>> $flight = factory(Flight::class)->make();
=> App\Models\Flight {#3496
name: "King Cole DVM",
}
>>>
検証3 同じEloquentモデルクラスが新旧の書き方をしている パターン2
ドキュメントを読むとHasFactory
トレイトのnewFactory
メソッドをオーバーライドして、任意のファクトリクラスのインスタンスを返すように変更すれば、検証2の新のファクトリクラスの命名ルールを適用しないで済みます。
この場合、旧ファクトリのファイル名を変更する必要はないです。
use Database\Factories\NewFactory\FlightFactory;
~~~~~~~~省略~~~~~~~~
protected static function newFactory()
{
return new FlightFactory();
}
あとファクトリクラスの$model
プロパティにEloquentモデルクラスを指定してあげる必要があります。
<?php
namespace Database\Factories\NewFactory;
use App\Models\Flight;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Flight>
*/
class FlightFactory extends Factory
{
protected $model = Flight::class; // これを追加
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition()
{
return [
'name' => 'aaa',
];
}
}
$ ./vendor/bin/sail artisan tinker
Psy Shell v0.11.2 (PHP 8.1.2 — cli) by Justin Hileman
>>>
>>>
>>> use App\Models\Flight;
>>> $flight = Flight::factory()->make();
=> App\Models\Flight {#3529
name: "aaa",
}
>>> $flight = factory(Flight::class)->make();
=> App\Models\Flight {#3528
name: "Dr. Ezra Stroman",
}
>>>
結果
3つの検証を試してみましたが、laravel/legacy-factories
パッケージを使うことで新旧の書き方が共存することは可能のようです。
なので、あとから地道に修正することもできそうですが、laravel/legacy-factories
パッケージがどのバージョンのLaravelまでサポートしてくれるのかわからないので、早めに修正は行った方が良さそうです。
※Laravel9はサポートしてくれています[2]
Discussion