2017 © Pedro PelĂĄez
 

library flare-cqrs

Flare is a small and easy to use CQRS library.

image

ignislabs/flare-cqrs

Flare is a small and easy to use CQRS library.

  • Friday, December 22, 2017
  • by Flatline
  • Repository
  • 1 Watchers
  • 1 Stars
  • 13 Installations
  • PHP
  • 0 Dependents
  • 0 Suggesters
  • 0 Forks
  • 0 Open issues
  • 8 Versions
  • 8 % Grown

The README.md

Flare CQRS

Flare is a small and easy to use CQRS library.
It drives CQRS by making use of the message bus pattern, separating Queries (interrogatory messages) from Commands (imperative messages)., (*1)

This library was greatly inspired by Messaging Flavours article by Mathias Verraes., (*2)

What is CQRS?

Originated with Bertrand Meyer's Command and Query Separation principle (CQS):, (*3)

It states that every method should either be a command that performs an action, or a query that returns data to the caller, but not both. In other words, asking a question should not change the answer. More formally, methods should return a value only if they are referentially transparent and hence possess no side effects., (*4)

So, _Command and Query Responsibility Segregation_ (CQRS):, (*5)

... applies the CQS principle by using separate Query and Command objects to retrieve and modify data, respectively., (*6)

Source: [Wikipedia][2], (*7)

Installation

Through composer:, (*8)

$ composer require ignislabs/flare-cqrs

Usage

FlareCQRS is framework-agnostic, but it's really easy to bootstrap and use., (*9)

Bootstrapping

<?php
// Instantiate the resolver:
// This will get you a new instance of the hander based on the _handler id_,
// i.e, the fully-qualified class name, or wharever identifier you might use in
// a framework container.
// By default FlareCQRS comes with two resolvers, a CallableResolver and a PSR11Resolver.
// You can always create your own resolver by implementing the `Resolver` contract.

// Generic callable resolver
$resolver = new \IgnisLabs\FlareCQRS\Handler\Resolver\CallableResolver(function($handlerId) {
    // Somehow resolve your handler handler:
    return new performMagicToGetHandlerInstance($handlerId);
});

// PSR11 resolver (assuming Laravel's `$app` container, since it's PSR-11 compliant)
$resolver = new \IgnisLabs\FlareCQRS\Handler\Resolver\PSR11Resolver($app);

// Now instantiate the buses passing them a Locator instance

$queryBus = new \IgnisLabs\FlareCQRS\QueryBus(
    // Tell the Locator which handler corresponds to which query
    // and how to instantiate the handlers (passing in the Resolver)
    new \IgnisLabs\FlareCQRS\Handler\Locator\MapLocator($resolver, [
        GetAllTasksQuery::class => GetAllTasksHandler::class
    ])
);

$commandBus = new \IgnisLabs\FlareCQRS\CommandBus(
    // Tell the Locator which handler corresponds to which command
    // and how to instantiate the handlers (passing in the Resolver)
    new \IgnisLabs\FlareCQRS\Handler\Locator\MapLocator($resolver, [
        AddTaskCommand::class => AddTaskHandler::class
    ])
);

Usage

Now you can use the buses to dispatch any message, like so:, (*10)

<?php
// Queries can return whatever you need, it will be encapsulated in a Result object
$result = $queryBus->dispatch(new GetAllTasksQuery('some', 'params'));
// You can call `$result->call`:
$result->call(function(TaskCollection $tasks) {
    // Do what you want with your results
    // Using `call` let's you use type-hinting
    // It can be a any `callable`, not just a closure
});
// Or just get the result right away:
$result->getResult();

// Commands do not return anything
$commandBus->dispatch(new AddTaskCommand('Task Title', 'The task description'));

// You can dispatch multiple commands in sequence with a single call
$commandBus->dispatch(
    new AddTaskCommand('Task Title', 'The task description'),
    new UpdateTaskCommand('NEW Task Title', 'The NEW task description')
);
// Or if you like splat!
$commandBus->dispatch(...$commandsArray);

