PHP Lightweight Message Bus supporting CQRS.

Overview

Prooph Service Bus

PHP 7.1+ lightweight message bus supporting CQRS and Micro Services

Build Status Coverage Status Gitter

Important

This library will receive support until December 31, 2019 and will then be deprecated.

For further information see the official announcement here: https://www.sasaprolic.com/2018/08/the-future-of-prooph-components.html

Messaging API

prooph/service-bus is a lightweight messaging facade. It allows you to define the API of your model with the help of messages.

  1. Command messages describe actions your model can handle.
  2. Event messages describe things that happened while your model handled a command.
  3. Query messages describe available information that can be fetched from your (read) model.

prooph/service-bus shields your model. Data input and output ports become irrelevant and no longer influence business logic. We're looking at you Hexagonal Architecture.

prooph/service-bus decouples your model from any framework. You can use a web framework like Zend, Symfony, Laravel and co. to handle http requests and pass them via prooph/service-bus to your model but you can also receive the same messages via CLI or from a messaging system like RabbitMQ or Beanstalkd.

It is also a perfect fit for microservices architecture as it provides an abstraction layer for message-based inter-service communication.

prooph_architecture

Installation

You can install prooph/service-bus via composer by running composer require prooph/service-bus, which will install the latest version as requirement to your composer.json.

Quick Start

<?php

use Prooph\ServiceBus\CommandBus;
use Prooph\ServiceBus\Example\Command\EchoText;
use Prooph\ServiceBus\Plugin\Router\CommandRouter;

$commandBus = new CommandBus();

$router = new CommandRouter();

//Register a callback as CommandHandler for the EchoText command
$router->route('Prooph\ServiceBus\Example\Command\EchoText')
    ->to(function (EchoText $aCommand): void {
        echo $aCommand->getText();
    });

//Expand command bus with the router plugin
$router->attachToMessageBus($commandBus);

//We create a new Command
$echoText = new EchoText('It works');

//... and dispatch it
$commandBus->dispatch($echoText);

//Output should be: It works

Live Coding Introduction

Prooph Service Bus v6

Documentation

Documentation is in the docs tree, and can be compiled using bookdown.

$ php ./vendor/bin/bookdown docs/bookdown.json
$ php -S 0.0.0.0:8080 -t docs/html/

Then browse to http://localhost:8080/

Support

Contribute

Please feel free to fork and extend existing or add new features and send a pull request with your changes! To establish a consistent code quality, please provide unit tests for all your changes and may adapt the documentation.

License

Released under the New BSD License.

