Package Data | |
---|---|
Maintainer Username: | impleri |
Maintainer Contact: | marcus@c4tech.com (Marcus Amargi) |
Package Create Date: | 2016-01-05 |
Package Last Update: | 2016-04-18 |
Home Page: | |
Language: | PHP |
License: | MIT |
Last Refreshed: | 2024-11-09 03:01:17 |
Package Statistics | |
---|---|
Total Downloads: | 151 |
Monthly Downloads: | 0 |
Daily Downloads: | 0 |
Total Stars: | 0 |
Total Watchers: | 6 |
Total Forks: | 0 |
Total Open Issues: | 0 |
Event Sourcing for Laravel. Made with love by C4 Tech and Design.
"c4tech/ray-emitter": "1.x"
to your composer requirements and run composer update
.C4tech\RayEmitter\ServiceProvider
to config/app.php
in the 'providers' array.php artisan vendor:publish
config/ray_emitter.php
to adjust your Event and Command handler prefices.The bulk of Ray Emitter is a set of base classes to implement the command side of CQRS and domain driven design in your application.
Commands encapsulate application state change requests at the Aggregate level. In general, Commands serve as the internal API, displacing the Controller layer of MVC architecture. Outward-facing APIs can parallel the Command structure or map them. The key to successful implementation of Commands is that they target one and only one Aggregate.
Repositories serve as a outer layer to Aggregates, supporting a single Aggregate by providing a way to rebuild the data for an Aggregate from the Event Store.
Aggregates encapsulate functionality and data related to a single Entity, known as the Aggregate Root. In this implementation, Aggregates handle Commands, providing validation of business logic, and transform successful Commands into Events. Aggregates also handle the replaying of Events when being rebuilt by the Repository.
Events are, in reality, nothing more than recorded changes caused by Commands. However, they produce no side-effects in and of themselves. When replayed, Events should only change data within the bounded context of the Aggregate.
Entities are one of the primary building blocks of a Domain, serving as the persisted representation of something that has an identity. In this implementation, Entities are read-only representations of an application state and contain all related Value Objects as properties. Since Aggregates should only persist references to other Aggregate Roots, the Entity provides a way to access the application state of another Aggregate without transgressing the bounded context. Entities displace the Model layer of MVC architecture.
Aggregates Roots serve as the single primary Entity for an Aggregate. In this implementation, Aggregate Roots are the write-enabled representation of an Entity.
Value Objects are the other primary build blocks of a Domain, serving as the stateless representation of a value. One marked difference between a Value Object and a simple property on a model is that Value Objects may contain business logic for validation (e.g. an Email value object can validate that the data provided to it fits the form of an email address). Value Objects do not have a persistent thread of identity (e.g. every $20.00 bill has the same value and are interchangeable as value objects). In this implementation, Value Objects are properties on an Entity/AggregateRoot and are set/updated via Events applied within an Aggregate.
While the Domain is application-agnostic, this implementation has a few hooks into Laravel:
In the future, these dependencies may be adjusted to be more framework-agnostic.
Since there's not a strong dependency on Laravel, why is this a Laravel package? That's easy: Laravel is expected to be used for the Query/ReadModel side of the design. When the Domain Event is fired as a Laravel system event, you should provide a Transformer to update the stored application state snapshot. What's that? The "normal" Laravel Model structure. That means you should still be maintaining database migrations and Eloquent Model classes. However, these react to the broadcast Events rather than the Controllers directly. Additionally, performing other system events (such as sending emails) should be triggered by the Domain Events.
You can construct how to handle Queries and Read Models. We suggest using the standard Laravel structure (Controllers, Models, etc) to perform read queries.
This package throws Exceptions and provides HTTP-friendly error codes for the chance that the thrown exception is not caught. Below are the exceptions and their HTTP status codes, as well as a description of how to handle them.
409 = Outdated Sequence. The Aggregate was updated before the Command was issued. Client should refresh read data and resubmit.
422 = Sequence Mismatch. The issued Command expected the Aggregate to have a later sequence version than it does. Client should refresh read data and resubmit.
501 = Event or Command Handler Missing. The Aggregate is missing the expected method for the Command or Domain Event.
504 = UnknownProperty. The Entity/AggregateRoot does not have the expected property defined or the Aggregate Root cannot find a setter method for the property.