承接 directorytree/dummy 相关项目开发

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

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

directorytree/dummy

Composer 安装命令:

composer require directorytree/dummy

包简介

README 文档

README

Generate PHP class instances populated with fake dummy data using Faker

Index

Requirements

  • PHP >= 8.0

Installation

You can install the package via composer:

composer require directorytree/dummy --dev

Upgrading

From v1 to v2

Dummy v2 renames the trait API so it is explicitly Dummy-owned and does not reserve the common factory() method name on your classes.

  1. Replace DirectoryTree\Dummy\HasFactory with DirectoryTree\Dummy\HasDummyFactory.
  2. Replace use HasFactory; with use HasDummyFactory;.
  3. Replace YourClass::factory() calls with YourClass::dummy().
  4. Rename toFactoryInstance to toDummyInstance.
  5. Rename getFactoryDefinition to getDummyDefinition.
  6. Change the toDummyInstance argument from array to DirectoryTree\Dummy\DummyData.

Before:

use DirectoryTree\Dummy\HasFactory;

class Reservation
{
    use HasFactory;

    protected static function toFactoryInstance(array $attributes): static
    {
        return new static(
            $attributes['name'],
            $attributes['email'],
        );
    }
}

$reservation = Reservation::factory()->make();

After:

use DirectoryTree\Dummy\DummyData;
use DirectoryTree\Dummy\HasDummyFactory;

class Reservation
{
    use HasDummyFactory;

    protected static function toDummyInstance(DummyData $attributes): static
    {
        return new static(
            $attributes['name'],
            $attributes['email'],
        );
    }
}

$reservation = Reservation::dummy()->make();

If your constructor or factory method needs a plain array, call all():

protected static function toDummyInstance(DummyData $attributes): static
{
    return new static($attributes->all());
}

You can also replace manual array access with helper methods where useful:

$attributes->get('profile.name');
$attributes->filled('email');
$attributes->boolean('active');
$attributes->integer('visits');
$attributes->enum('status', Status::class);
$attributes->enums('roles', Role::class);
$attributes->only(['name', 'email']);
$attributes->except('password');

State callbacks, attribute closures, raw(), and custom Factory::generate(array $attributes) methods continue to receive plain arrays.

Introduction

Consider you have a class representing a restaurant reservation:

namespace App\Data;

class Reservation
{
    public function __construct(
        public string $name,
        public string $email,
        public DateTime $date,
    ) {}
}

To make dummy instances of this class during testing, you have to manually populate it with dummy data.

This can quickly get out of hand as your class grows, and you may find yourself writing the same dummy data generation code over and over again.

Dummy provides you with a simple way to generate dummy instances of your classes using a simple API:

// Generate one instance:
$reservation = Reservation::dummy()->make();

// Generate multiple instances:
$collection = Reservation::dummy()->count(5)->make();

Setup

Dummy provides you two different ways to generate classes with dummy data.

HasDummyFactory Trait

The HasDummyFactory trait is applied directly to the class you would like to generate dummy instances of.

To use the HasDummyFactory trait, you must implement the toDummyInstance and getDummyDefinition methods:

namespace App\Data;

use DateTime;
use Faker\Generator;
use DirectoryTree\Dummy\DummyData;
use DirectoryTree\Dummy\HasDummyFactory;

/**
 * @use HasDummyFactory<Reservation>
 */
class Reservation
{
    use HasDummyFactory;
    
    /**
     * Constructor.
     */
    public function __construct(
        public string $name,
        public string $email,
        public DateTime $date,
    ) {}
    
    /**
     * Define the factory's default state.
     */
    protected static function getDummyDefinition(Generator $faker): array
    {
        return [
            'name' => $faker->name(),
            'email' => $faker->email(),
            'datetime' => $faker->dateTime(),
        ];
    }
    
    /**
     * Create a new instance of the class using the factory definition.
     */
    protected static function toDummyInstance(DummyData $attributes): static
    {
        return new static(
            $attributes['name'],
            $attributes['email'],
            $attributes['datetime'],
        );
    }
}

