Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/beberlei/litecqrs-php
Small convention based CQRS library for PHP
https://github.com/beberlei/litecqrs-php
Last synced: 18 days ago
JSON representation
Small convention based CQRS library for PHP
- Host: GitHub
- URL: https://github.com/beberlei/litecqrs-php
- Owner: beberlei
- License: mit
- Archived: true
- Created: 2012-08-09T06:45:10.000Z (almost 12 years ago)
- Default Branch: master
- Last Pushed: 2018-12-10T13:14:40.000Z (over 5 years ago)
- Last Synced: 2024-05-14T13:22:01.393Z (about 1 month ago)
- Language: PHP
- Size: 769 KB
- Stars: 556
- Watchers: 53
- Forks: 47
- Open Issues: 14
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Lists
- awesome-php-cn - 官网
- awesome-php - LiteCQRS - A CQRS (Command Query Responsibility Separation) library. (Miscellaneous)
- awesome-php-cn - 官网
- awesome-php - LiteCQRS - A CQRS (Command Query Responsibility Separation) library. (Miscellaneous)
README
# LiteCQRS for PHP
Small naming-convention based CQRS library for PHP (loosely based on [LiteCQRS for
C#](https://github.com/danielwertheim/LiteCQRS)) that relies on the MessageBus,
Command, EventSourcing and Domain Event patterns.[![Build Status (Master)](https://travis-ci.org/beberlei/litecqrs-php.png?branch=master)](https://travis-ci.org/beberlei/litecqrs-php)
**NOTE** Use the 1.1 branch, as the dev-master is currently in heavy refactoring.
## Terminology
CQS is Command-Query-Separation: A paradigm where read methods never change
state and write methods never return data. Build on top, CQRS suggests the
separation of read- from write-model and uses the [DomainEvent
pattern](http://martinfowler.com/eaaDev/DomainEvent.html) to notify the read
model about changes in the write model.LiteCQRS uses the command pattern and a central message bus service that
finds the corresponding handler to execute a command. A command is just a class
with some properties describing it, it can optionally implement ``LiteCQRS\Command``.During the execution of a command, domain events can be triggered. These are
again just simple classes with some properties and they can optionally implement
``LiteCQRS\DomainEvent``.An event queue knows what domain events have been triggered during a command
and then publishes them to an event message bus, where many listeners can
listen to them.## Changes
### From 1.0 to 1.1
* Extending ``LiteCQRS\Command`` and ``LiteCQRS\DomainEvent`` is NOT required anymore.
In fact you can use any class as command or event. The naming conventions alone
make sure command handlers and event listeners are detected.* JMS Serializer Plugin cannot "detach" aggregate root properties that are part
of an event that is serialized anymore. Putting related aggregate roots into
an Event is therefore not supported anymore (and not a good idea even with
JMS Serializer 0.9 anyways).## Conventions
* All public methods of a command handler class are mapped to Commands "Command
Class Shortname" => "MethodName" when the method and command class shortname match.
Implementing an interface for the commands is NOT required (since 1.1)
* Domain Events are applied to Event Handlers "Event Class Shortname" =>
"onEventClassShortname". Only if this matches is an event listener registered.
* Domain Events are applied on Entities/Aggregate Roots "Event Class Shortname"
=> "applyEventClassShortname"
* You can optionally extend the ``DefaultDomainEvent`` which has a constructor
that maps its array input to properties and throws an exception if an unknown
property is passed.
* There is also a ``DefaultCommand`` with the same semantics as
``DefaultDomainEvent``. Extending this is not required.Examples:
* ``HelloWorld\GreetingCommand`` maps to the ``greeting(GreetingCommand $command)`` method on the registered handler.
* ``HelloWorld\Commands\Greeting`` maps to the ``greeting(Greeting $command)`` method on the registered handler.
* ``HelloWorld\GreetedEvent`` is passed to all event handlers that have a method ``onGreeted(GreetedEvent $event)``.
* ``HelloWorld\Events\Greeted`` is passed to all event handlers that have a method ``onGreeted(Greeted $event)``.
* ``HelloWorld\GreetedEvent`` is delegated to ``applyGreeted($event)`` when created on the aggregate root## Installation & Requirements
Use the 1.1 branch, as the dev-master is currently in heavy refactoring.
The core library has no dependencies on other libraries. Plugins have dependencies on their specific libraries.
Install with [Composer](http://getcomposer.org):
{
"require": {
"beberlei/lite-cqrs": "1.1"
}
}## Workflow
These are the steps that a command regularly takes through the LiteCQRS stack during execution:
1. You push commands into a ``CommandBus``. Commands are simple objects
extending ``Command`` created by you.
2. The ``CommandBus`` checks for a handler that can execute your command. Every
command has exactly one handler.
3. The command handler changes state of the domain model. It does that by
creating events (that represent state change) and passing them to the
``AggregateRoot::apply()`` or ``DomainEventProvider::raise()`` method of your domain objects.
4. When the command is completed, the command bus will check all objects in the
identity map for events.
5. All found events will be passed to the ``EventMessageBus#publish()`` method.
6. The EventMessageBus dispatches all events to observing event handlers.
8. Event Handlers can create new commands again using the ``CommandBus``.Command and Event handler execution can be wrapped in handlers that manage
transactions. Event handling is always triggered outside of any command
transaction. If the command fails with any exception all events created by the
command are forgotten/ignored. No event handlers will be triggered in this case.In the case of InMemory CommandBus and EventMessageBus LiteCQRS makes sure that
the execution of command and event handlers is never nested, but in sequential
linearized order. This prevents independent transactions for each command
from affecting each other.## Examples
See [examples/](https://github.com/beberlei/litecqrs-php/tree/master/example) for
some examples:1. ``example1.php`` shows usage of the Command- and EventMessageBus with one domain object
2. ``example2_event.php`` shows direct usage of the EventMessageBus inside a command
3. ``example3_sequential_commands.php`` demonstrates how commands are processed sequentially.
4. ``tictactoe.php`` implements a tic tac toe game with CQRS.
5. ``SymfonyExample.md`` shows ``example1.php`` implemented within the scope of a Symfony2 project.## Setup
1. In Memory Command Handlers, no event publishing/observing
```php
register('MyApp\ChangeEmailCommand', $userService);
```2. In Memory Commands and Events Handlers
This uses ``LiteCQRS\EventProviderInterface`` instances to trigger domain events.
```php
register('MyApp\ChangeEmailCommand', $userService);$someEventHandler = new MyEventHandler();
$messageBus->register($someEventHandler);
```3. In Memory Commands + Custom Event Queue
LiteCQRS knows about triggered events by asking ``LiteCQRS\Bus\EventQueue``.
Provide your own implementation to be independent of
your domain objects having to implement ``EventProviderInterface``.```php