DownloadMigrations
Back to README
Table of Contents
Using migrations
?? Go to TOC
Command can generate a full domain directory structure starting from an
existing database migration.
The command will parse the migration and map all fields in the data transfer object, projection and projector.
Important: the command can process _only_ "create" migrations. Other migrations that modify table structure will be
skipped.
Generate a domain using existing migration
?? Go to TOC
Command can generate a full domain directory structure starting from an existing migration.
E.g. migration 2024_10_01_112344_create_tigers_table.php
return new class extends Migration
{
/
* Run the migrations.
*/
public function up(): void
{
Schema::create('tigers', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name')->index();
$table->int('age');
$table->json('meta');
$table->timestamps();
});
}
// etc.
};
In this example, id will be used as primary key. No aggregate will be available.
It is possible to specify the migration interactively or, more efficiently, passing it to command options. Please notice
that the migration filename timestamp is not needed:
php artisan make:event-sourcing-domain Tiger --domain=Animal --migration=create_tigers_table --notifications=slack --failed-events=1 --reactor=0 --unit-test
Your choices:
| Option | Choice |
|----------------------------|--------------------------------------------|
| Model | Tiger |
| Domain | Animal |
| Namespace | Domain |
| Use migration | 2024_10_01_112344_create_animals_table.php |
| Primary key | id |
| Create Aggregate class | no |
| Create Reactor class | no |
| Create PHPUnit tests | yes |
| Create failed events | yes |
| Model properties | string name |
| | int age |
| | array meta |
| Notifications | yes |
Do you confirm the generation of the domain?
> yes
Domain [Animal] with model [Tiger] created successfully.
Directory structure generated (using id as primary key)
app/
??? Domain/
? ??? Animal/
? ??? Actions/
? ? ??? CreateTiger
? ? ??? DeleteTiger
? ? ??? UpdateTiger
? ??? DataTransferObjects/
? ? ??? TigerData
? ??? Events/
? ? ??? TigerCreated
? ? ??? TigerCreationFailed
? ? ??? TigerDeleted
? ? ??? TigerDeletionFailed
? ? ??? TigerUpdateFailed
? ? ??? TigerUpdated
? ??? Notifications/
? ? ??? Concerns/
? ? ? ??? HasDataAsArray
? ? ? ??? HasSlackNotification
? ? ??? TigerCreated
? ? ??? TigerCreationFailed
? ? ??? TigerDeleted
? ? ??? TigerDeletionFailed
? ? ??? TigerUpdateFailed
? ? ??? TigerUpdated
? ??? Projections/
? ? ??? Tiger
? ??? Projectors/
? ??? TigerProjector
??? etc.
tests/
??? Unit/
? ??? Domain/
? ??? Animal/
? ??? TigerTest.php
??? etc.
If Spatie event sourcing is configured to auto-discover projectors, that is immediately usable:
use App\Domain\Animal\Actions\CreateTiger;
use App\Domain\Animal\DataTransferObjects\TigerData;
use App\Domain\Animal\Projections\Tiger;
# This will create a record in 'tigers' table, using projector TigerProjector
(new CreateTiger())(new TigerData(
name: 'tiger',
age: 7,
meta: []
));
# Retrieve record
$tiger = Tiger::query()->where('name', 'tiger')->first();
Generate a domain using update migration
?? Go to TOC
Command can generate a full domain directory structure starting from an update migration.
It is possible to exclude one or more specific update migrations, using a string or regular expression. See next
example.
E.g. create migration 2024_10_01_112344_create_tigers_table.php
return new class extends Migration
{
/
* Run the migrations.
*/
public function up(): void
{
Schema::create('tigers', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name')->index();
$table->int('age');
$table->json('meta');
$table->timestamps();
});
}
// etc.
};
E.g. update migration 2024_10_07_031123_update_tigers_table.php
return new class extends Migration
{
/
* Run the migrations.
*/
public function up(): void
{
Schema::create('tigers', function (Blueprint $table) {
$table->float('age');
$table->string('colour');
});
}
// etc.
};
In this example, id will be used as primary key. No aggregate will be available.
Important: to parse both create and update migrations, pass the _table name_ in the --migration parameter. That
will search for all migrations containing that name. Words create and update are reserved and cannot be passed.
It is possible to specify the migration interactively or, more efficiently, passing it to command options. Please notice
that the migration filename timestamp is not needed:
php artisan make:event-sourcing-domain Tiger --domain=Animal --migration=tigers --notifications=slack --failed-events=1 --reactor=0 --unit-test
Your choices:
| Option | Choice |
|----------------------------|--------------------------------------------|
| Model | Tiger |
| Domain | Animal |
| Namespace | Domain |
| Use migration | 2024_10_01_112344_create_animals_table.php |
| | 2024_10_07_031123_update_tigers_table.php |
| Primary key | id |
| Create Aggregate class | no |
| Create Reactor class | no |
| Create PHPUnit tests | yes |
| Create failed events | yes |
| Model properties | string name |
| | int age |
| | array meta |
| Notifications | yes |
Do you confirm the generation of the domain?
> yes
Domain [Animal] with model [Tiger] created successfully.
Generate a domain using update migration excluding some specific migration
?? Go to TOC
Command can generate a full domain directory structure starting from an update migration, excluding specific
migration(s) with the option --migration-exclude.
E.g. create migration 2024_10_01_112344_create_tigers_table.php
return new class extends Migration
{
/
* Run the migrations.
*/
public function up(): void
{
Schema::create('tigers', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name')->index();
$table->int('age');
$table->json('meta');
$table->timestamps();
});
}
// etc.
};
E.g. update migration #1 2024_10_07_031123_update_tigers_table.php
return new class extends Migration
{
/
* Run the migrations.
*/
public function up(): void
{
Schema::create('tigers', function (Blueprint $table) {
$table->float('age');
});
}
// etc.
};
E.g. update migration #2 2024_10_07_031124_drop_age_column_from_tigers_table.php (we do not want to include this)
return new class extends Migration
{
/
* Run the migrations.
*/
public function up(): void
{
Schema::create('tigers', function (Blueprint $table) {
$table->dropColumn('age');
});
}
// etc.
};
E.g. update migration #3 2024_10_07_031125_drop_meta_column_from_tigers_table.php (we do not want to include this)
return new class extends Migration
{
/
* Run the migrations.
*/
public function up(): void
{
Schema::create('tigers', function (Blueprint $table) {
$table->dropColumn('meta');
});
}
// etc.
};
The excluded migration can be passed in two ways:
-
filename
-
valid regular expression
Passing exluded migration as filename
php artisan make:event-sourcing-domain Tiger --domain=Animal --migration=tigers --migration-exclude=drop_age_column_from_tigers --notifications=slack --failed-events=1 --reactor=0 --unit-test
Only migrations listed as parsed will be processed:
| Migration | Parsed | Excluded |
|----------------------------------------------------------|--------|----------|
| 2024_10_01_112344_create_tigers_table.php | yes | |
| 2024_10_07_031123_update_tigers_table.php | yes | |
| 2024_10_07_031124_drop_age_column_from_tigers_table.php | | yes |
| 2024_10_07_031125_drop_meta_column_from_tigers_table.php | yes | |
Passing exclude migration(s) as regex
php artisan make:event-sourcing-domain Tiger --domain=Animal --migration=tigers --migration-exclude="/_drop/" --notifications=slack --failed-events=1 --reactor=0 --unit-test
Only migrations listed as parsed will be processed:
| Migration | Parsed | Excluded |
|----------------------------------------------------------|--------|----------|
| 2024_10_01_112344_create_tigers_table.php | yes | |
| 2024_10_07_031123_update_tigers_table.php | yes | |
| 2024_10_07_031124_drop_age_column_from_tigers_table.php | | yes |
| 2024_10_07_031125_drop_meta_column_from_tigers_table.php | | yes |
Limitations
?? Go to TOC
Unsupported column types
?? Go to TOC
The following column types are not yet supported:
-
primary composite keys e.g. `$table->primary(['id', 'parent_id']);`
-
`binary`
-
`foreignIdFor`
-
`foreignUlid`
-
`geography` (from Laravel 11.x)
-
`geometry`
-
`morphs`
-
`nullableMorphs`
-
`nullableUlidMorphs`
-
`nullableUuidMorphs`
-
`set`
-
`ulidMorphs`
-
`uuidMorphs`
-
`ulid`
If the database migration contains any of those:
-
a warning will be generated in command line output for each of those
-
a @todo comment will be added for each of those in the data transfer object, projection and projector.
E.g. migration 2024_10_01_112344_create_lions_table.php
php artisan make:event-sourcing-domain Lion --domain=Animal --migration=create_lions_table
return new class extends Migration
{
/
* Run the migrations.
*/
public function up(): void
{
Schema::create('lions', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name')->index();
$table->int('age');
$table->ulidMorphs('taggable');
$table->timestamps();
});
}
// etc.
};
Data Transfer Object
namespace App\Domain\Animal\DataTransferObjects;
class LionData
{
public function __construct(
public string $name,
public int $age,
// @todo public ulidMorphs $taggable, column type is not yet supported,
) {}
// etc.
}
Projection
namespace App\Domain\Animal\Projections;
/
* @property int $id
* @property string $name
* @property int $age
*/
class Lion extends Projection
{
protected $primaryKey = 'id';
protected $fillable = [
'id',
'name',
'age',
// @todo 'taggable', column type 'ulidMorphs' is not yet supported
];
protected $casts = [
'id' => 'int',
'name' => 'string',
'age' => 'int',
// @todo 'taggable' => 'ulidMorphs', column type is not yet supported
];
// etc.
}
Projector
namespace App\Domain\Animal\Projectors;
class AnimalProjector extends Projector
{
public function onLionCreated(LionCreated $event): void
{
try {
(new Animal)->writeable()->create([
'name' => $event->lionData->name,
'age' => $event->lionData->age,
// @todo 'taggable' => $event->lionData->taggable, column type 'ulidMorphs' is not yet supported
]);
} catch (Exception $e) {
Log::error('Unable to create animal', [
'error' => $e->getMessage(),
'event' => $event,
]);
}
}
// etc.
}
|