承接 christophrumpel/laravel-factories-reloaded 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

christophrumpel/laravel-factories-reloaded

Composer 安装命令:

composer require christophrumpel/laravel-factories-reloaded

包简介

This package sits on top of Laravel factories and provides you with dedicated factory classes for every model.

README 文档

README

Latest Version on Packagist v1 Total Downloads MIT Licensed

This package generates class-based model factories, which you can use instead of the ones provided by Laravel.

Screenshot of the command

Laravel 8 Support

The new version v3 now supports Laravel 8 and PHP 8+. Since L8 changed their own implementation of factories a lot, this new v2 version ONLY works with Laravel 8. If you are not using L8 yet, use the latest 1.* version of this package, if you need PHP 7 support, use the latest 2.* version.

Benefits

  • use the features you already love from Laravel factories (create, make, times, states)
  • automatically create new class factories for specific or All your models
  • automatically import defined default data and states from your Laravel factories
  • and many more...

📺 I've recorded some videos to give you an overview of the features.

⚠️ Note: Interested in WHY you need class-based factories? Read here.

Installation

You can install the package via composer:

composer require --dev christophrumpel/laravel-factories-reloaded

To publish the config file run:

php artisan vendor:publish --provider="Christophrumpel\LaravelFactoriesReloaded\LaravelFactoriesReloadedServiceProvider"

It will provide the package's config file where you can define multiple paths of your models, the path of the newly generated factories, the namespace of your old Laravel factories, as well as where your old Laravel factories are located.

Configuration

Laravel Factories Namespace

Factories are namespaced since Laravel 8, and the default factories namespace is Database\Factories. If your laravel factories namespace is Database\Factories\ClassFactories, you can customize it at the config file as below:

'vanilla_factories_namespace' => 'Database\Factories\ClassFactories',

It will resolve your old laravel factory class as Database\Factories\ClassFactories\UserFactory, instead of Database\Factories\UserFactory.

Usage

Generate Factories

First, you need to create a new factory class for one of your models. This is done via a newly provided command called make:factory-reloaded.

php artisan make:factory-reloaded

You can pick one of the found models or create factories for all of them.

Command Options

If you want to define options through the command itself, you can do that as well:

php artisan make:factory-reloaded --models_path="app/Models"  --factories_path="tests/ClassFactories" --factories_namespace="Tests\ClassFactories"

Currently, you can only define one location for your models this way.

Define Default Model Data

Similar to Laravel factories, you can define default data for your model instances. Inside your new factories, there is a getDefaults method defined for that. The Faker helper to create dummy data is available as well.

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,
    ];
}

Use New Factories

Let's say you have created a new user factory. You can now start using it and create a new user instance. Similar to Laravel factories, the create method will persist in a new model.

$user = UserFactory::new()->create();

If you like to get an instance that is not persisted yet, you can choose the make method.

$user = UserFactory::new()->make();

To create multiple instances, you chain the times() method before the create or make method.

$users = UserFactory::new()
    ->times(4)
    ->create();

States

You may have defined states in your old Laravel factories.

$factory->state(User::class, 'active', function () {
    return [
        'active' => true,
    ];
});

While creating a new class factory, you will be asked if you like those states to be imported to your new factories. If you agree, you can immediately use them. The state active is now a method on your UserFactory.

$user = UserFactory::new()
    ->active()
    ->create();

Relations

Often you will need to create a new model instance with related models. This is now pretty simple by using the with method:

$user = UserFactory::new()
    ->with(Recipe::class, 'recipes', 3)
    ->create();

Here were are getting a user instance that has three related recipes attached. The second argument here defines the relationship name.

⚠️ Note: For this to work, you need to have a new RecipeFactory already created.

You can also define extras for the related models when using related model factories directly.

$user = UserFactory::new()
    ->withFactory(RecipeFactory::new()->withCustomName(), 'recipes', 3)
    ->create();

You can create many related models instances by chaining withs.

$recipe = RecipeFactory::new()
    ->with(Group::class, 'group')
    ->with(Ingredient::class, 'ingredients')
    ->with(Ingredient::class, 'ingredients', 3)
    ->create();

