eventsauce / laravel-eventsauce
Integration support for EventSauce with the Laravel framework.
Fund package maintenance!
driesvints
Installs: 60 796
Dependents: 0
Suggesters: 0
Security: 0
Stars: 99
Watchers: 5
Forks: 17
Open Issues: 11
Requires
- php: ^7.4|^8.0
- ext-json: *
- eventsauce/eventsauce: ^0.8.2|^1.0.0
- illuminate/bus: ^8.0|^9.0.0
- illuminate/container: ^8.0|^9.0.0
- illuminate/queue: ^8.0|^9.0.0
- illuminate/support: ^8.0|^9.0.0
- ramsey/uuid: ^3.8|^4.0
Requires (Dev)
- orchestra/testbench: ^6.0|^7.0
- phpunit/phpunit: ^9.3
Suggests
- eventsauce/code-generation: Generate commands and events with ease
README
Laravel EventSauce
This library allows you to easily integrate EventSauce with your Laravel application. It takes out the tedious work of having to set up your own message dispatcher and provides an easy API to set up aggregate roots, aggregate root repositories, consumers, and more. It also comes with a range of scaffolding console commands to easily generate the boilerplate needed to get started with an Event Sourced application.
⚠️ While already usable, this library is currently still a work in progress. More documentation and features will be added over time. We appreciate pull requests that help extend and improve this project.
Requirements
- PHP 7.4 or higher
- Laravel 8.0 or higher
Installation
Before installing a new package it's always a good idea to clear your config cache:
php artisan config:clear
You can install the library through Composer. This will also install the main EventSauce library.
composer require eventsauce/laravel-eventsauce
Configuration
You can publish the config file with the following command:
php artisan vendor:publish --tag="eventsauce-config"
Migrations
The default domain_messages
table will be loaded in through the library's service provider and migrated with:
php artisan migrate
You can also publish it and modify it as you see fit with the following command:
php artisan vendor:publish --tag="eventsauce-migrations"
Default Connection
The default database connection can be modified by setting the EVENTSAUCE_CONNECTION
env variable:
EVENTSAUCE_CONNECTION=mysql
Default Table
The default table name for your domain messages can be set with the EVENTSAUCE_TABLE
env variable:
EVENTSAUCE_TABLE=event_store
Scaffolding
Laravel EventSauce comes with some commands that you can use to scaffold objects and files which you'll need to build your Event Sourced app. These commands take out the tedious work of writing these yourself and instead let you focus on actually writing your domain logic.
Generating Aggregate Roots
Laravel EventSauce can generate aggregate roots and its related files for you. By using the make:aggregate-root
command, you can generate the following objects and files:
- The
AggregateRoot
- The
AggregateRootId
- The
AggregateRootRepository
- The migration file
To generate these files for a "Registration" process, run the following command:
php artisan make:aggregate-root Domain/Registration
This will scaffold the following files:
App\Domain\Registration
App\Domain\RegistrationId
App\Domain\RegistrationRepository
database/migrations/xxxx_xx_xx_create_registration_domain_messages_table.php
These are all the files you need to get started with an https://github.com/EventSaucePHP/LaravelEventSauce.
Generating Consumers
Laravel EventSauce can also generate consumers for you. For example, run the make:consumer
command to generate a SendEmailConfirmation
process manager:
php artisan make:consumer Domain/SendEmailConfirmation
This will create a class at App\Domain\SendEmailConfirmation
where you can now define handle{EventName}
methods to handle events.
Generating Commands & Events
EventSauce can generate commands and events for you so you don't need to write these yourself. First, define a commands_and_events.yml
file which contains your definitions:
namespace: App\Domain\Registration commands: ConfirmUser: fields: identifier: RegistrationAggregateRootId user_id: int events: UserWasConfirmed: fields: identifier: RegistrationAggregateRootId user_id: int
Then define the input and output output file in the AggregateRootRepository:
final class RegistrationAggregateRootRepository extends AggregateRootRepository { ... /** @var string */ protected static $inputFile = __DIR__.'/commands_and_events.yml'; /** @var string */ protected static $outputFile = __DIR__.'/commands_and_events.php'; }
And register the AggregateRootRepository in your eventsauce.php
config file:
'repositories' => [ App\Domain\Registration\RegistrationAggregateRootRepository::class, ],
You can now generate commands and events for all repositories that you've added by running the following command:
php artisan eventsauce:generate
For more info on creating events and commands with EventSauce, as well as how to define different types, see the EventSauce documentation.
Usage
Aggregate Roots
More docs coming soon...
Aggregate Root Repositories
More docs coming soon...
Queue Property
You can instruct Laravel to queue all consumers onto a specific queue by setting the $queue
property:
use App\Domain\SendConfirmationNotification; use EventSauce\LaravelEventSauce\AggregateRootRepository; final class RegistrationAggregateRootRepository extends AggregateRootRepository { protected array $consumers = [ SendConfirmationNotification::class, ]; protected string $queue = 'registrations'; }
This will force all consumers who have the ShouldQueue
contract implemented to make use of the registrations
queue instead of the default queue defined in your queue.php
config file.
Consumers
Consumers are classes that react to events fired from your aggregate roots. There's two types of consumers: projections and process managers. Projections update read models (think updating data in databases, updating reports,...) while process managers handle one-time tasks (think sending emails, triggering builds, ...). For more information on how to use them, check out EventSauce's Reacting to Events documentation.
A SendEmailConfirmation
process manager, for example, can look like this:
use App\Events\UserWasRegistered; use App\Models\User; use App\Notifications\NewUserNotification; use EventSauce\LaravelEventSauce\Consumer; final class SendConfirmationNotification extends Consumer { protected function handleUserWasRegistered(UserWasRegistered $event): void { User::where('email', $event->email()) ->first() ->notify(new NewUserNotification()); } }
Within this consumer you always define methods following the handle{EventName}
specification.
Registering Consumers
After writing your consumer, you can register them with the $consumers
property on the related AggregateRootRepository
:
use App\Domain\SendConfirmationNotification; use EventSauce\LaravelEventSauce\AggregateRootRepository; final class RegistrationAggregateRootRepository extends AggregateRootRepository { protected array $consumers = [ SendConfirmationNotification::class, ]; }
The sequence of adding consumers shouldn't matter as the data handling within these consumers should always be treated as independent from each other.
Queueing Consumers
By default, consumers are handled synchronous. To queue a consumer you should implement the ShouldQueue
contract on your consumer class.
use EventSauce\LaravelEventSauce\Consumer; use Illuminate\Contracts\Queue\ShouldQueue; final class SendConfirmationNotification extends Consumer implements ShouldQueue { ... }
By doing so, we'll instruct Laravel to queue the consumer and let the data handling be done at a later point in time. This is useful to delay long-running data processing.
Changelog
Check out the CHANGELOG in this repository for all the recent changes.
Maintainers
This project is currently looking for a new maintainer.
Acknowledgments
Thanks to Frank De Jonge for building EventSauce. Thanks to Freek Van der Herten and Spatie's Laravel EventSauce library for inspiration to some of the features in this package.
License
Laravel EventSauce is open-sourced software licensed under the MIT license.