The $attributes argument passed into toDummyInstance is a DirectoryTree\Dummy\DummyData instance. It supports array access and common data helpers, such as get, has, filled, notFilled, boolean, integer, enum, enums, only, except, collect, and all.

Once implemented, you may call the Reservation::dummy() method to create a new dummy factory:

$factory = Reservation::dummy();

Dynamic State Methods

The HasDummyFactory trait supports defining dynamic state methods. You can define state methods in your class using the format get{StateName}State and call them dynamically on the factory:

namespace App\Data;

use DateTime;
use Faker\Generator;
use DirectoryTree\Dummy\DummyData;
use DirectoryTree\Dummy\HasDummyFactory;

/**
 * @use HasDummyFactory<Reservation>
 */
class Reservation
{
    use HasDummyFactory;

    public function __construct(
        public string $name,
        public string $email,
        public DateTime $datetime,
        public string $status = 'pending',
        public string $type = 'standard',
    ) {}

    // Dynamic state methods...

    public static function getConfirmedState(): array
    {
        return ['status' => 'confirmed'];
    }

    public static function getPremiumState(): array
    {
        return [
            'type' => 'premium',
            'status' => 'confirmed',
        ];
    }

    public static function getCancelledState(): array
    {
        return ['status' => 'cancelled'];
    }

    protected static function toDummyInstance(DummyData $attributes): self
    {
        return new static(
            $attributes['name'],
            $attributes['email'],
            $attributes['datetime'],
            $attributes['status'] ?? 'pending',
            $attributes['type'] ?? 'standard',
        );
    }

    protected static function getDummyDefinition(Generator $faker): array
    {
        return [
            'name' => $faker->name(),
            'email' => $faker->email(),
            'datetime' => $faker->dateTime(),
        ];
    }
}

You can then use these state methods dynamically:

// Create a confirmed reservation
$confirmed = Reservation::dummy()->confirmed()->make();

// Create a premium reservation
$premium = Reservation::dummy()->premium()->make();

// Chain multiple states
$premiumCancelled = Reservation::dummy()->premium()->cancelled()->make();

Class Factory

If you need more control over the dummy data generation process, you may use the Factory class.

The Factory class is used to generate dummy instances of a class using a separate factory class definition.

To use the Factory class, you must extend it with your own and override the definition and generate methods:

namespace App\Factories;

use App\Data\Reservation;
use DirectoryTree\Dummy\Factory;

/**
 * @extends Factory<Reservation>
 */
class ReservationFactory extends Factory
{
    /**
     * Define the factory's default state.
     */
    protected function definition(): array
    {
        return [
            'name' => $this->faker->name(),
            'email' => $this->faker->email(),
            'datetime' => $this->faker->dateTime(),
        ];
    }
    
    /**
     * Generate a new instance of the class.
     */
    protected function generate(array $attributes): Reservation
    {
        return new Reservation(
            $attributes['name'],
            $attributes['email'],
            $attributes['datetime'],
        );
    }
}

Usage

Once you've defined a factory, you can generate dummy instances of your class using the make method:

// Using the trait:
$reservation = Reservation::dummy()->make();

// Using the factory class:
$reservation = ReservationFactory::new()->make();

To add or override attributes in your definition, you may pass an array of attributes to the make method:

$reservation = Reservation::dummy()->make([
    'name' => 'John Doe',
]);

To generate multiple instances of the class, you may use the count method:

This will return an Illuminate\Support\Collection instance containing the generated classes.

$collection = Reservation::dummy()->count(5)->make();

If you have a counted factory but need one instance, use makeOne:

$reservation = Reservation::dummy()->count(5)->makeOne();

To make several instances with a different state record for each one, use makeMany:

$collection = Reservation::dummy()->makeMany([
    ['name' => 'Taylor Otwell'],
    ['name' => 'Nuno Maduro'],
]);

You may also defer generation by creating a lazy callback:

$makeReservation = Reservation::dummy()->lazy([
    'name' => 'John Doe',
]);

$reservation = $makeReservation();

Factory States

State manipulation methods allow you to define discrete modifications that can be applied to your dummy factories in any combination.

