承接 tobento/app-seeding 相关项目开发

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

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

tobento/app-seeding

Composer 安装命令:

composer require tobento/app-seeding

包简介

App seeding support.

README 文档

README

Seeding support for the app using the Seeder Service.

Table of Contents

Getting Started

Add the latest version of the app seeding project running this command.

composer require tobento/app-seeding

Requirements

  • PHP 8.4 or greater

Documentation

App

Check out the App Skeleton if you are using the skeleton.

You may also check out the App to learn more about the app in general.

Seeding Boot

The seeding boot does the following:

  • SeedInterface implementation
  • SeedersInterface implementation
  • adds console commands for seeding

The following seeders will be available:

Keep in mind that no Resources are set as they may be specific to your app needs. Therefore, the seeders mostly using the Lorem Seeder as fallback.

use Tobento\App\AppFactory;
use Tobento\Service\Seeder\SeedInterface;
use Tobento\App\Seeding\SeedersInterface;

// Create the app
$app = new AppFactory()->createApp();

// Add directories:
$app->dirs()
    ->dir(realpath(__DIR__.'/../'), 'root')
    ->dir(realpath(__DIR__.'/../app/'), 'app')
    ->dir($app->dir('app').'config', 'config', group: 'config')
    ->dir($app->dir('root').'vendor', 'vendor');

// Adding boots
$app->boot(\Tobento\App\Seeding\Boot\Seeding::class);
$app->booting();

// Available Interfaces:
$seed = $app->get(SeedInterface::class);
$seeders = $app->get(SeedersInterface::class);

// Run the app
$app->run();

Adding Seed Resources

You may add seeder resources by the following ways:

Globally by using the app on method

use Tobento\App\AppFactory;
use Tobento\Service\Seeder\SeedInterface;
use Tobento\Service\Seeder\Resource;

// Create the app
$app = new AppFactory()->createApp();

// Add directories:
$app->dirs()
    ->dir(realpath(__DIR__.'/../'), 'root')
    ->dir(realpath(__DIR__.'/../app/'), 'app')
    ->dir($app->dir('app').'config', 'config', group: 'config')
    ->dir($app->dir('root').'vendor', 'vendor');
    
// Adding boots
$app->boot(\Tobento\App\Seeding\Boot\Seeding::class);
$app->booting();

// Add resources:
$app->on(SeedInterface::class, function(SeedInterface $seed) {

    $seed->resources()->add(new Resource('countries', 'en', [
        'Usa', 'Switzerland', 'Germany',
    ]));
});

$seed = $app->get(SeedInterface::class);

var_dump($seed->country());
// string(7) "Germany"

// Run the app
$app->run();

Specific on any service using the seed

use Tobento\Service\Seeder\SeedInterface;
use Tobento\Service\Seeder\Resource;

class ServiceUsingSeed
{
    public function __construct(
        protected SeedInterface $seed,
    ) {
        $seed->resources()->add(new Resource('countries', 'en', [
            'Usa', 'Switzerland', 'Germany',
        ]));
    }
}

Factories

Creating Factories

You may create seed factories for testing or other purposes.

To create a factory, create a class that extends the AbstractFactory::class and configure your entity by using the definition method:

use Tobento\App\Seeding\AbstractFactory;

class UserFactory extends AbstractFactory
{
    public function definition(): array
    {
        return [
            'firstname' => $this->seed->firstname(),
            'role' => 'admin',
        ];
    }
}

Creating entities

You may use the createEntity method to create specific entites using the definition. By default, a stdClass class will be created.

use Tobento\App\Seeding\AbstractFactory;

class UserFactory extends AbstractFactory
{
    protected function createEntity(array $definition): object
    {
        return new User(
            firstname: $definition['firstname'],
        );
    }
}

Storing entities

By default, entities will not be stored. You may use the storeEntity method to store the entity based on the definition. In Addition, you may use getService method to get any service from the app container.

