webspot/messagebus

This package is abandoned and no longer maintained. No replacement package was suggested.

Webspot MessageBus

dev-master 2015-05-30 21:25 UTC

This package is not auto-updated.

Last update: 2015-12-07 13:06:50 UTC


README

Build Status Code Climate Test Coverage

Inspired by MessageRequest-Oriented Middleware, though not implementing its asynchronous nature.

The idea is to decouple application layers by not having their classes interact with each other directly. Instead they get a MessageBus which they ask to respond to a RequestMessage.

The RequestMessage

A RequestMessage is an immutable object describing what the client expects. This means that any request data must be passed through the constructor. A RequestMessageInterface implementation consists of the following methods:

  • getName() : string returns a unique string identifying the request
  • getRequestData() : array returns the requests data serialized into an array

Other getters may be defined upon the RequestMessage to allow working with non-array-serialized data. Any method changing the message must return a new instance with the change instead of changing the object.

The ResponseMessage

A ResponseMessage is an immutable object describing the server's response to a request. This means that any response data must be passed through the constructor. A ResponseMessageInterface implementation consists of the following methods:

  • getRequestName() : string returns a unique string identifying the request
  • getResponseData() : array returns the response data serialized into an array

Other getters may be defined upon the ResponseMessage to allow working with non-array-serialized data. Any method changing the message must return a new instance with the change instead of changing the object.

The MessageBus

The MessageBus consists of a Protocol object and an implementation of the MessageBusInterface::handle(RequestMessageInterface $message) : void method. The handle() method will throw an UnhandledMessageException the MessageRequest didn't generate a Response.

An example

Let's say we're in a Controller and want to fetch an Entity. This might look like this:

<?php

namespace Application\Controller;

use Webspot\MessageBus\MessageRequest;
use Webspot\MessageBus\MessageBusInterface;

class PostsController
{
    /** @var  MessageBusInterface */
    private $messageBus;

    public function __construct(MessageBusInterface $messageBus)
    {
        $this->messageBus = $messageBus;
    }

    public function getAction($id)
    {
        // Assume we have an extension of the RequestMessageInterface which adds a getEntity() method
        $message = new FindEntityMessage('posts.find', $id);
        $response = $this->serviceBus->handle($message);
        return new JsonResponse($response->getResponseData());
    }

    public function getCommentsAction($postId)
    {
        // Assume we have an extension of the RequestMessageInterface which adds a getEntities() method
        $message = new GetEntitiesMessage('posts.comments.get', $postId);
        $response = $this->serviceBus->handle($message);
        return new JsonResponse($message->getCommentCollection()->toArray());
    }
}

The Model layer would define HandlerProviders extending the Webspot\MessageBus\HandlerProviderInterface. For the above use-case a PostsHandlerProvider would provide Handlers extending the Webspot\MessageBus\HandlerInterface accepting the posts.find and posts.comments.get request messages.

As such the Model layer's MessageBus construction would look somewhat like the following:

<?php

use Symfony\Component\EventDispatcher\EventDispatcher;
use Webspot\EventManager\EventManager;
use Webspot\MessageBus\MessageBus;
use Webspot\MessageBus\Protocol;

$messageBus = new MessageBus();

$postsHandlerProvider = new PostsHandlerProvider($postsRepository);
$messageBus->register($postsHandlerProvider);

We could even take it a step further and even push the HttpResponse generation through another MessageBus:

<?php

namespace Application\Controller;

use Webspot\MessageBus\MessageBusInterface;

class PostsController
{
    /** @var  MessageBusInterface */
    private $serviceBus;

    /** @var  MessageBusInterface */
    private $viewBus;

    public function __construct(MessageBusInterface $serviceBus, MessageBusInterface $viewBus)
    {
        $this->serviceBus = $serviceBus;
        $this->viewBus = $viewBus;
    }

    public function getAction($id)
    {
        // Assume we receive an extension of the ResponseMessageInterface which adds a getEntity() method
        $serviceRequest = new FindEntityMessage('posts.find', $id);
        $serviceResponse = $this->serviceBus->handle($serviceRequest);

        // Assume we receive an extension of the ResponseMessageInterface which adds a getHttpResponse() method
        $viewRequest = new PrepareResponseMessage('posts.view.json', $serviceResponse->getEntity());
        $viewResponse = $this->viewBus->handle($viewRequest);
        return $viewResponse->getResponse();
    }
}

Where the ViewBus would for example have a service using a Fractal\Transformer to transform a Post Entity into an array and wrap it into a HttpFoundation JsonResponse object.