Comments
  • Proposal: Add interfaces for classes when using an InvokeStrategy

    Proposal: Add interfaces for classes when using an InvokeStrategy

    If we have a EventRouter with a mapping e.g.

    auswahl_100

    and we use for example the OnEventStrategy wants to call the onEvent() method, even if the class just uses __invoke() as callable.

    So currently it is not possible to use more than one InvokeStrategy. If we use a specific InvokeStrategy we are bound to this InvokeStrategy

    I propose to provide an interface for each InvokeStrategy (for the given methods e.g.)

    interface UseHandleCommandStrategy {
        public interface handle(Message $message) : void;
    }
    
    interface UseOnEventStrategy {
        public interface onEvent(Message $message) : void;
    }
    
    interface UseFinderInvokeStrategy {
        public interface find(Message $message, $deferred) : void;
    }
    

    So we can build in a check if the handler wants to use a specific strategy:

    foreach ($handlers as $handler) {
        if ($handler instanceof UseOnEventStrategy) {
            $handler->onEvent($message);
        }
    }
    

    Handler not implementing the interface will just be skipped, so multiple strategies are possible then.

    BC break 
    opened by lunetics 24
  • Add an AsyncSwitchMessageRouter

    Add an AsyncSwitchMessageRouter

    Use case taken from the chat:

    first round: http request -> command bus -> custom router checks if command should be handled async (marker interface) and has no "handled-by-queue" metadata set -> route to bernard -> bernard producer add command to queue second round: bernard consumer -> $command->withAddedMetadata('handled-by-queue', $queueName); -> command bus -> custom router sees the metadata key and now routes to command handler instead of bernard -> command handler -> ...

    Idea: the AsyncSwitchMessageRouter can decorate a "standard router plugin" configured with the in-process message routes. The router should check either a specific message metadata key or if message implements an AsyncMessage marker interface (tbd) and route the message to a configured message producer. In the draft from the chat the consumer adds a metadata key to tell the router that the message was consumed from a queue. But the router should add such a metada key BEFORE it routes the message to a producer. So the router can check its own metadata key when it receives the message a second time. If the metadata key is present the AsyncSwitchMessageRouter delegates routing to its inner (decorated) router.

    enhancement 
    opened by codeliner 17
  • `Prooph\ServiceBus\Plugin`ServiceLocatorPlugin` is not compatible with the `EventBus`

    `Prooph\ServiceBus\Plugin`ServiceLocatorPlugin` is not compatible with the `EventBus`

    Prooph\ServiceBus\Plugin\ServiceLocatorPlugin relies onProoph\ServiceBus\MessageBus::EVENT_PARAM_MESSAGE_HANDLER, but the Prooph\ServiceBus\EventBus has its own EVENT_PARAM_EVENT_LISTENERS

    This means that registering a ServiceLocatorPlugin against an EventBus is not causing any effect, as no events are intercepted.

    opened by Ocramius 12
  • Bugfix: exception is not resettable with finalize event

    Bugfix: exception is not resettable with finalize event

    This PR provides a bugfix for not resettable exceptions with finalize event.

    • [x] add unit test which would fail without this PR
    • [x] fix the bug

    /cc @prolic please confirm this as a bug

    bug 
    opened by oqq 10
  • What the sense in ReactPHP  and it is Promises if QueryBus works synchronously?

    What the sense in ReactPHP and it is Promises if QueryBus works synchronously?

    I have tested 2 queries

    `$this->queryBus->dispatch(new GetUserList( ))->then(
                function($result){
                    dump($result); // some result
                }
            );
    
            $this->queryBus->dispatch( new GetUserList( ))->then(
                function($result)  {
                    dump($result); // empty should be
                }
            )
            ;`
    

    for first one handler i put sleep for 5 seconds, and here results are

    //first - should be last, coz results + sleep
    Paginator {#3327 ▼
    ...
    }
    //second, should be first, because no sleep + empty results
    []
    

    Maybe i missed something, please tell me please.

    documentation 
    opened by BonBonSlick 9
  • QueryBus testing

    QueryBus testing

    Hi!

    I am currently finding my way around with QueryBus. And I got confused with testing it. I created an empty project, pulled up just a few things:

    "require": {
            "prooph/service-bus": "^6.0",
            "react/promise": "^2.5"
        },
        "require-dev": {
            "phpunit/phpunit": "^6.1"
        }
    

    and then run this test:

    <?php
    declare(strict_types=1);
    
    
    use PHPUnit\Framework\TestCase;
    use Prooph\ServiceBus\QueryBus;
    
    final class QueryTest extends TestCase
    {
        function test_query() {
        
            $queryBus = new QueryBus();
            $queryBus->dispatch('anyname')->then(function(){
                //will not get there anyway
            }, function(Throwable $e){
                // Does nothing
                $this->fail($e->getMessage());
            });
            
        
        }
    }
    

    And it is green. I get control in second callable, but PHPUnit did not respect the fail() call at all.

    Do you have any suggestions on how to test queries / how to fix that test?

    P.s. I browsed through the proophessor-do but did not find query tests there.

    question 
    opened by lezhnev74 9
  • update factories to interop-config 1.0, add static factory support

    update factories to interop-config 1.0, add static factory support

    This PR adds support for interop-config 1.0 and adds a new feature called static factories. Also dependencies are updated to latest versions and Composer scripts were added.

    If this is ok, I will update the other packages in the same manner. /cc @codeliner

    Note: We have some BC breaks of the factory methods because the interface of interop-config has changed. I think we should also mark the factories as final, because the config id (container id) is now configurable. What do you think?

    enhancement BC break 
    opened by sandrokeil 8
  • exchange PromiseInterface for ExtendedPromiseInterface

    exchange PromiseInterface for ExtendedPromiseInterface

    Could we exchange \React\Promise\PromiseInterface for \React\Promise\ExtendedPromiseInterface which simply extends PromiseInterface but has the done method? see https://reactphp.org/promise/#extendedpromiseinterface

    until #147 anyway

    BC break 
    opened by basz 7
  • bus factory async option

    bus factory async option

    @prolic can you take over the release when everything is merged to develop?

    Won't have much time the next days and then I'm off for 3 weeks.

    /cc @guyradford

    enhancement 
    opened by codeliner 7
  • Resolve #107 - Correctly detect event name in OnEventStrategy

    Resolve #107 - Correctly detect event name in OnEventStrategy

    This change fixes an issue with OnEventStrategy not correctly determining the event name if a custom event returns a message name other than its own class name through the messageName() method.

    bug 
    opened by robertlemke 7
  • Use LazyPromise?

    Use LazyPromise?

    public function __invoke(Message $message, Deferred $deferred = null):?Promise
    {
        $needReply = (bool) $deferred;
        // stripped code. 
        if ($needReply) { 
            return new LazyPromise(function() use ($deferred, $reply) {
                $value = JSON::decode($reply->receive($this->replyTimeout)->getBody());
    
                try {
                    $deferred->resolve($value);
                } catch (TimeoutException $e) {
                    $deferred->reject($e->getMessage());
                }
            });
        }
    

    But this is a BC an can only be done with a new major release.

    enhancement question BC break 
    opened by prolic 6
  • Improve message producer documentation

    Improve message producer documentation

    Provide better explanation and examples of async message routing.

    See chat discussion for the why?

    Guy Radford @guyradford 22:08 ... I have managed to get the router to put the ActionEvent out through Bernard... but the router then try to route the message internally... I have trued to get$actionEvent->stopPropagation(true); and $actionEvent->setParam(MessageBus::EVENT_PARAM_MESSAGE_HANDLED, true); but neither works.

    Alexander Miertsch @codeliner 22:27 ... Your router invokes BernardMessageProducer directly? If so, this is the problem. The router should route your command to the BernardMessageProducer only. All message producers are callable so they can be used as (or better replace) command handlers. We should make that more clear in the docs. For now take a look at the proophessor-do snapshot tutorial. In the last paragraph you can see how the TakeSnapshot command is routed to zeromq-message-producer instead of a in-process-command-handler (see the route config example). You just need to do the same in your application. You don't even need a specific router for the task.

    documentation 
    opened by codeliner 1
Releases(v6.3.0)
Owner
CQRS and EventSourcing Infrastructure for PHP
null
Command bus package for PHP

#Chief Chief is a powerful standalone command bus package for PHP 5.4+. Contents What is a command bus Installation Usage Class-based command handlers

Adam Nicholson 49 Apr 29, 2021
A simple bus ticket system made by Larave 5.4

Bus Ticket System About Bus Ticket System A simple bus ticket system made by Larave 5.4. There are several features here in this project and those are

Eng Hasan Hajjar 3 Sep 30, 2022
Proxy based Redis cluster solution supporting pipeline and scaling dynamically

Codis is a proxy based high performance Redis cluster solution written in Go. It is production-ready and widely used at wandoujia.com and many compani

null 12.7k Jan 2, 2023
Small convention based CQRS library for PHP

LiteCQRS for PHP Small naming-convention based CQRS library for PHP (loosely based on LiteCQRS for C#) that relies on the MessageBus, Command, EventSo

Benjamin Eberlei 560 Nov 20, 2022
🐘 🎯 Hexagonal Architecture, DDD & CQRS in PHP

?? ?? Hexagonal Architecture, DDD & CQRS in PHP Example of a PHP application using Domain-Driven Design (DDD) and Command Query Responsibility Segrega

CodelyTV 2.5k Jan 6, 2023
Enraged Xenomorph - DDD/CQRS Symfony Application Boilerplate

Enraged Xenomorph - DDD/CQRS Symfony Application Boilerplate This project is very opinionated attempt to compile a bit of experience, few good practic

Gniewomir Świechowski 1 Jan 10, 2022
Dockerise Symfony Application (Symfony 6 + Clean Architecture+ DDD+ CQRS + Docker + Xdebug + PHPUnit + Doctrine ORM + JWT Auth + Static analysis)

Symfony Dockerise Symfony Application Install Docker Install Docker Compose Docker PHP & Nginx Create Symfony Application Debugging Install Xdebug Con

null 48 Jan 5, 2023
A Symfony project made with DDD, CQRS and Hexagonal Architecture

Symfony Blog DDD + CQRS + Hexagonal Architecture A Symfony blog project made with CQRS, Hexagonal Architecture and DDD Docker integration This project

null 5 Aug 10, 2022
Orkestra is a library of infrastructure and architecture helpers for creating CQRS applications

Orkestra Orkestra is an opinionated framework with a plethora of recommendations on architectural design that we use internally at Morebec to develop

Morébec 2 Aug 18, 2021
Because every Wedding RSVP website needs to follow DDD, CQRS, Hexagonal Architecture, Event Sourcing, and be deployed on Lambda.

Our Wedding Website Because every Wedding RSVP website needs to follow DDD, CQRS, Hexagonal Architecture, Event Sourcing, and be deployed on Lambda. ?

Edd Mann 3 Aug 21, 2022
Clean Architecture, DDD and CQRS using Symfony 6

Task manager system using Clean Architecture, DDD and CQRS. Environment setup Install Docker Clone the project: git clone https://github.com/k0t9i/Tas

null 3 Sep 5, 2022
Get dialogflow fullfilment message in PHP

dialogflow-php PHP Client Library for Dialogflow API v2 Requirements Dialogflow Agent Google Account Credentials file PHP Composer Installation To beg

Emmadi Sumith Kumar 17 Oct 28, 2022
⚡ Php snippets, random stuff, demos, functions, fast message system, agnostic and framework free - 100% compactible ;) ⚡

⚡ Php8 FPM Nginx Fast, Scripts, Pearls & Treasures ?? Want to run and test asap ? docker-compose up -d phpgit_php8;ip=$(docker-machine ip default);ech

Benjamin FONTAINE 0 Mar 20, 2022
Xenon\LaravelBDSms is a sms gateway package for sending text message to Bangladeshi mobile numbers using several gateways like sslcommerz, greenweb, dianahost,metronet in Laravel framework

Xenon\LaravelBDSms is a sms gateway package for sending text message to Bangladeshi mobile numbers using several gateways for Laravel. You should use

Ariful Islam 95 Jan 3, 2023
Magento 2 Message Queue Open Source Module

Magento 2 Message Queue Module Lightweight implementation of message queue for Magento 2 Community Edition. System requirements This extension support

Renato 36 Sep 30, 2021
This is an implementation of PSR specification. It allows you to send and consume message with Redis store as a broker.

This is an implementation of PSR specification. It allows you to send and consume message with Redis store as a broker.

Enqueue 35 Nov 4, 2022
Magento 2 Message Queue OS AMQP Broker Implementation

Magento 2 Message Queue AMQP Backend AMQP message queue backend implementation for Rcason_Mq. Installation Require the module via Composer $ composer

Renato 8 Jul 12, 2022
Ask your friends to send you an anonymous message without knowing them

Ask your friends to send you an anonymous message without knowing them. ????????

Siavash 1 Apr 16, 2022
Promoting the interoperability of message queue objects.

Queue Interoperability About queue-interop tries to identify and standardize a common way for PHP programs to create, send, receive and read MQ messag

null 446 Jan 3, 2023