| description | Ecotone — The enterprise architecture layer for Laravel and Symfony |
|---|
Ecotone extends your existing Laravel and Symfony application with the enterprise architecture layer
One Composer package adds CQRS, Event Sourcing, Workflows, and production resilience to your codebase. No framework change. No base classes. Just PHP attributes on your existing code.
composer require ecotone/laravel # or ecotone/symfony-bundleclass OrderService
{
#[CommandHandler]
public function placeOrder(PlaceOrder $command, EventBus $eventBus): void
{
// your business logic
$eventBus->publish(new OrderWasPlaced($command->orderId));
}
#[QueryHandler('order.getStatus')]
public function getStatus(string $orderId): string
{
return $this->orders[$orderId]->status;
}
}
class NotificationService
{
#[Asynchronous('notifications')]
#[EventHandler]
public function whenOrderPlaced(OrderWasPlaced $event, NotificationSender $sender): void
{
$sender->sendOrderConfirmation($event->orderId);
}
}That's the entire setup. No bus configuration. No handler registration. No retry config. No serialization wiring. Ecotone reads your attributes and handles the rest:
- Command and Query Bus — wired automatically from your
#[CommandHandler]and#[QueryHandler]attributes - Event routing —
NotificationServicesubscribes toOrderWasPlacedwithout any manual wiring - Async execution —
#[Asynchronous('notifications')]routes to RabbitMQ, SQS, Kafka, or DBAL — your choice of transport - Failure isolation — each event handler gets its own copy of the message, so one handler's failure never blocks another
- Retries and dead letter — failed messages retry automatically, permanently failed ones go to a dead letter queue you can inspect and replay
- Tracing — OpenTelemetry integration traces every message across sync and async flows
Extract a specific flow and test it in isolation — only the services you need:
$ecotone = EcotoneLite::bootstrapFlowTesting([OrderService::class]);
$ecotone->sendCommand(new PlaceOrder('order-1'));
$this->assertEquals('placed', $ecotone->sendQueryWithRouting('order.getStatus', 'order-1'));Only OrderService is loaded. No notifications, no other handlers — just the flow you're verifying.
Now bring in the full async flow. Enable an in-memory channel and run it within the same test process:
$notifier = new InMemoryNotificationSender();
$ecotone = EcotoneLite::bootstrapFlowTesting(
[OrderService::class, NotificationService::class],
[NotificationSender::class => $notifier],
enableAsynchronousProcessing: [
SimpleMessageChannelBuilder::createQueueChannel('notifications')
]
);
$ecotone
->sendCommand(new PlaceOrder('order-1'))
->run('notifications');
$this->assertEquals(['order-1'], $notifier->getSentOrderConfirmations());->run('notifications') processes messages from the in-memory queue — right in the same process. The async handler executes deterministically, no timing issues, no polling, no external broker.
The key: swap the in-memory channel for DBAL, RabbitMQ, or Kafka to test what runs in production — the test stays the same. Ecotone runs the consumer within the same process, so switching transports never changes how you test. The ease of in-memory testing stays with you no matter what backs your production system.
No command bus configuration. No handler registration. No message serialization setup. You write a PHP class with an attribute, and Ecotone wires the bus, the routing, the serialization, and the async transport. Your code stays focused on what your application actually does — your domain.
Add #[Asynchronous('channel')] to any handler. The handler code stays identical. Switch from synchronous to RabbitMQ to SQS to Kafka by changing one line of configuration. Your business logic never knows the difference.
Every failed message is captured in a dead letter queue. You see what failed, the full exception, and the original message. Replay it with one command. And can be combined with inbuilt Outbox pattern to ensure full consistency. No more silent failures. No more guessing what happened to that order at 3am.
A multi-step business process — order placement, payment, shipping, notification — doesn't need to be scattered across event listeners, cron jobs, and database flags. Ecotone gives you Sagas for stateful workflows, handler chaining for linear pipelines, and Orchestrators for declarative process control. The entire business flow is readable in one class.
When a new developer opens your code, they see PlaceOrder, OrderWasPlaced, ShipOrder — not AbstractMessageBusHandlerFactory. Ecotone keeps your domain clean: no base classes to extend, no framework interfaces to implement, no infrastructure leaking into your business logic. Just plain PHP objects with attributes that declare their intent.
Ecotone's declarative, attribute-based architecture is inherently friendly to AI code generators. When your AI assistant works with Ecotone code, two things happen:
Less context needed, less code generated. A command handler with #[CommandHandler] and #[Asynchronous('orders')] tells the full story in two attributes — no bus configuration files, no handler registration, no retry setup to feed into the AI's context window. The input is smaller because there's less infrastructure to read, and the output is smaller because there's less boilerplate to generate. That means lower token cost, faster iteration cycles, and more accurate results.
AI that knows Ecotone. Your AI assistant can work with Ecotone out of the box:
- Agentic Skills — Ready-to-use skills that teach any coding agent how to correctly write handlers, aggregates, sagas, projections, tests, and more. Install with one command and your AI generates idiomatic Ecotone code from the start.
- MCP Server — Direct access to Ecotone documentation for any AI assistant that supports Model Context Protocol — Claude Code, Cursor, Windsurf, GitHub Copilot, and others.
- llms.txt — AI-optimized documentation files that give any LLM instant context about Ecotone's API and patterns.
Testing that AI can actually run. Ecotone's testing support runs async flows in the same process — even complex workflows with sagas and projections can be tested with ->sendCommand() and ->run(). Your coding agent writes and verifies tests without needing to set up external infrastructure or guess at test utilities.
Declarative configuration that any coding agent can follow and reproduce. Testing support that lets it verify even the most advanced flows. Less guessing, no hallucinating — just confident iteration.
| Capability | What it gives you | Learn more |
|---|---|---|
| CQRS | Separate command and query handlers. Clean responsibility boundaries. Automatic bus wiring. | Command Handling |
| Event Sourcing | Store events instead of state. Full audit trail. Rebuild read models anytime. Time travel and replay. | Event Sourcing |
| Workflows & Sagas | Orchestrate multi-step business processes. Stateful workflows with compensation logic. | Business Workflows |
| Async Messaging | RabbitMQ, Kafka, SQS, Redis, DBAL. One attribute to go async. Swap transports without code changes. | Asynchronous Handling |
| Production Resilience | Automatic retries, dead letter queues, outbox pattern, message deduplication, failure isolation. | Resiliency |
| Domain-Driven Design | Aggregates, domain events, bounded contexts. Pure PHP objects with no framework coupling. | Aggregates |
| Distributed Bus | Cross-service messaging. Share events and commands between microservices with guaranteed delivery. | Microservices |
| Multi-Tenancy | Tenant-isolated processing, projections, and event streams. Built in, not bolted on. | Multi-Tenancy |
| Observability | OpenTelemetry integration. Trace every message — sync or async — across your entire system. | Monitoring |
| Interceptors | Cross-cutting concerns — authorization, logging, transactions — applied declaratively via attributes. | Interceptors |
Every mature ecosystem has an enterprise architecture layer on top of its web framework:
| Ecosystem | Web Framework | Enterprise Architecture Layer |
|---|---|---|
| Java | Spring Boot | Spring Integration + Axon Framework |
| .NET | ASP.NET | NServiceBus / MassTransit |
| PHP | Laravel / Symfony | Ecotone |
Ecotone is built on the same foundation — Enterprise Integration Patterns — that powers Spring Integration, NServiceBus, and Apache Camel. In active development since 2017 and used in production by teams running multi-tenant, event-sourced systems at scale, Ecotone brings the same patterns that run banking, logistics, and telecom systems in Java and .NET to PHP.
This isn't about PHP catching up. It's about your team using proven architecture patterns — with the development speed that PHP gives you — without giving up the ecosystem you already know.
Laravel — Laravel's queue runs jobs, not business processes. Stop stitching Spatie + Laravel Workflow + Bus::chain + DIY outbox. Ecotone replaces the patchwork with one attribute-driven toolkit: aggregates with auto-published events, piped workflows, sagas, snapshots, transactional outbox — testable in-process, running on the queues you already have.
composer require ecotone/laravel
→ Laravel Quick Start · Laravel Module docs
Symfony — Symfony Messenger handles dispatch. For aggregates, sagas, or event sourcing the usual path is bolting on a separate event sourcing library, rolling your own outbox, and writing dedup middleware per handler. Ecotone replaces the patchwork with one attribute-driven toolkit: aggregates, sagas, event sourcing, piped workflows, transactional outbox, and per-handler failure isolation so one failing listener doesn't double-charge customers on retry. Pure POPOs, Bundle auto-config, your Messenger transports preserved.
composer require ecotone/symfony-bundle
→ Symfony Quick Start · Symfony Module docs
Any PHP framework — Ecotone Lite works with any PSR-11 compatible container.
composer require ecotone/lite-application
→ Ecotone Lite docs
Try it in one handler. You don't need to migrate your application. Install Ecotone, add an attribute to one handler, and see what happens. If you like what you see, add more. If you don't — remove the package. Zero commitment.
- Install — Setup guide for any framework
- Learn by example — Send your first command in 5 minutes
- Go through tutorial — Build a complete messaging flow step by step
- Workshops, Support, Consultancy — Hands-on training for your team
{% hint style="info" %} The full CQRS, Event Sourcing, and Workflow feature set is free and open source under the Apache 2.0 License. Enterprise features are available for teams that need advanced scaling, distributed bus with service map, orchestrators, and production-grade Kafka integration. {% endhint %}
{% hint style="success" %} Join Ecotone's Community Channel — ask questions and share what you're building. {% endhint %}
.png)