Here we are getting a recipe that has a group and four ingredients.

⚠️ Note: Up to the version 1.0.8, only the last with relation is built.

In Laravel factories, you could also define a related model in your default data like:

$factory->define(Ingredient::class, function (Faker $faker) {
    return [
        'name' => $faker->name,
        'recipe_id' => factory(Recipe::class),
    ];
});

This can also be achieved in our new factory classes.

public function getDefaults(Faker $faker): array
{
    return [
        'name' => $faker->name,
        'recipe_id' => factory(Recipe::class),
    ];
}

Or even better through an instance of a new factory class.

public function getDefaults(Faker $faker): array
{
    return [
        'name' => $faker->name,
        'recipe_id' => RecipeFactory::new(),
    ];
}

⚠️ Note: I wouldn't recommend any of these options because you do not see that additional models are persisted in your tests. Please use the given "with" method create a dedicated method for creating a relation yourself.

Callbacks

In Laravel, you are able to define factory callbacks for afterCreating and afterMaking. You can do something similar also with factory classes. Since both the make and create method are inside your factory class, you are free to add code there:

public function create(array $extra = []): Group
{
    return $this->build($extra);
}

public function make(array $extra = []): Group
{
    return $this->build($extra, 'make');
}

It depends on what you want to achive, but personally I would add a method to your factory which you call from within your test. This way it is more obvious what is happening.

Immutability

You might have noticed that when this package imports a state for you, it will clone the factory before returning.

public function active(): UserFactory
{
    return tap(clone $this)->overwriteDefaults([
        'active' => true,
    ]);
}

This is recommended for all methods which you will use to setup your test model. If you wouldn't clone the factory, you will always modify the factory itself. This could lead into problems when you use the same factory again.

To make a whole factory immutable by default, set the $immutable property to true. That way, every state change will automatically return a cloned instance.

class UserFactory
{
    protected string $modelClass = User::class;
    protected bool $immutable = true;

    // ...

    public function active(): UserFactory
    {
        return $this->overwriteDefaults([
            'active' => true,
        ]);
    }
}

In some context, you might want to use a standard factory as immutable. This can be done with the immutable method.

$factory = UserFactory::new()
    ->immutable();

$activeUser = $factory
    ->active()
    ->create();

$inactiveUser = $factory->create();

Note: with and withFactory methods are always immutable.

What Else

The best thing about those new factory classes is that you own them. You can create as many methods or properties as you like to help you create those specific instances that you need. Here is how a more complex factory call could look like:

UserFactory::new()
    ->active()
    ->onSubscriptionPlan(SubscriptionPlan::paid)
    ->withRecipesAndIngredients()
    ->times(10)
    ->create();

Using such a factory call will help your tests to stay clean and give everyone a good overview of what is happening here.

Why Class-Based Factories?

  • They give you much more flexibility on how to create your model instances.
  • They make your tests much cleaner because you can hide complex preparations inside the class.
  • They provide IDE auto-completion which you do not get have with Laravel factories.

Testing

composer test

Changelog

Please see CHANGELOG for more information about what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security

If you discover any security-related issues, please email christoph@christoph-rumpel.com instead of using the issue tracker.

Credits

Some of the implementations are inspired by Brent's article about how they deal with factories at Spatie.

And a big thanks goes out to Adrian who helped me a lot with refactoring this package.

License

The MIT License (MIT). Please see License File for more information.

christophrumpel/laravel-factories-reloaded 适用场景与选型建议

christophrumpel/laravel-factories-reloaded 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 47.76k 次下载、GitHub Stars 达 381, 最近一次更新时间为 2020 年 02 月 05 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「christophrumpel」 「laravel-factories-reloaded」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 christophrumpel/laravel-factories-reloaded 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 christophrumpel/laravel-factories-reloaded 我们能提供哪些服务?
定制开发 / 二次开发

基于 christophrumpel/laravel-factories-reloaded 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 47.76k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 381
  • 点击次数: 2
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 381
  • Watchers: 12
  • Forks: 19
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2020-02-05