use Tobento\App\Seeding\AbstractFactory;

class UserFactory extends AbstractFactory
{
    protected function storeEntity(array $definition): object
    {
        return $this->getService(UserRepositoryInterface::class)
            ->create($definition);
    }
}

Using Factories

A factory can be created by calling the new method on the factory class:

$factory = UserFactory::new();

// you may overwrite the default definition:
$factory = UserFactory::new(['role' => 'editor']);

Make entities

The make method creates an array of entities and returns them for further use in code, but does not store them in the database e.g.

// make 10 entities:
$users = $factory->times(10)->make();

// make one:
$user = $factory->makeOne();

Create entities

The create method creates an array of entities, stores them in the database for instance and returns them for further use in the code.

// create 10 entities:
$users = $factory->times(10)->create();

// create one:
$user = $factory->createOne();

Raw entities

The raw method creates an array of attributes from definition only and returns them for further use in code.

// create 10:
$attributes = $factory->times(10)->raw();

// create one:
$attributes = $factory->rawOne();

Modify definition

You may modify the definition by using the modify method:

use Tobento\Service\Seeder\SeedInterface;

$users = $factory
    ->modify(fn (SeedInterface $seed, array $definition) => [
        'email' => $seed->email(),
    ])
    ->times(10)
    ->make();

You may use the method inside your factory class:

use Tobento\App\Seeding\AbstractFactory;
use Tobento\Service\Seeder\SeedInterface;

class UserFactory extends AbstractFactory
{
    public function withEmail(string $email): static
    {
        return $this->modify(fn(SeedInterface $seed, array $definition) => [
            'email' => $email
        ]);
    }
}

$users = $factory
    ->withEmail('admin@example.com')
    ->times(10)
    ->make();

Modify entity

You may modify the entity by using the modifyEntity method:

use Tobento\Service\Seeder\SeedInterface;

$users = $factory
    ->modifyEntity(static function (SeedInterface $seed, object $user) {
        return $user->markAsDeleted();
    })
    ->times(10)
    ->make();

You may use the method inside your factory class:

use Tobento\App\Seeding\AbstractFactory;
use Tobento\Service\Seeder\SeedInterface;

class UserFactory extends AbstractFactory
{
    public function deleted(string $email): static
    {
        return $this->modifyEntity(static function (SeedInterface $seed, object $user) {
            return $user->markAsDeleted();
        });
    }
}

$users = $factory
    ->deleted()
    ->times(10)
    ->make();

Seeders

You may create a seeder class to easily seed your application with test data.

Creating Seeders

To create a seeder, create a class that implements the SeederInterface::class:

use Tobento\App\Seeding\SeederInterface;

class UserSeeder implements SeederInterface
{
    public function run(): \Generator
    {
        foreach (UserFactory::new()->times(100)->create() as $user) {
            yield $user;
        }
    }
}

If you want to seed millions of test data, using factories my not be the fastest solution. Instead you may directly use the storage if available which is much faster.

Example using the user repository from the App User bundle:

use Tobento\App\Seeding\SeederInterface;
use Tobento\App\User\UserRepositoryInterface;
use Tobento\Service\Repository\Storage\StorageRepository;
use Tobento\Service\Iterable\ItemFactoryIterator;

class UserSeeder implements SeederInterface
{
    public function __construct(
        protected UserRepositoryInterface $userRepository,
    ) {
        if (! $userRepository instanceof StorageRepository) {
            throw new \InvalidArgumentException('Not supported ...');
        }
    }
    
    public function run(): \Generator
    {        
        yield from $this->userRepository
            ->query()
            ->chunk(length: 10000)
            ->insertItems(new ItemFactoryIterator(
                factory: function (): array {
                    return UserFactory::new()->definition();
                },
                create: 1000000,
            ));
    }
}

Adding Seeders

You may add seeders to be run by the app console using the app on method.

