Installation
Run composer require domain-engine/toolkit in your Laravel project.
While this is a Symfony bundle, Laravel can integrate it via Symfony Bridge or by manually adapting its components.
Enable Core Functionality
Register the bundle in config/app.php under providers:
'providers' => [
// ...
DomainEngine\ToolkitBundle\ToolkitBundle::class,
],
First Use Case: Annotate a Value Object
Define a simple value object in your domain layer (e.g., app/Domain/ValueObject/Email.php):
namespace App\Domain\ValueObject;
use DomainEngine\Toolkit\Annotation\ValueObject;
#[ValueObject]
class Email
{
public function __construct(private string $address) {}
public function getAddress(): string { return $this->address; }
}
Autoload Annotations
Configure Symfony’s annotation autoloader in composer.json:
"autoload": {
"psr-4": {
"App\\": "app/"
},
"classmap": ["vendor/domain-engine/toolkit"]
}
Run composer dump-autoload.
Domain Events & Process Manager
use DomainEngine\Toolkit\Annotation\DomainEvent;
#[DomainEvent]
class OrderCreated {}
// In AggregateRoot:
$this->recordThat(new OrderCreated($orderId));
ProcessManager to orchestrate workflows:
use DomainEngine\Toolkit\ProcessManager;
$processManager = app(ProcessManager::class);
$processManager->handle(new OrderCreated($orderId));
Command Handling
use DomainEngine\Toolkit\Annotation\Command;
#[Command]
class CreateOrder {}
$this->app->bind(
CommandHandler::class,
fn() => new CommandHandler(app(Dispatcher::class))
);
Aggregate Roots
use DomainEngine\Toolkit\Annotation\AggregateRoot;
#[AggregateRoot]
class Order {}
DomainEvent annotations to auto-publish events.Symfony Messenger Bridge
Use Laravel’s Illuminate\Bus\Dispatcher to integrate with Symfony Messenger:
$dispatcher = app(Dispatcher::class);
$messenger = new Messenger($dispatcher);
$processManager = new ProcessManager($messenger);
Laravel Service Container Bind toolkit services explicitly:
$this->app->singleton(ProcessManager::class, fn() => new ProcessManager(app(Messenger::class)));
Event Listeners Convert Symfony Messenger listeners to Laravel events:
// Symfony Messenger Listener
$messenger->addListener(OrderCreated::class, fn(OrderCreated $event) => ...);
// Laravel Event Listener
event(new OrderCreated($orderId));
Annotation Processing
composer dump-autoload is run post-installation.Messenger Integration
Dispatcher and Symfony’s Messenger have different expectations.symfony/messenger-bridge) or wrap the Dispatcher in a Messenger adapter.Aggregate Root State
DomainEvent annotations for all state transitions.Enable Debug Mode
Configure Symfony’s debug mode in config/packages/domain_engine_toolkit.yaml:
framework:
messenger:
debug: true
Log Domain Events Add a listener to log events for debugging:
$messenger->addListener(DomainEvent::class, fn($event) => \Log::debug($event));
Custom Annotations Extend the annotation system by creating new attributes:
#[Attribute]
class CustomAnnotation {}
Process Manager Plugins
Override the ProcessManager to add custom workflow logic:
class CustomProcessManager extends ProcessManager
{
protected function getHandlers(): array
{
return array_merge(parent::getHandlers(), [
CustomEvent::class => new CustomHandler(),
]);
}
}
Value Object Validation Add validation logic to value objects:
#[ValueObject]
class Email
{
public function __construct(string $address)
{
if (!filter_var($address, FILTER_VALIDATE_EMAIL)) {
throw new \InvalidArgumentException("Invalid email");
}
$this->address = $address;
}
}
How can I help you explore Laravel packages today?