christophrumpel / laravel-factories-reloaded
该软件包位于 Laravel 工厂之上,为每个模型提供专门的工厂类。
Requires
- php: ^8.0
- christophrumpel/laravel-command-file-picker: ^1.1
- illuminate/support: ^8.0
- laravel/framework: ^8.0
- nikic/php-parser: ^4.3
- roave/better-reflection: ^5.3
Requires (Dev)
- friendsofphp/php-cs-fixer: ^2.16
- mockery/mockery: ^1.2
- orchestra/testbench: ^6.0
- phpunit/phpunit: ^9.3
- dev-master
- v3.0.0
- v2.2.0
- v2.1.0
- v2.0.2
- v2.0.1
- v2.0
- v1.3.0
- v1.2.0
- 1.1.1
- v1.1.0
- v1.0.8
- v1.0.7
- v1.0.6
- v1.0.5
- v1.0.4
- v1.0.3
- v1.0.2
- v1.0.1
- v1.0.0
- v0.0.16
- v0.0.15
- v0.0.14
- v0.0.13
- v0.0.12
- v0.0.11
- v0.0.10
- v0.0.9
- v0.0.8
- v0.0.7
- v0.0.6
- v0.0.5
- v0.0.4
- v0.0.3
- v0.0.2
- v0.0.1
- dev-support-laravel-8
- dev-feature/supportBelongsToRelationship
- dev-bugfix/throwErrorIfStateIsOfTypeArray
- dev-devmsh-pr
- dev-test-devmsh-pr
- dev-feature/makeImportedStatesImmutable
- dev-feature/useDifferentModelsForGeneratedFactoriesTests
- dev-nuernbergerA-transform-vanilla-factories
- dev-transform-vanilla-factories
- dev-feature/addMakeMethod
- dev-feature/addRelationships
- dev-feature/addStates
This package is auto-updated.
Last update: 2024-09-04 12:57:15 UTC
README
该软件包生成基于类的模型工厂,您可以使用它来替代 Laravel 提供的工厂。
Laravel 8 支持
新版本 v3 现在支持 Laravel 8 和 PHP 8+。由于 Laravel 8 对工厂的实现方式进行了大量更改,因此新版本 v2 仅适用于 Laravel 8。如果您尚未使用 Laravel 8,请使用此软件包的最新 1.* 版本,如果需要 PHP 7 支持,请使用最新 2.* 版本。
优势
- 使用您已熟悉的 Laravel 工厂功能(
create
、make
、times
、states
) - 自动创建针对特定或所有模型的类工厂
- 自动导入定义的
默认数据
和states
从您的 Laravel 工厂 - 等等...
📺 我录制了一些 视频,以概述功能。
⚠️ 注意:对为什么需要基于类的工厂感兴趣?请在此处阅读 这里。
安装
您可以通过 composer 安装该软件包
composer require --dev christophrumpel/laravel-factories-reloaded
要发布配置文件,请运行
php artisan vendor:publish --provider="Christophrumpel\LaravelFactoriesReloaded\LaravelFactoriesReloadedServiceProvider"
它将提供软件包的配置文件,您可以在其中定义 模型的多个路径
、新生成的工厂的路径
、旧 Laravel 工厂的命名空间
,以及您的旧 Laravel 工厂的位置。
配置
Laravel 工厂命名空间
自 Laravel 8 以来,工厂已被命名空间化,默认的工厂命名空间为 Database\Factories
。如果您的 Laravel 工厂命名空间为 Database\Factories\ClassFactories
,您可以在配置文件中进行自定义,如下所示
'vanilla_factories_namespace' => 'Database\Factories\ClassFactories',
它将解析您的旧 Laravel 工厂类为 Database\Factories\ClassFactories\UserFactory
,而不是 Database\Factories\UserFactory
。
使用方法
生成工厂
首先,您需要为您的模型之一创建一个新的工厂类。这通过一个新的命令 make:factory-reloaded
完成。
php artisan make:factory-reloaded
您可以选择其中一个找到的模型或为所有模型创建工厂。
命令选项
如果您想通过命令本身定义选项,也可以这样做
php artisan make:factory-reloaded --models_path="app/Models" --factories_path="tests/ClassFactories" --factories_namespace="Tests\ClassFactories"
目前,您只能通过这种方式定义一个模型的位置。
定义默认模型数据
类似于 Laravel 工厂,您可以定义模型实例的默认数据。在您的新工厂中,有一个名为 getDefaults
的方法用于此目的。同样,也提供了 Faker
辅助工具来创建虚拟数据。
public function getDefaults(Faker $faker): array { return [ 'name' => $faker->name, 'email' => $faker->unique()->safeEmail, 'email_verified_at' => now(), 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 'remember_token' => Str::random(10), 'active' => false, ]; }
使用新工厂
假设您已创建了一个新的用户工厂。现在您可以使用它并创建一个新的用户实例。类似于 Laravel 工厂,create
方法将持久化到一个新的模型中。
$user = UserFactory::new()->create();
如果您想获取一个尚未持久化的实例,可以选择 make
方法。
$user = UserFactory::new()->make();
要创建多个实例,请在 create
或 make
方法之前链式调用 times()
方法。
$users = UserFactory::new() ->times(4) ->create();
状态
您可能在您的旧 Laravel 工厂中定义了状态。
$factory->state(User::class, 'active', function () { return [ 'active' => true, ]; });
在创建新的类工厂时,系统会询问您是否希望将这些状态导入到新的工厂中。如果同意,可以立即使用它们。状态 active
现在是您的 UserFactory
的一个方法。
$user = UserFactory::new() ->active() ->create();
关系
通常您需要使用相关模型创建一个新的模型实例。现在通过使用 with
方法,这变得相当简单。
$user = UserFactory::new() ->with(Recipe::class, 'recipes', 3) ->create();
这里我们得到了一个附有三个相关菜谱的用户实例。这里的第二个参数定义了关系名称。
⚠️ 注意:为了使此功能正常工作,您需要已经创建了一个新的 RecipeFactory。
您还可以在直接使用相关模型工厂时定义相关模型的额外属性。
$user = UserFactory::new() ->withFactory(RecipeFactory::new()->withCustomName(), 'recipes', 3) ->create();
您可以通过链式调用 with
来创建许多相关模型实例。
$recipe = RecipeFactory::new() ->with(Group::class, 'group') ->with(Ingredient::class, 'ingredients') ->with(Ingredient::class, 'ingredients', 3) ->create();
这里我们得到一个具有一个组和四个成分的菜谱。
⚠️ 注意:在版本 1.0.8 之前,只有最后一个
with
关系被构建。
在 Laravel 工厂中,您也可以在默认数据中定义相关模型,如下所示
$factory->define(Ingredient::class, function (Faker $faker) { return [ 'name' => $faker->name, 'recipe_id' => factory(Recipe::class), ]; });
这也可以在我们的新工厂类中实现。
public function getDefaults(Faker $faker): array { return [ 'name' => $faker->name, 'recipe_id' => factory(Recipe::class), ]; }
或者通过新工厂类的实例来做得更好。
public function getDefaults(Faker $faker): array { return [ 'name' => $faker->name, 'recipe_id' => RecipeFactory::new(), ]; }
⚠️ 注意:我不推荐使用这些选项,因为在测试中您看不到额外的模型被持久化。请使用提供的 "with" 方法为您自己创建一个创建关系的专用方法。
回调
在 Laravel 中,您可以为 afterCreating
和 afterMaking
定义工厂 回调
。您也可以用工厂类做类似的事情。由于 make
和 create
方法都在您的工厂类中,您可以在那里添加代码。
public function create(array $extra = []): Group { return $this->build($extra); } public function make(array $extra = []): Group { return $this->build($extra, 'make'); }
这取决于您想要实现什么,但就我个人而言,我会在工厂中添加一个方法,并在测试中调用它。这样,就可以更清楚地了解发生了什么。
不可变性
您可能已经注意到,当此包为您导入一个 状态
时,它会在返回之前克隆工厂。
public function active(): UserFactory { return tap(clone $this)->overwriteDefaults([ 'active' => true, ]); }
这适用于所有您将用于设置测试模型的方法。如果您不克隆工厂,您将始终修改工厂本身。这可能导致在使用同一个工厂时出现问题。
为了使整个工厂默认为不可变,请将 $immutable
属性设置为 true
。这样,每次状态更改都会自动返回一个克隆实例。
class UserFactory { protected string $modelClass = User::class; protected bool $immutable = true; // ... public function active(): UserFactory { return $this->overwriteDefaults([ 'active' => true, ]); } }
在某些情况下,您可能希望使用一个标准工厂作为不可变。这可以通过 immutable
方法来完成。
$factory = UserFactory::new() ->immutable(); $activeUser = $factory ->active() ->create(); $inactiveUser = $factory->create();
注意:
with
和withFactory
方法始终是不可变的。
还有什么
这些新工厂类最好的地方在于您 拥有
它们。您可以创建尽可能多的方法或属性来帮助您创建所需的特定实例。以下是一个更复杂的工厂调用的示例
UserFactory::new() ->active() ->onSubscriptionPlan(SubscriptionPlan::paid) ->withRecipesAndIngredients() ->times(10) ->create();
使用这样的工厂调用将帮助您的测试保持干净,并为每个人提供一个很好的概述。
为什么使用基于类的工厂?
- 它们在创建模型实例方面提供了更大的灵活性。
- 它们使测试变得更加干净,因为您可以将复杂的准备隐藏在类内部。
- 它们提供 IDE 自动完成功能,这是 Laravel 工厂所不具备的。
测试
composer test
更新日志
请参阅 更新日志 获取有关最近更改的更多信息。
贡献
请参阅 贡献指南 获取详细信息。
安全性
如果您发现任何安全相关的问题,请通过电子邮件 christoph@christoph-rumpel.com 而不是使用问题跟踪器。
鸣谢
一些实现受到了Brent关于如何处理Spatie工厂的文章的启发,该文章可参考Brent的文章。
同时,对Adrian表示衷心的感谢,他在重构此包方面给予了我很大帮助。
许可协议
MIT许可协议(MIT)。有关更多信息,请参阅许可文件。