use Tobento\App\Seeding\SeedersInterface;

// ...

$app->on(
    SeedersInterface::class,
    static function (SeedersInterface $seeders): void {
        $seeders->addSeeder('users', UserSeeder::class);
    }
);

Running Seeders

To run your added seeders use the seed console command.

php ap seed

Run only specific seeders by its name

php ap seed --name=users

Display seeded entities

You may display the seeded entities with the verbosity option:

php ap seed -v

List all seeder names

You may display the seeder names by using the seed:list console command.

php ap seed:list

User Seeding

If you have installed the User App bundle you may use the provided user factory and user seeder.

User Factory

use Tobento\App\Seeding\User\UserFactory;

$user = UserFactory::new()
    ->withEmail('foo@example.com')
    ->withSmartphone('22334455')
    ->withUsername('Username')
    ->withPassword('123456')
    ->withRoleKey('admin') // 'guest' if role does not exist.
    ->withAddress(['firstname' => 'Firstname'])
    ->makeOne();

User Seeder

use Tobento\App\Seeding\User\UserStorageSeeder;

$app->on(
    SeedersInterface::class,
    static function (SeedersInterface $seeders): void {
        $seeders->addSeeder('users', UserStorageSeeder::class);
    }
);

Repository

You may easily create seed factories and seeders from any repository implementing the Repository Interface.

Creating Repository Factories

Using the repository factory

By using the RepositoryFactory::new method, you can quickly create a seed factory, which may be useful for testing purposes.

use Tobento\App\Seeding\Repository\RepositoryFactory;
use Tobento\Service\Repository\RepositoryInterface;
use Tobento\Service\Seeder\SeedInterface;
use Tobento\Service\Seeder\Lorem;

$factory = RepositoryFactory::new(
    repository: MyProductRepository::class, // string|RepositoryInterface
    definition: function (SeedInterface $seed): array {
        return [
            'sku' => Lorem::word(number: 1),
            'desc' => Lorem::sentence(number: 2),
        ];
    }
);

// using the factory:
$products = $factory->times(10)->make();

Storage Repositories with defined columns, will create the definition automatically based on the columns. You do not need to set a definition at all.

use Tobento\App\Seeding\Repository\RepositoryFactory;

$factory = RepositoryFactory::new(repository: MyProductRepository::class);

// using the factory:
$products = $factory->times(10)->make();

Check out the Using Factories section for more info using the factory in general.

Using the AbstractFactory

To create a factory, create a class that extends the AbstractFactory::class and use the REPOSITORY constant to define your repository class:

use Tobento\App\Seeding\Repository\AbstractFactory;

class ProductFactory extends AbstractFactory
{
    public const REPOSITORY = MyProductRepository::class;
}

// using the factory:
$products = ProductFactory::new()->times(10)->make();

Sure, you may customize the definition for more flexibility:

use Tobento\App\Seeding\Repository\AbstractFactory;

class ProductFactory extends AbstractFactory
{
    public function definition(): array
    {
        // you may call the parent if you have
        // repositories with columns so it will
        // automatically create the definition
        // based on the columns.
        $definition = parent::definition();
        
        // and just overwrite if needed:
        $definition['name'] = $this->seed->firstname();
        
        return $definition;
    }
}

Credits

tobento/app-seeding 适用场景与选型建议

tobento/app-seeding 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 100 次下载、GitHub Stars 达 0, 最近一次更新时间为 2023 年 12 月 13 日, 在 PHP 生态内属于活跃度较高的组件。

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

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

围绕 tobento/app-seeding 我们能提供哪些服务?
定制开发 / 二次开发

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

BUG 修复 & 性能优化

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

项目外包 & 长期维护

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

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

统计信息

  • 总下载量: 100
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 17
  • 依赖项目数: 1
  • 推荐数: 0

GitHub 信息

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

其他信息

  • 授权协议: MIT
  • 更新时间: 2023-12-13