Message (Query & Command) classes

Your Message classes are simple DTO objects, so there are no rules or contracts to use, they can be whatever you like., (*11)

You can, however, take advantage of the DataAccessorTrait. With it you can have automatic accessor properties for your message classes. The trait defines a data private property, a get accessor method and the __get magic method so you can access the data as properties:, (*12)

<?php

class MyMessage {
    use \IgnisLabs\FlareCQRS\Message\DataAccessorTrait;

    public function __construct(string $foo, int $bar) {
        $this->setData(compact('foo', 'bar'));
    }
}

$message = new MyMessage('baz', 'qux');
// Using generic `get` accessor:
$message->get('foo'); // returns 'baz'
// Using the magic accessor:
$message->bar; // returns 'qux'

Handlers

A handler can be anything, as long as it is callable. Although, you will probably want to make them classes. In order to make a class be callable, just implement the __invoke method in it., (*13)

The __invoke method will receive an instance of the corresponding command., (*14)

This way, the classes are 100% yours, no hard dependency on this library whatsoever and you can typehint freely., (*15)

Let's see a quick example:, (*16)

<?php
class MyMessageHandler {
    public function __invoke(MyMessage $command) {
     // do something here
    }
}

Middlewares

You can create middlewares to interact with the messages before they reach their respective handlers., (*17)

Middlewares, same as with the Handlers, are callables, but you might prefer them to be classes, by using the same __invoke strategy., (*18)

You can pass your middlewares globally to your buses on instantiation as the last parameters like so:, (*19)

<?php
$callableMiddleware = function() { /* ... */ };
$queryBus = new \IgnisLabs\FlareCQRS\QueryBus(
    $locator, new LoggingMiddleware($logger), new FooMiddleware, $callableMiddleware
);

Or you can add/replace the middlewares on a one time basis:, (*20)

<?php
// Add a middleware to the chain
$commandBus->addMiddleware(new LoggingMiddleware($logger));
// Completely replace the middleware chain
$commandBus->middlewares(new LoggingMiddleware($logger), new FooMiddleware);

Buses are immutable, so adding or replacing middlewares on a bus will always return a new bus instance, so any subsequent calls to your buses will not be affected by these middleware changes., (*21)

The Versions

22/12 2017

2.x-dev

2.9999999.9999999.9999999-dev

Flare is a small and easy to use CQRS library.

  Sources   Download

MIT

The Requires

  • php >=7.1

 

The Development Requires

04/12 2017

dev-master

9999999-dev

Flare is a small and easy to use CQRS library.

  Sources   Download

MIT

The Requires

  • php >=7.1

 

The Development Requires

29/11 2017

1.2.x-dev

1.2.9999999.9999999-dev

Flare is a small and easy to use CQRS library.

  Sources   Download

MIT

The Requires

  • php >=7.1

 

The Development Requires

29/11 2017

1.0.0

1.0.0.0

Flare is a small and easy to use CQRS library.

  Sources   Download

MIT

The Requires

  • php >=7.1

 

The Development Requires

12/10 2017

0.1.3

0.1.3.0

Flare is a small and easy to use CQRS library.

  Sources   Download

MIT

The Requires

  • php >=7.1

 

The Development Requires

12/10 2017

0.1.2

0.1.2.0

Flare is a small and easy to use CQRS library.

  Sources   Download

MIT

The Requires

  • php >=7.1

 

The Development Requires

03/02 2017

0.1.1

0.1.1.0

Flare is a small and easy to use CQRS library.

  Sources   Download

MIT

The Requires

  • php >=7.1

 

The Development Requires

23/01 2017

0.1.0

0.1.0.0

Flare is a small CQRS library.

  Sources   Download

MIT

The Requires

  • php >=7.1

 

The Development Requires