spiral-packages/database-seeder

The package provides the ability to seed your database with data using seed classes

2.1.1 2022-08-08 19:22 UTC

This package is auto-updated.

Last update: 2022-11-24 20:25:27 UTC


README

PHP Latest Version on Packagist GitHub Tests Action Status Total Downloads

The package provides the ability to seed your database with data using seed classes.

Requirements

Make sure that your server is configured with following PHP version and extensions:

  • PHP 8.1+
  • Spiral framework ^3.0

Installation

You can install the package via composer:

composer require spiral-packages/database-seeder --dev

After package install you need to register bootloader from the package.

protected const LOAD = [
    // ...
    \Spiral\DatabaseSeeder\Bootloader\DatabaseSeederBootloader::class,
];

Note if you are using spiral-packages/discoverer, you don't need to register bootloader by yourself.

Usage

Creating entities by Factory

Provides the ability to easily create entities, for example, in tests in your application or packages.

You need to create a factory class, extend it from Spiral\DatabaseSeeder\Factory\AbstractFactory and implement two methods entity and definition. Method entity must return a fully qualified class name. Method definition must return an array with generation rules. Keys - properties in the target class. Values - property value or calling method that can generate property value (for example, method from Faker).

<?php

declare(strict_types=1);

namespace Database\Seeder;

use App\Entity\User;
use Spiral\DatabaseSeeder\Factory\AbstractFactory;

class UserFactory extends AbstractFactory
{
    public function entity(): string
    {
        return User::class;
    }
    
    public function makeEntity(array $definition): User
    {
        return new User($definition['username']);
    }

    public function admin(): self
    {
        return $this->state(fn(\Faker\Generator $faker, array $definition) => [
            'admin' => true,
        ]);
    }
    
    public function fromCity(string $city): self
    {
        return $this->state(fn(\Faker\Generator $faker, array $definition) => [
            'city' => $city,
        ]);
    }
    
    public function withBirthday(\DateTimeImmutable $date): self
    {
        return $this->entityState(static function (User $user) use ($date) {
            $user->birthday = $date;
            return $user;
        });
    }

    public function definition(): array
    {
        return [
            'firstName' => $this->faker->firstName(),
            'lastName' => $this->faker->lastName(),
            'birthday' => \DateTimeImmutable::createFromMutable($this->faker->dateTime()),
            'comments' => CommentFactory::new()->times(3)->make(), // Can use other factories.
            // Be careful, circular dependencies are not allowed!
        ];
    }
}

A factory can be created using the method new.

$factory = UserFactory::new();

A factory has several useful methods:

  • create - Creates an array of entities, stores them in the database, and returns them for further use in code.
  • createOne - Creates one entity, stores it in the database, and returns it for further use in code.
  • make - Creates an array of entities and returns them for further use in code.
  • makeOne - Creates one entity and returns it for further use in code.
  • raw - or data property. Used to get an array of entity data (raw data, without entity creation).

A few examples:

// 10 users stored in the database
$users = UserFactory::new()->times(10)->create();

// one user stored in the database
$user = UserFactory::new()->createOne();

// 10 users. Entities will not be saved to the database. Only returned for future use
$users = UserFactory::new()->times(10)->make();

// one user. Will not be saved to the database
$user = UserFactory::new()->makeOne();

// array with raw user data
$data = UserFactory::new()->raw();
// or
$data = UserFactory::new()->data;

// Create user with state based on attributes
$user = UserFactory::new()
    ->state(static fn(\Faker\Generator $faker) => ['admin' => $faker->bool])
    ->createOne();

// Create user with state based on entity object
$user = UserFactory::new()
    ->entityState(static function(User $user) {
        return $user->markAsDeleted();
    })
    ->createOne();

// Create user with state from UserFactory class
$user = UserFactory::new()->admin()->createOne();
$user = UserFactory::new()->fromCity('New York')->createOne();
$user = UserFactory::new()
    ->withBirthday(new \DateTimeImmutable('2010-01-01 00:00:00'))
    ->createOne();

Seeding

The package provides the ability to seed the database with test data. To do this, create a Seeder class and extend it from the Spiral\DatabaseSeeder\Seeder\AbstractSeeder class. Implement the run method. This method should return a generator with entities to store in the database.

<?php

declare(strict_types=1);

namespace Database\Seeder;

use Spiral\DatabaseSeeder\Seeder\AbstractSeeder;

class UserTableSeeder extends AbstractSeeder
{
    public function run(): \Generator
    {
        foreach (UserFactory::new()->times(100)->make() as $user) {
            yield $user;
        }
    }
}

Console commands

The package provides console commands to quickly create a factory, seeder, and perform seeding of a test database using seeder classes.

  • The Spiral\DatabaseSeeder\Console\Command\FactoryCommand console command is used to create a factory. The name of the factory is passed as an argument.
php ./app.php create:factory UserFactory
  • The Spiral\DatabaseSeeder\Console\Command\SeederCommand console command is used to create a seeder. The name of the seeder is passed as an argument.
php ./app.php create:seeder UserSeeder
  • The Spiral\DatabaseSeeder\Console\Command\SeedCommand console command is used to perform seeding of a test database using seeder classes.
php ./app.php db:seed

Testing applications with database

The package provides several additional features for easier testing of applications with databases.

Note Important! Be sure to set up a test database in the test application. Never use a production database for testing!

To use these features, your application's tests must be written using the spiral/testing package.

First of all, inherit the base test class that is used in tests using the new functionality. This will make it possible to use traits to simplify working with the database in tests and provide additional methods for testing. Example:

<?php

declare(strict_types=1);

namespace Tests\Feature;

abstract class TestCase extends \Spiral\DatabaseSeeder\TestCase
{
}

Next, you can add some traits:

RefreshDatabase

This trait creates the database structure on a first run and wraps the test execution into a transaction. After the test runs, the transaction is rollback, but the database structure is saved for use in the next test.

<?php

declare(strict_types=1);

namespace Tests\Feature;

use Spiral\DatabaseSeeder\Database\Traits\RefreshDatabase;

abstract class TestCase extends \Spiral\DatabaseSeeder\TestCase
{
    use RefreshDatabase;
}

DatabaseMigrations

This trait creates a database structure, performs a test, and completely rollback the state of the database.

<?php

declare(strict_types=1);

namespace Tests\Feature;

use Spiral\DatabaseSeeder\Database\Traits\DatabaseMigrations;

abstract class TestCase extends \Spiral\DatabaseSeeder\TestCase
{
    use DatabaseMigrations;
}

DatabaseAsserts

This trait is enabled by default in Spiral\DatabaseSeeder\TestCase. Provides additional assertions for checking data in a database. Available methods:

  • assertTableExists - Checks if a table exists in a database
  • assertTableIsNotExists - Checks if the table is not in the database
  • assertTableCount - Checks if a table has a certain number of records
  • assertTableHas - Checks if there is a record in a table that matches a certain condition
  • assertEntitiesCount - same as assertTableCount, but checks by entity, not by table name
  • assertTableHasEntity - same as assertTableHas, but checks by entity, not by table name

Testing

composer test

Changelog

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

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

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