reedware / laravel-seeders
Adds the ability to generate and seed from seed data.
Requires
- php: ^8.0
- illuminate/console: ^9.0|^10.0
- illuminate/container: ^9.0|^10.0
- illuminate/database: ^9.0|^10.0
- illuminate/http: ^9.0|^10.0
- illuminate/support: ^9.0|^10.0
Requires (Dev)
- laravel/pint: ^1.10
- orchestra/testbench: ^7.0|^8.0
- phpstan/phpstan: ^1.4.7
This package is auto-updated.
Last update: 2024-10-27 01:44:31 UTC
README
This package adds the ability to generate and seed from seed data.
Introduction
Seeders in Laravel are great for seeding fake data, but that's not their only use case. Seeders are also often used for seeding the boilerplate application data used in glossary type tables (e.g. enumerables, drop-down options, etc.), or tables managed by developers (e.g. roles, permissions, etc.). However, when seeding boilerplate data, there can be a number of complications that arise over time. This package aims to provide seeding application data, and solves the following complications that come with it:
- You want to seed an initial data set, and let the application manage the rest
- You want to seed an initial data set, occasional new entries, and let the application manage the rest
- You want the seeders to have full control over a table
- You want to manage a table through seeding, except for a few columns
Installation
Composer
This package can be installed using composer:
composer require reedware/laravel-seeders
Service Provider
This package uses auto-discovery to register its service provider. If you choose to manually register the provider, here's the full class path:
'providers' => [ /* ... */ Reedware\LaravelSeeders\SeederServiceProvider::class /* ... */ ]
Facade
This package uses auto-discover to register its facade. If you choose to manually register the facade, here's the default binding:
'aliases' => [ 'Seed' => Reedware\LaravelSeeders\Seed::class ]
If you wish to avoid using the facade, you can obtain the underlying instance through the IoC Container:
app('db.seed') // or app(Reedware\LaravelSeeders\Contracts\Factory::class)
Usage
Basic Example
To create your first seeder, start by creating a new seeder like so:
<?php use Reedware\LaravelSeeders\ResourceSeeder; class PermissionSeeder extends ResourceSeeder { /** * The model this resource corresponds to. * * @var string */ public static $model = \App\Models\Permission::class; /** * The attributes to match when creating or updating records. * * @var array */ public static $match = ['name']; /** * The columns to used order the resources in storage. * * @var array */ public static $orderBy = ['name' => 'asc']; }
In this example, the seeder will generate seed data from the permissions
table (derived from the model), and order the line items by the name
attribute. When the seeder is used to seed from the source data, it will match existing permissions by the name
property, and update them accordingly.
Allowed Operations
By default, resource seeders will perform the following operations upon seeding:
- Create database records that for seed data records that don't have a corresponding database record
- Update database records that do have corresponding seed data records
- Delete database records that aren't listed in the seed data
In this operation mode, the seed data is considered to be the source of truth for the database table.
However, you can disable any of the operations like so:
<?php use Reedware\LaravelSeeders\ResourceSeeder; class MySeeder extends ResourceSeeder { /* ... */ /** * Whether or not new records in storage can be inserted into the database. * * @var boolean */ public static $allowCreating = true; /** * Whether or not existing records in storage can be updated within the database. * * @var boolean */ public static $allowUpdating = true; /** * Whether or not missing records in storage can be deleted from the database. * * @var boolean */ public static $allowDeleting = true; }
Here are the effects of disabling each operation:
- When creating is disabled, no new database records will be created, even if the seed data contains unmatched records
- When updating is disabled, existing records won't be updated (new records can still be created if creating is enabled)
- When deleting is disabled, no database records will be deleted, even if no matching seed data record exists
Soft Deletion
When a seeded model soft deletes, the behavior of the seeder changes in the following ways:
- Soft deleted database records are still included in seed data generation
- The "deleted_at" column is mapped to a "trashed" boolean in the seed data
- Deletions while seeding execute as soft deletions, providing a fresh timestamp at the time of seeding
Hard Deletion
When a database record is being deleted, it may have foreign key associations that prevent its deletion. Deletion through seeding deletes through the model, rather than a database query, so that you can leverage the Model::deleting(...)
event hook to remove or unlink any relationships that would prevent its deletion.
Primary Keys
By default, seeders do not respect or enforce primary keys. If you wish to generate and seed primary keys, you can enable them like so:
<?php use Reedware\LaravelSeeders\ResourceSeeder; class MySeeder extends ResourceSeeder { /* ... */ /** * Whether or not to omit the primary key. * * @var boolean */ public static $omitPrimaryKey = false; }
Column Mapping
If you want to change the generation ouput and the seeder intake, you can customize the following methods within your seeder:
<?php use Reedware\LaravelSeeders\ResourceSeeder; class MySeeder extends ResourceSeeder { /* ... */ /** * Maps the model attributes to stored attributes. * * @param array $attributes * * @return array */ public static function mapAttributes(array $attributes) { $attributes = parent::mapAttributes($attributes); $parts = explode(' ', $attributes['full_name']); $attributes['first_name'] = array_shift($parts); $attributes['last_name'] = $parts; return $attributes; } /** * Unmaps stored attributes to model attributes. * * @param array $attributes * * @return array */ public static function unmapAttributes(array $attributes) { $attributes = parent::unmapAttributes($attributes); $attributes['full_name'] = $attributes['first_name'] . ' ' . $attributes['last_name']; } }
Column Omission
If you want to prevent specific columns from being seeded, you can omit them in your resource seeder:
<?php use Reedware\LaravelSeeders\ResourceSeeder; class MySeeder extends ResourceSeeder { /* ... */ /** * Additional columns to omit when seeding. * * @var array */ public static $omit = [ 'pretend' ]; }
Environment Specific Behavior
The configuration options for each resource seeder has been shown using a property. If you want to have environment specific behavior, you won't be able to use properties to do that. Luckily, each property has a corresponding method that you can leverage instead:
<?php use Reedware\LaravelSeeders\ResourceSeeder; class MySeeder extends ResourceSeeder { /* ... */ /** * Returns whether or not existing records in storage can be updated within the database. * * @return boolean */ public static function allowUpdating() { return app()->environment() !== 'production'; } }
Commands
To seed using a seeder from this package, you can call the traditional php artisan db:seed --class="MyDatabaseSeeder
command.
To generate seed data based on table contents, you can call the new php artisan db:seed:generate --class="MyDatabaseSeeder
command.
Data Storage
The data you want to seed into your application should be housed within your source code, and therefore maintained under version control. The location and format of the seed data is customizable if you aren't comfortable with the default configuration.
Root Path
By default, this package places your seed data within a new ~/database/seeders/data
directory. If you wish to customize this location, you can tap into the Seed
facade:
<?php use Illuminate\Support\ServiceProvider; use Seed; class AppServiceProvider extends ServiceProvider { public function boot() { Seed::setRootPath('where/ever/you/want'); } }
Model Mapping
This package uses your models as reference to the source tables, as it detected soft deletion, timestamp usage, and other features that are already configured by your models. Your model is also used to name the seed data file, by converting the model based name to plural snake case (e.g. "MyModel" becomes "my-models.csv").
If you wish to override a particular model, you can tap into the Seed
facade:
Seed::filename(MyModel::class, 'my-filename.csv');
Alternatively, if you wish to customize the default convention, you redefine it:
Seed::guessFilenamesUsing(function($class) { return $class . '.csv'; });
File Format
This package uses csv files as external storage, but you may prefer another format. You can override the file reader and writer to use whichever format you prefer:
Custom Reader:
<?php use Reedware\LaravelSeeders\Contracts\Reader; class MyReader implements Reader { // } Seed::readUsing(function($filename) { return new MyReader($filename); });
Custom Writer:
<?php use Reedware\LaravelSeeders\Contracts\Writer; class MyWriter implements Writer { // } Seed::writeUsing(function($filename) { return new MyWriter($filename); });