For example, your App\Factories\Reservation factory might contain a tomorrow state method that modifies one of its default attribute values:

class ReservationFactory extends Factory
{
    // ...

    /**
     * Indicate that the reservation is for tomorrow.
     */
    public function tomorrow(): Factory
    {
        return $this->state(function (array $attributes) {
            return ['datetime' => new DateTime('tomorrow')];
        });
    }
}

You may prepend a state when you need it evaluated before the factory's existing states:

$reservation = Reservation::dummy()
    ->tomorrow()
    ->prependState([
        'name' => 'Early State',
    ])
    ->make();

Eloquent Attributes

When Laravel's Eloquent is installed, Dummy will expand Eloquent model instances and factories into model keys:

use App\Models\Company;
use App\Models\User;

$reservation = Reservation::dummy()->make([
    'company_id' => Company::factory(),
    'user_id' => User::factory()->create(),
]);

This also works for values returned from attribute closures, so dependent attributes can use previously expanded keys:

$reservation = Reservation::dummy()->make([
    'company_id' => Company::factory(),
    'user_id' => fn (array $attributes) => User::factory([
        'company_id' => $attributes['company_id'],
    ]),
]);

Factory Callbacks

Factory callbacks are registered using the afterMaking method and allow you to perform additional tasks after making or creating a class. You should register these callbacks by defining a configure method on your factory class. This method will be automatically called when the factory is instantiated:

class ReservationFactory extends Factory
{
    // ...
    
    /**
     * Configure the dummy factory.
     */
    protected function configure(): static
    {
        return $this->afterMaking(function (Reservation $reservation) {
            // ...
        });
    }
}

You may remove configured afterMaking callbacks for a single factory chain with withoutAfterMaking:

$reservation = ReservationFactory::new()
    ->withoutAfterMaking()
    ->make();

Factory Sequences

Sometimes you may wish to alternate the value of a given attribute for each generated class.

You may accomplish this by defining a state transformation as a sequence:

Reservation::dummy()
    ->count(3)
    ->sequence(
        ['datetime' => new Datetime('tomorrow')],
        ['datetime' => new Datetime('next week')],
        ['datetime' => new Datetime('next month')],
    )
    ->make();

Factory Collections

By default, when making more than one dummy class, an instance of Illuminate\Support\Collection will be returned.

If you need to customize the collection of classes generated by a factory, you may override the collect method:

class ReservationFactory extends Factory
{
    // ...
    
    /**
     * Create a new collection of classes.
     */
    public function collect(array $instances = []): ReservationCollection
    {
        return new ReservationCollection($instances);
    }
}

Factory Macros

Factories are macroable, allowing you to register reusable factory helpers:

use DirectoryTree\Dummy\Factory;

Factory::macro('named', function (string $name) {
    return $this->state([
        'name' => $name,
    ]);
});

$reservation = Reservation::dummy()->named('John Doe')->make();

IDE Type Inference

Dummy includes generic PHPDoc annotations so static analysis tools and IDEs can infer factory return types.

When using the HasDummyFactory trait, add an @use annotation to your class:

/**
 * @use HasDummyFactory<Reservation>
 */
class Reservation
{
    use HasDummyFactory;

    // ...
}

When using a dedicated factory class, add an @extends annotation:

/**
 * @extends Factory<Reservation>
 */
class ReservationFactory extends Factory
{
    // ...
}

These annotations allow tools to infer that Reservation::dummy()->makeOne() and ReservationFactory::new()->makeOne() return a Reservation instance.

directorytree/dummy 适用场景与选型建议

directorytree/dummy 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 9.71k 次下载、GitHub Stars 达 41, 最近一次更新时间为 2024 年 12 月 15 日, 在 PHP 生态内属于活跃度较高的组件。

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

围绕 directorytree/dummy 我们能提供哪些服务?
定制开发 / 二次开发

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

BUG 修复 & 性能优化

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

项目外包 & 长期维护

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

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

统计信息

  • 总下载量: 9.71k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 41
  • 点击次数: 7
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 41
  • Watchers: 1
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2024-12-15