├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml.dist ├── src ├── CommandBus │ ├── CommandBus.php │ ├── CommandBusMiddleware.php │ ├── Contracts │ │ ├── Command.php │ │ ├── CommandBusMiddleware.php │ │ ├── CommandHandler.php │ │ ├── CommandHandlerResolver.php │ │ └── CommandTranslator.php │ ├── LoggerCommandBusMiddleware.php │ ├── Resolver │ │ ├── InteropContainerResolver.php │ │ ├── PsrContainerResolver.php │ │ ├── SimpleArrayResolver.php │ │ └── SymfonyContainerResolver.php │ ├── TransactionalCommandBusMiddleware.php │ └── Translator │ │ └── AppendStrategy.php ├── EventBus │ ├── Contracts │ │ ├── Event.php │ │ ├── EventBusMiddleware.php │ │ ├── EventHandler.php │ │ ├── EventHandlerPriority.php │ │ ├── EventHandlerResolver.php │ │ └── EventTranslator.php │ ├── EventBus.php │ ├── EventBusMiddleware.php │ ├── LoggerEventBusMiddleware.php │ ├── Resolver │ │ ├── InteropContainerResolver.php │ │ ├── PsrContainerResolver.php │ │ ├── SimpleArrayResolver.php │ │ └── SymfonyContainerResolver.php │ ├── TransactionalEventBusMiddleware.php │ └── Translator │ │ └── EventFullyQualifiedClassNameStrategy.php ├── QueryBus │ ├── CacheQueryBusMiddleware.php │ ├── Contracts │ │ ├── Query.php │ │ ├── QueryBusMiddleware.php │ │ ├── QueryHandler.php │ │ ├── QueryHandlerResolver.php │ │ ├── QueryResponse.php │ │ └── QueryTranslator.php │ ├── EmptyResponse.php │ ├── LoggerQueryBusMiddleware.php │ ├── QueryBus.php │ ├── QueryBusMiddleware.php │ ├── Resolver │ │ ├── InteropContainerResolver.php │ │ ├── PsrContainerResolver.php │ │ ├── SimpleArrayResolver.php │ │ └── SymfonyContainerResolver.php │ └── Translator │ │ └── AppendStrategy.php └── Serializer │ ├── Contracts │ └── Serializer.php │ ├── JsonObjectSerializer.php │ ├── JsonSerializer.php │ └── NativeSerializer.php └── tests ├── CommandBus ├── CommandBusMiddlewareTest.php ├── CommandBusTest.php ├── DummyCommand.php ├── DummyCommandHandler.php ├── LoggerCommandBusMiddlewareTest.php ├── Resolver │ ├── InteropContainerResolverTest.php │ ├── PsrContainerResolverTest.php │ ├── SimpleArrayResolverTest.php │ └── SymfonyContainerResolverTest.php ├── SqliteCommand.php ├── TransactionalCommandBusMiddlewareTest.php └── Translator │ └── AppendStrategyTest.php ├── ContainerException.php ├── EventBus ├── DummyEvent.php ├── DummyEventHandler.php ├── EventBusMiddlewareTest.php ├── EventBusTest.php ├── LoggerEventBusMiddlewareTest.php ├── Resolver │ ├── InteropContainerResolverTest.php │ ├── PsrContainerResolverTest.php │ ├── SimpleArrayResolverTest.php │ └── SymfonyContainerResolverTest.php ├── SqliteEvent.php ├── SqliteEventHandler.php ├── TransactionalEventBusMiddlewareTest.php └── Translator │ └── EventFullyQualifiedClassNameStrategyTest.php ├── InMemoryCache.php ├── InMemoryCacheItem.php ├── InMemoryInteropContainer.php ├── InMemoryLogger.php ├── InMemoryPsrContainer.php ├── InMemorySymfonyContainer.php ├── NotFoundException.php ├── QueryBus ├── CacheQueryBusMiddlewareTest.php ├── DummyQuery.php ├── DummyQueryHandler.php ├── DummyQueryResponse.php ├── LoggerQueryBusMiddlewareTest.php ├── QueryBusMiddlewareTest.php ├── QueryBusTest.php ├── Resolver │ ├── InteropContainerResolverTest.php │ ├── PsrContainerResolverTest.php │ ├── SimpleArrayResolverTest.php │ └── SymfonyContainerResolverTest.php └── Translator │ └── AppendStrategyTest.php └── Serializer ├── JsonObjectSerializerTest.php ├── JsonSerializerTest.php └── NativeSerializerTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | /build/ 3 | composer.phar 4 | composer.lock 5 | 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | php: 3 | - "7.0" 4 | 5 | before_script: 6 | - curl -sS https://getcomposer.org/installer | php -- --filename=composer 7 | - chmod +x composer 8 | - composer install 9 | 10 | script: 11 | - php vendor/bin/phpunit --coverage-text 12 | 13 | branches: 14 | only: 15 | - master 16 | 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Nil Portugués Calderó 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Message Bus 2 | 3 | [![Build Status](https://travis-ci.org/PHPMessageBus/messagebus.svg?branch=master)](https://travis-ci.org/PHPMessageBus/messagebus) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/PHPMessageBus/messagebus/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/PHPMessageBus/messagebus/?branch=master) [![SensioLabsInsight](https://insight.sensiolabs.com/projects/04e1a12f-e916-4ae6-875f-5e694fb71b6a/mini.png?)](https://insight.sensiolabs.com/projects/04e1a12f-e916-4ae6-875f-5e694fb71b6a) [![Latest Stable Version](https://poser.pugx.org/nilportugues/messagebus/v/stable?)](https://packagist.org/packages/nilportugues/messagebus) [![Total Downloads](https://poser.pugx.org/nilportugues/messagebus/downloads?)](https://packagist.org/packages/nilportugues/messagebus) [![License](https://poser.pugx.org/nilportugues/messagebus/license?)](https://packagist.org/packages/nilportugues/messagebus) 4 | [![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.me/nilportugues) 5 | 6 | Implementation for the CommandBus, the QueryBus and the EventBus in PHP 7 and using PSR-11. 7 | 8 | --- 9 | 10 | - [Installation](#installation) 11 | - [Introduction](#introduction) 12 | - [What is a Message Bus?](#what-is-a-message-bus) 13 | - [What are its benefits?](#what-are-its-benefits) 14 | - [1. CommandBus](#1---commandbus) 15 | - [1.1 - Usage](#11---usage) 16 | - [1.1.1 - Create a Command](#111---create-a-command) 17 | - [1.1.2 - Create a CommandHandler](#112---create-a-commandhandler) 18 | - [1.1.3 - Register the CommandHandler](#113---register-the-commandhandler) 19 | - [1.1.4 - Setting up the CommandBus](#114---setting-up-the-commandbus) 20 | - [1.1.5 - Registering the remaining CommandBus classes](#115---registering-the-remaining-commandbus-classes) 21 | - [1.1.6 - Running the CommandBus](#116---running-the-commandbus) 22 | - [ 1.2 - Predefined Middlewares](#12---predefined-middlewares) 23 | - [ 1.3 - Custom Middlewares](#13---custom-middlewares) 24 | - [2. QueryBus](#2---querybus) 25 | - [2.1 - Usage](#21-usage) 26 | - [2.1.1 - Create a Query](#211---create-a-query) 27 | - [2.1.2 - Create a QueryHandler](#212---create-a-queryhandler) 28 | - [2.1.3 - Create a QueryResponse](#213---create-a-queryresponse) 29 | - [2.1.4 - Register the QueryHandler](#214---register-the-queryhandler) 30 | - [2.1.5 - Setting up the QueryBusMiddleware](#215---setting-up-the-querybusmiddleware) 31 | - [2.1.6 - Registering the remaining QueryBus classes](#216---registering-the-remaining-querybus-classes) 32 | - [2.1.7 - Running the QueryBus](#216---running-the-querybus) 33 | - [ 2.2 - Predefined Middlewares](#22---predefined-middlewares) 34 | - [ 2.3 - Custom Middlewares](#23---custom-middlewares) 35 | - [3. EventBus](#3---eventbus) 36 | - [3.1 - Usage](#31---usage) 37 | - [3.1.1 - Create an Event](#311---create-an-event) 38 | - [3.1.2 - Create an EventHandler](#312---create-an-eventhandler) 39 | - [3.1.3 - (Optional) Set the EventHandler's Priority](#313---optional-set-the-eventhandlers-priority) 40 | - [3.1.4 - Register the EventHandler](#314---register-the-eventhandler) 41 | - [3.1.5 - Setting up the EventBusMiddleware](#315---setting-up-the-eventbusmiddleware) 42 | - [3.1.6 - Registering the remaining EventBus classes](#316---registering-the-remaining-eventbus-classes) 43 | - [3.1.7 - Running the EventBus](#317---running-the-eventbus) 44 | - [3.1.8 - (Optional) Running the EventBus as a Queue](#318---optional-running-the-eventbus-as-a-queue) 45 | - [3.2 - Predefined Middlewares](#32---predefined-middlewares) 46 | - [3.3 - Custom Middlewares](#33---custom-middlewares) 47 | - [4 - Serializers](#4---serializers) 48 | - [4.1 - NilPortugues\MessageBus\Serializer\NativeSerializer](#41---nilportuguesmessagebusserializernativeserializer) 49 | - [4.2 - NilPortugues\MessageBus\Serializer\JsonSerializer](#42---nilportuguesmessagebusserializerjsonserializer) 50 | - [4.3 - NilPortugues\MessageBus\Serializer\JsonObjectSerializer](#43---nilportuguesmessagebusserializerjsonobjectserializer) 51 | - [Contribute](#contribute) 52 | - [Support](#support) 53 | - [Authors](#authors) 54 | - [License](#license) 55 | 56 | ## Installation 57 | 58 | Use [Composer](https://getcomposer.org) to install the package: 59 | 60 | ``` 61 | $ composer require nilportugues/messagebus 62 | ``` 63 | 64 | ## Introduction 65 | 66 | The idea of a message bus is that you create message objects that represent what you want your application to do. Then, you toss it into the bus and the bus makes sure that the message object gets to where it needs to go. 67 | 68 | Easy right? Keep reading! 69 | 70 | ### What is a Message Bus? 71 | 72 | A Message Bus is a pipe of Messages. This implementation takes care of 3 types of messages, Commands, Queries and Events. While all look similar at first, their intent is different. 73 | 74 | - **Command**: its intent is about expressing an order to the system and modifies its current state. User expects no response. 75 | - **Event**: its intent is to express something that has already happened in the system, and record it. User expects no response. 76 | - **Query**: its intent is about expressing a question to the system. User expects a response. 77 | 78 | From this classification, one can spot that Command and Events can work together very well. 79 | 80 | ### What are its benefits? 81 | 82 | Given the nature of the message, implementing an interface, you may write behaviours that wrap the message to log, process or modify the response using the **Decorator pattern**. These are called **Middleware**. 83 | 84 | **For instance:** 85 | 86 | - Implementing task-based user-interfaces you can map concepts to Commands, Queries and Events easily. 87 | - It allows you to easily write a logging system to know what's going, whether its a Command, a Query or an Event. It's possible. 88 | 89 | **To wrap-up, its benefits are:** 90 | 91 | - Encourages separation of concerns. 92 | - Encourages single responsibility design. 93 | 94 | --- 95 | 96 | ## 1. CommandBus 97 | 98 | ### 1.1 - Usage 99 | 100 | #### 1.1.1 - Create a Command 101 | 102 | ```php 103 | username = $username; 115 | $this->password = $password; 116 | $this->emailAddress = $emailAddress; 117 | } 118 | 119 | //getters... 120 | } 121 | ``` 122 | 123 | #### 1.1.2 - Create a CommandHandler 124 | 125 | The Command Handler must implement the `CommandHandler` interface and implement the `__invoke` method. 126 | 127 | For instance: 128 | 129 | ```php 130 | userRepository = $userRepository; 141 | } 142 | 143 | public function __invoke(RegisterUser $command) 144 | { 145 | $user = new User( 146 | $command->getUsername(), 147 | $command->getPassword(), 148 | $command->getEmail(), 149 | ); 150 | 151 | $this->userRepository->save($user); 152 | } 153 | } 154 | ``` 155 | 156 | #### 1.1.3 - Register the CommandHandler 157 | 158 | I'm assuming you're using some kind Service Container. Now it's time to register your CommandHandler. 159 | 160 | For instance, in a `Psr\Container` compliant Service Container, we can do this as follows: 161 | 162 | ```php 163 | get('UserRepository'); 168 | }; 169 | ``` 170 | 171 | #### 1.1.4 - Setting up the CommandBus 172 | 173 | 174 | The Command Bus Middleware requires two classes to be injected. First one is the command translator, and second one the handler resolver. 175 | 176 | **CommandTranslator** 177 | 178 | Classes implementing this interface will provide the FQN for the Handler class given a Command. 179 | 180 | This package provides an implementation, `NilPortugues\MessageBus\CommandBus\Translator\AppendStrategy` which basically appends the word `Handler` to the provided `Command` class. 181 | 182 | 183 | For custom strategies, you may write your own implementing the `NilPortugues\MessageBus\CommandBus\Contracts\CommandTranslator` interface. 184 | 185 | **CommandHandlerResolver** 186 | 187 | Classes implementing this interface will be resolving the class for the instance required based on the output of the CommandTranslator used. 188 | 189 | This package provides an implementation, `NilPortugues\MessageBus\CommandBus\Resolver\PsrContainerResolver`, that expects any Service Container implementing the `Psr\Container` interface. 190 | 191 | For Symfony 2 and 3 framework users up to version 3.2, you should use Symfony Container: `NilPortugues\MessageBus\CommandBus\Resolver\SymfonyContainerResolver`. For Symfony 3.3 and up use the PSR-11 ContainerResolver class. 192 | 193 | #### 1.1.5 - Registering the remaining CommandBus classes 194 | 195 | The minimum set up to get the Command Bus working is: 196 | 197 | ```php 198 | get('CommandTranslator'), 212 | $container->get('CommandHandlerResolver'), 213 | ); 214 | }; 215 | 216 | $container['CommandBus'] = function($container) { 217 | return new \NilPortugues\MessageBus\CommandBus\CommandBus([ 218 | $container->get('CommandBusMiddleware'), 219 | ]); 220 | }; 221 | ``` 222 | 223 | If for instance, we want to log everything happening in the Command Bus, we'll add to the middleware list the logger middleware. This will wrap the Command Bus, being able to log before and after it ran, and if there was an error. 224 | 225 | ```php 226 | get('Monolog') 232 | ); 233 | }; 234 | 235 | //Update the CommandBus with the LoggerCommandBusMiddleware 236 | $container['CommandBus'] = function($container) { 237 | return new \NilPortugues\MessageBus\CommandBus\CommandBus([ 238 | $container->get('LoggerCommandBusMiddleware'), 239 | $container->get('CommandBusMiddleware'), 240 | ]); 241 | }; 242 | ``` 243 | 244 | #### 1.1.6 - Running the CommandBus 245 | 246 | Finally, to make use of the CommandBus, all you need to do is run this code: 247 | ```php 248 | get('CommandBus'); 250 | $command = new RegisterUser('MyUsername', 'MySecretPassword', 'hello@example.com'); 251 | $commandBus($command); 252 | ``` 253 | 254 | 255 | ### 1.2 - Predefined Middlewares 256 | 257 | **TransactionalCommandBusMiddleware** 258 | 259 | - **Class:** `NilPortugues\MessageBus\CommandBus\TransactionalCommandBusMiddleware` 260 | - Class construct method expects a PDO connection. It will wrap all the underlying middleware calls with `beginTransaction-commit` and `rollback` if any kind of exception is thrown. 261 | 262 | 263 | **LoggerQueryBusMiddleware** 264 | 265 | - **Class:** `NilPortugues\MessageBus\CommandBus\LoggerCommandBusMiddleware` 266 | - Class construct method expects a PSR3 Logger implementation. 267 | 268 | 269 | ### 1.3 - Custom Middlewares 270 | 271 | In order to write custom middleware a new class implementing the `NilPortugues\MessageBus\CommandBus\Contracts\CommandBusMiddleware` interface is required. 272 | 273 | ---- 274 | 275 | ## 2. QueryBus 276 | 277 | ### 2.1 - Usage 278 | 279 | #### 2.1.1 - Create a Query 280 | 281 | ```php 282 | userId = $userId; 292 | } 293 | 294 | public function getUserId() : string 295 | { 296 | return $this->userId; 297 | } 298 | } 299 | ``` 300 | 301 | #### 2.1.2 - Create a QueryHandler 302 | 303 | The Query Handler must implement the `QueryHandler` interface and implement the `__invoke` method. 304 | 305 | For instance: 306 | 307 | ```php 308 | userRepository = $userRepository; 320 | } 321 | 322 | public function __invoke(GetUser $query) : QueryResponse 323 | { 324 | $userId = $query->getUserId(); 325 | $user = $this->userRepository->find($userId); 326 | 327 | return new UserQueryResponse($user); 328 | } 329 | } 330 | ``` 331 | 332 | #### 2.1.3 - Create a QueryResponse 333 | 334 | Response queries are generic responses. 335 | 336 | If you take into account section 2.1.2, you'll see the UserQueryResponse has a $user injected into the constructor. 337 | This has been done in order to reuse the QueryResponse in other scenarios such as fetching an updated user. 338 | 339 | ```php 340 | get('UserRepository')); 365 | }; 366 | ``` 367 | 368 | #### 2.1.5 - Setting up the QueryBusMiddleware 369 | 370 | The Query Bus Middleware requires two classes to be injected. First one is the query translator, and second one the handler resolver. 371 | 372 | **QueryTranslator** 373 | 374 | Classes implementing this interface will provide the FQN for the Handler class given a Query. 375 | 376 | This package provides an implementation, `NilPortugues\MessageBus\QueryBus\Translator\AppendStrategy` which basically appends the word `Handler` to the provided `Query` class. 377 | 378 | 379 | For custom strategies, you may write your own implementing the `NilPortugues\MessageBus\QueryBus\Contracts\QueryTranslator` interface. 380 | 381 | **QueryHandlerResolver** 382 | 383 | Classes implementing this interface will be resolving the class for the instance required based on the output of the QueryTranslator used. 384 | 385 | This package provides an implementation, `NilPortugues\MessageBus\QueryBus\Resolver\PsrContainerResolver`, that expects any Service Container implementing the `Psr\Container` interface. 386 | 387 | For Symfony 2 and 3 framework users up to version 3.2, you should use Symfony Container: `NilPortugues\MessageBus\QueryBus\Resolver\SymfonyContainerResolver`. For Symfony 3.3 and up use the PSR-11 ContainerResolver class. 388 | 389 | #### 2.1.5 - Registering the remaining QueryBus classes 390 | 391 | The minimum set up to get the Query Bus working is: 392 | 393 | ```php 394 | get('QueryTranslator'), 408 | $container->get('QueryHandlerResolver'), 409 | ); 410 | }; 411 | 412 | $container['QueryBus'] = function($container) { 413 | return new \NilPortugues\MessageBus\QueryBus\QueryBus([ 414 | $container->get('QueryBusMiddleware'), 415 | ]); 416 | }; 417 | ``` 418 | 419 | If for instance, we want to log everything happening in the Query Bus, we'll add to the middleware list the logger middleware. This will wrap the Query Bus, being able to log before and after it ran, and if there was an error. 420 | 421 | ```php 422 | get('Monolog') 428 | ); 429 | }; 430 | 431 | //Update the QueryBus with the LoggerQueryBusMiddleware 432 | $container['QueryBus'] = function($container) { 433 | return new \NilPortugues\MessageBus\QueryBus\QueryBus([ 434 | $container->get('LoggerQueryBusMiddleware'), 435 | $container->get('QueryBusMiddleware'), 436 | ]); 437 | }; 438 | ``` 439 | 440 | #### 2.1.6 - Running the QueryBus 441 | 442 | Finally, to make use of the QueryBus, all you need to do is run this code: 443 | ```php 444 | get('QueryBus'); 446 | $query = new GetUser(1): 447 | $userQueryResponse = $queryBus($query); 448 | ``` 449 | 450 | 451 | ### 2.2 - Predefined Middlewares 452 | 453 | **CacheQueryBusMiddleware** 454 | 455 | - **Class**: `NilPortugues\MessageBus\QueryBus\CacheQueryBusMiddleware` 456 | - Class construct method expects a Serializer (see below), a PSR6 Caching implementation and queue name. 457 | 458 | **LoggerQueryBusMiddleware** 459 | 460 | - **Class**: `NilPortugues\MessageBus\QueryBus\LoggerQueryBusMiddleware` 461 | - Class construct method expects a PSR3 Logger implementation. 462 | 463 | 464 | ### 2.3 - Custom Middlewares 465 | 466 | In order to write custom middleware a new class implementing the `NilPortugues\MessageBus\QueryBus\Contracts\QueryBusMiddleware` interface is required. 467 | 468 | ---- 469 | 470 | ## 3. EventBus 471 | 472 | ### 3.1 - Usage 473 | 474 | 475 | #### 3.1.1 - Create an Event 476 | 477 | We'll be creating an Event. Due to the nature of events, an event may be mapped to one or more Event Handlers. 478 | 479 | ```php 480 | userId = $userId; 491 | $this->email = $email; 492 | } 493 | 494 | public function getUserId() : string 495 | { 496 | return $this->userId; 497 | } 498 | 499 | public function getEmail() : string 500 | { 501 | return $this->email; 502 | } 503 | } 504 | ``` 505 | 506 | #### 3.1.2 - Create an EventHandler 507 | 508 | To illustrate the power of eventing, we'll map the previous event `UserRegistered` to two EventHandlers. 509 | 510 | **First Event Handler** 511 | 512 | First event handler we'll create assumes we've got an email service to send a welcome email. 513 | 514 | ```php 515 | emailProvider = $emailProvider; 526 | } 527 | 528 | public function __invoke(UserRegistered $event) 529 | { 530 | $this->guard($event); 531 | $this->emailProvider->send('welcome_email', $event->getEmail()); 532 | } 533 | 534 | public static function subscribedTo() : string 535 | { 536 | return UserRegistered::class; 537 | } 538 | } 539 | ``` 540 | 541 | **Second Event Handler** 542 | 543 | Second event handler we'll create the relationships in our database for user friends and user credits. 544 | 545 | ```php 546 | userFriendsRepository = $userFriendsRepository; 558 | $this->userCreditsRepository = $userCreditsRepository; 559 | } 560 | 561 | public function __invoke(UserRegistered $event) 562 | { 563 | $this->userFriendsRepository->add(new UserFriendsCollection($event->getUserId(), [])); 564 | $this->userCreditsRepository->add(new UserCredits($event->getUserId(), new Credits(0)); 565 | } 566 | 567 | public static function subscribedTo() : string 568 | { 569 | return UserRegistered::class; 570 | } 571 | } 572 | ``` 573 | 574 | 575 | #### 3.1.3 - (Optional) Set the EventHandler's Priority 576 | 577 | Sometimes you want or must make sure an action precedes another one. 578 | 579 | By default, all events have a priority, this being set by the `EventHandlerPriority::LOW_PRIORITY` constant value. 580 | 581 | To implement your priority order in your classes implement the `EventHandler` interface, must implement another interface, the `EventHandlerPriority`. 582 | 583 | For instance, if we would like `SendWelcomeEmailHandler` to happen after `SetupUserAccountHandler`, we should give the first less priority, or the latter more. 584 | 585 | **SetupUserAccountHandler should go first when dispatching event UserRegistered** 586 | 587 | ```php 588 | get('UserFriendRepository'), 650 | $container->get('UserCreditsRepository') 651 | ); 652 | }; 653 | $container['SendWelcomeEmailHandler'] = function($container) { 654 | return new SendWelcomeEmailHandler($container->get('EmailProvider'); 655 | }; 656 | ``` 657 | 658 | 659 | #### 3.1.5 - Setting up the EventBusMiddleware 660 | 661 | The Event Bus Middleware requires two classes to be injected. First one is the Event translator, and second one the handler resolver. 662 | 663 | **EventTranslator** 664 | 665 | Takes care of registering the EventHandlers subscribed to an Event. 666 | 667 | Its implementation can be found at: `NilPortugues\MessageBus\EventBus\Translator\EventFullyQualifiedClassNameStrategy`. 668 | 669 | **EventHandlerResolver** 670 | 671 | Classes implementing this interface will be resolving the class for the instance required based on the output of the EventTranslator used. 672 | 673 | This package provides an implementation, `NilPortugues\MessageBus\EventBus\Resolver\PsrContainerResolver`, that expects any Service Container implementing the `Psr\Container` interface. 674 | 675 | For Symfony 2 and 3 framework users up to version 3.2, you should use Symfony Container: `NilPortugues\MessageBus\EventBus\Resolver\SymfonyContainerResolver`. For Symfony 3.3 and up use the PSR-11 ContainerResolver class. 676 | 677 | #### 3.1.6 - Registering the remaining EventBus classes 678 | 679 | 680 | The minimum set up to get the Event Bus working is: 681 | 682 | ```php 683 | get('EventTranslator'), 702 | $container->get('EventHandlerResolver'), 703 | ); 704 | }; 705 | 706 | $container['EventBus'] = function($container) { 707 | return new \NilPortugues\MessageBus\EventBus\EventBus([ 708 | $container->get('EventBusMiddleware'), 709 | ]); 710 | }; 711 | ``` 712 | 713 | If for instance, we want to log everything happening in the Event Bus, we'll add to the middleware list the logger middleware. This will wrap the Event Bus, being able to log before and after it ran, and if there was an error. 714 | 715 | ```php 716 | get('Monolog') 722 | ); 723 | }; 724 | 725 | //Update the EventBus with the LoggerEventBusMiddleware 726 | $container['EventBus'] = function($container) { 727 | return new \NilPortugues\MessageBus\EventBus\EventBus([ 728 | $container->get('LoggerEventBusMiddleware'), 729 | $container->get('EventBusMiddleware'), 730 | ]); 731 | }; 732 | ``` 733 | 734 | #### 3.1.7 - Running the EventBus 735 | 736 | Finally, to make use of the EventBus, all you need to do is run this code: 737 | ```php 738 | get('EventBus'); 740 | $Event = new GetUser(1): 741 | $userEventResponse = $eventBus($Event); 742 | ``` 743 | 744 | #### 3.1.8 - (Optional) Running the EventBus as a Queue 745 | 746 | **Save your users time and load your pages faster! Go asynchronous using a queue.** 747 | 748 | To do so, you'll have to require an additional package: **EventBus Queue**. This extension can be downloaded using composer: 749 | 750 | ``` 751 | composer require nilportugues/eventbus-queue 752 | ``` 753 | 754 | [Documentation and installation guide can be found in its repository](https://github.com/PHPMessageBus/eventbus-queue). 755 | 756 | ### 3.2 - Predefined Middlewares 757 | 758 | **TransactionalEventBusMiddleware** 759 | 760 | - **Class**: `NilPortugues\MessageBus\EventBus\TransactionalEventBusMiddleware` 761 | - Class construct method expects a PDO connection. It will wrap all the underlying middleware calls with beginTransaction-commit and rollback if any kind of exception is thrown. 762 | 763 | **LoggerEventBusMiddleware** 764 | 765 | - **Class**: `NilPortugues\MessageBus\EventBus\LoggerEventBusMiddleware` 766 | - Class construct method expects a PSR3 Logger implementation. 767 | 768 | **ProducerEventBusMiddleware** 769 | 770 | - **Class**: `NilPortugues\MessageBus\EventBusQueue\ProducerEventBusMiddleware` 771 | - Adds events to an Event Queue. Required running `composer require nilportugues/eventbus-queue` first. 772 | 773 | 774 | ### 3.3 - Custom Middlewares 775 | 776 | In order to write custom middleware a new class implementing the `NilPortugues\MessageBus\EventBus\Contracts\EventBusMiddleware` interface is required. 777 | 778 | 779 | --- 780 | 781 | ## 4 - Serializers 782 | 783 | Serializers are to be used mainly all the `ProducerEventBusMiddleware` classes. You may also find this in Cache classes. 784 | 785 | Choose one or another depending on your needs. 786 | 787 | ### 4.1 - NilPortugues\MessageBus\Serializer\NativeSerializer 788 | 789 | For caching, this is the best option. 790 | 791 | In the EventBus use this if your Consumer is written in PHP and will share the same code base as the object serialized. 792 | 793 | - **Pros:** Fastest serialization possible. 794 | - **Cons:** Consumer must be written in PHP and classes must be available or unserialize will fail. 795 | 796 | ### 4.2 - NilPortugues\MessageBus\Serializer\JsonSerializer 797 | 798 | Not recommended for caching. 799 | 800 | In the EventBus use this if your Consumer is written in PHP but your consumers may be written in many languages. 801 | 802 | - **Pros:** If consumer is PHP, the data will be restored and if sharing the same code base as the object serialized, an object can be obtained on unserialize. If not, you may be able to fetch data manually as regular JSON. 803 | - **Cons** : If fetching data from the data-store as JSON it will hold references to the PHP data-structure, but does not interfere consuming data. 804 | 805 | ### 4.3 - NilPortugues\MessageBus\Serializer\JsonObjectSerializer 806 | 807 | Doesn't work for caching. 808 | 809 | In the EventBus use this if your Consumer is written in PHP but you're not consuming data currently. 810 | 811 | - **Pros:** JSON can be reused to consume this data in the future as its supported everywhere. 812 | - **Cons:** You'll have to write your consumer to read the JSON structure. 813 | 814 | 815 | ## Contribute 816 | 817 | Contributions to the package are always welcome! 818 | 819 | * Report any bugs or issues you find on the [issue tracker](https://github.com/PHPMessageBus/messagebus/issues/new). 820 | * You can grab the source code at the package's [Git repository](https://github.com/PHPMessageBus/message-bus). 821 | 822 | 823 | ## Support 824 | 825 | Get in touch with me using one of the following means: 826 | 827 | - Emailing me at 828 | - Opening an [Issue](https://github.com/PHPMessageBus/message-bus/issues/new) 829 | 830 | 831 | ## Authors 832 | 833 | * [Nil Portugués Calderó](https://nilportugues.com/) 834 | * [The Community Contributors](https://github.com/PHPMessageBus/message-bus/graphs/contributors) 835 | 836 | 837 | ## License 838 | The code base is licensed under the [MIT license](LICENSE). 839 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nilportugues/messagebus", 3 | "description": "MessageBus library. Contains CommandBus, QueryBus and EventBus and multiple middleware implementations.", 4 | "type": "library", 5 | "homepage": "http://nilportugues.com", 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Nil Portugués Calderó", 10 | "email": "contact@nilportugues.com" 11 | } 12 | ], 13 | "require": { 14 | "php": ">=7", 15 | "container-interop/container-interop": "^1.2", 16 | "nilportugues/assert": "^1.0", 17 | "nilportugues/serializer": "^1.2", 18 | "psr/container": "^1.0", 19 | "psr/log": "^1.0", 20 | "psr/cache": "^1.0" 21 | }, 22 | "require-dev": { 23 | "phpunit/phpunit": "5.2.*", 24 | "fabpot/php-cs-fixer": "~1.9", 25 | "symfony/dependency-injection": "~2.7|~3.0" 26 | }, 27 | "prefer-stable": true, 28 | "autoload": { 29 | "psr-4": { 30 | "NilPortugues\\MessageBus\\": "src" 31 | } 32 | }, 33 | "autoload-dev": { 34 | "psr-4": { 35 | "NilPortugues\\Tests\\MessageBus\\": "tests/" 36 | } 37 | }, 38 | "scripts": { 39 | "tests": "php vendor/bin/phpunit", 40 | "fixer": "php vendor/bin/php-cs-fixer fix src && php vendor/bin/php-cs-fixer fix tests" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | ./tests 33 | 34 | 35 | 36 | 37 | 38 | ./ 39 | 40 | ./tests 41 | ./vendor/ 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/CommandBus/CommandBus.php: -------------------------------------------------------------------------------- 1 | middleware = $middleware; 26 | } 27 | 28 | /** 29 | * @param Command $command 30 | * @param callable|null $next 31 | */ 32 | public function __invoke(Command $command, callable $next = null) 33 | { 34 | $middleware = $this->middleware; 35 | $current = array_shift($middleware); 36 | 37 | if (empty($middleware) && !empty($current)) { 38 | $current->__invoke($command); 39 | 40 | return; 41 | } 42 | 43 | foreach ($middleware as $commandBusMiddleware) { 44 | $callable = function ($command) use ($commandBusMiddleware) { 45 | return $commandBusMiddleware($command); 46 | }; 47 | 48 | $current->__invoke($command, $callable); 49 | $current = $commandBusMiddleware; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/CommandBus/CommandBusMiddleware.php: -------------------------------------------------------------------------------- 1 | commandTranslator = $commandTranslator; 26 | $this->handlerResolver = $handlerResolver; 27 | } 28 | 29 | /** 30 | * @param Command $command 31 | * @param callable|null $next 32 | */ 33 | public function __invoke(Command $command, callable $next = null) 34 | { 35 | $handlerName = $this->commandTranslator->handlerName($command); 36 | 37 | /** @var $handlerInstance CommandHandler */ 38 | $handlerInstance = $this->handlerResolver->instantiate($handlerName); 39 | $handlerInstance($command); 40 | 41 | if ($next) { 42 | $next($command); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/CommandBus/Contracts/Command.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 27/02/16 5 | * Time: 10:24. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\CommandBus\Contracts; 12 | 13 | /** 14 | * Interface Command. 15 | */ 16 | interface Command 17 | { 18 | } 19 | -------------------------------------------------------------------------------- /src/CommandBus/Contracts/CommandBusMiddleware.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 29/02/16 5 | * Time: 23:55. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\CommandBus\Contracts; 12 | 13 | /** 14 | * Interface CommandBusMiddleware. 15 | */ 16 | interface CommandBusMiddleware 17 | { 18 | /** 19 | * @param Command $command 20 | * @param callable $next 21 | */ 22 | public function __invoke(Command $command, callable $next = null); 23 | } 24 | -------------------------------------------------------------------------------- /src/CommandBus/Contracts/CommandHandler.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 27/02/16 5 | * Time: 10:24. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\CommandBus\Contracts; 12 | 13 | /** 14 | * Interface CommandHandler. 15 | */ 16 | interface CommandHandler 17 | { 18 | } 19 | -------------------------------------------------------------------------------- /src/CommandBus/Contracts/CommandHandlerResolver.php: -------------------------------------------------------------------------------- 1 | logger = $logger; 23 | } 24 | 25 | /** 26 | * @param Command $command 27 | * @param callable|null $next 28 | */ 29 | public function __invoke(Command $command, callable $next = null) 30 | { 31 | try { 32 | if ($next) { 33 | $this->preCommandLog($command); 34 | $next($command); 35 | $this->postCommandLog($command); 36 | } 37 | } catch (Exception $e) { 38 | $this->logException($e); 39 | } 40 | } 41 | 42 | /** 43 | * @param Command $command 44 | */ 45 | protected function preCommandLog(Command $command) 46 | { 47 | $this->logger->info(sprintf('Starting %s handling.', get_class($command))); 48 | } 49 | 50 | /** 51 | * @param Command $command 52 | */ 53 | protected function postCommandLog(Command $command) 54 | { 55 | $this->logger->info(sprintf('%s was handled successfully.', get_class($command))); 56 | } 57 | 58 | /** 59 | * @param Exception $e 60 | */ 61 | protected function logException(Exception $e) 62 | { 63 | $this->logger->alert(sprintf('[%s:%s] %s', $e->getFile(), $e->getLine(), $e->getMessage())); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/CommandBus/Resolver/InteropContainerResolver.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:11. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\CommandBus\Resolver; 12 | 13 | use Interop\Container\ContainerInterface; 14 | use InvalidArgumentException; 15 | use NilPortugues\MessageBus\CommandBus\Contracts\CommandHandler; 16 | use NilPortugues\MessageBus\CommandBus\Contracts\CommandHandlerResolver; 17 | 18 | /** 19 | * Class InteropContainerResolver. 20 | */ 21 | class InteropContainerResolver implements CommandHandlerResolver 22 | { 23 | /** @var ContainerInterface */ 24 | protected $container; 25 | 26 | /** 27 | * InteropContainerResolver constructor. 28 | * 29 | * @param ContainerInterface $container 30 | */ 31 | public function __construct(ContainerInterface $container) 32 | { 33 | $this->container = $container; 34 | } 35 | 36 | /** 37 | * Given a string to identify the Command Handler, return the instance. 38 | * 39 | * @param string $handler 40 | * 41 | * @return CommandHandler 42 | */ 43 | public function instantiate(string $handler) : CommandHandler 44 | { 45 | if (false === $this->container->has($handler)) { 46 | throw new InvalidArgumentException( 47 | sprintf('Handler %s could not be found. Did you register it?', $handler) 48 | ); 49 | } 50 | 51 | return $this->container->get($handler); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/CommandBus/Resolver/PsrContainerResolver.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:11. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\CommandBus\Resolver; 12 | 13 | use Psr\Container\ContainerInterface; 14 | 15 | /** 16 | * Class PsrContainerResolver. 17 | */ 18 | class PsrContainerResolver extends InteropContainerResolver 19 | { 20 | /** 21 | * PsrContainerResolver constructor. 22 | * 23 | * @param ContainerInterface $container 24 | */ 25 | public function __construct(ContainerInterface $container) 26 | { 27 | $this->container = $container; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/CommandBus/Resolver/SimpleArrayResolver.php: -------------------------------------------------------------------------------- 1 | handlers = $handlers; 22 | } 23 | 24 | /** 25 | * Given a string to identify the Command Handler, return the instance. 26 | * 27 | * @param string $handler 28 | * 29 | * @return CommandHandler 30 | * 31 | * @throws InvalidArgumentException 32 | */ 33 | public function instantiate(string $handler) : CommandHandler 34 | { 35 | if (false === isset($this->handlers[$handler])) { 36 | throw new InvalidArgumentException( 37 | sprintf('Handler %s could not be found. Did you register it?', $handler) 38 | ); 39 | } 40 | 41 | $callable = $this->handlers[$handler]; 42 | 43 | return ($callable instanceof \Closure) ? $callable() : new $callable(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/CommandBus/Resolver/SymfonyContainerResolver.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 15/02/17 5 | * Time: 11:13. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\CommandBus\Resolver; 12 | 13 | use Symfony\Component\DependencyInjection\ContainerInterface; 14 | use InvalidArgumentException; 15 | use NilPortugues\MessageBus\CommandBus\Contracts\CommandHandler; 16 | use NilPortugues\MessageBus\CommandBus\Contracts\CommandHandlerResolver; 17 | 18 | /** 19 | * Class SymfonyContainerResolver. 20 | */ 21 | class SymfonyContainerResolver implements CommandHandlerResolver 22 | { 23 | /** @var ContainerInterface */ 24 | protected $container; 25 | 26 | /** 27 | * SymfonyContainerResolver constructor. 28 | * 29 | * @param ContainerInterface $container 30 | */ 31 | public function __construct(ContainerInterface $container) 32 | { 33 | $this->container = $container; 34 | } 35 | 36 | /** 37 | * Given a string to identify the Command Handler, return the instance. 38 | * 39 | * @param string $handler 40 | * 41 | * @return CommandHandler 42 | */ 43 | public function instantiate(string $handler) : CommandHandler 44 | { 45 | $handler = ltrim($handler, '\\'); 46 | if (false === $this->container->has($handler)) { 47 | throw new InvalidArgumentException( 48 | sprintf('Handler %s could not be found. Did you register it?', $handler) 49 | ); 50 | } 51 | 52 | return $this->container->get($handler); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/CommandBus/TransactionalCommandBusMiddleware.php: -------------------------------------------------------------------------------- 1 | pdo = $pdo; 22 | } 23 | 24 | /** 25 | * @param Command $command 26 | * @param callable|null $next 27 | */ 28 | public function __invoke(Command $command, callable $next = null) 29 | { 30 | try { 31 | $this->pdo->beginTransaction(); 32 | $next($command); 33 | $this->pdo->commit(); 34 | } catch (\PDOException $exception) { 35 | $this->pdo->rollBack(); 36 | throw $exception; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/CommandBus/Translator/AppendStrategy.php: -------------------------------------------------------------------------------- 1 | append = $append; 28 | } 29 | 30 | /** 31 | * Given a command, find the Command Handler's name. 32 | * 33 | * @param Command $command 34 | * 35 | * @return string 36 | */ 37 | public function handlerName(Command $command) : string 38 | { 39 | return sprintf('%s%s', get_class($command), $this->append); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/EventBus/Contracts/Event.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 17/03/16 5 | * Time: 22:00. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\EventBus\Contracts; 12 | 13 | /** 14 | * Interface Event. 15 | */ 16 | interface Event 17 | { 18 | } 19 | -------------------------------------------------------------------------------- /src/EventBus/Contracts/EventBusMiddleware.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 29/02/16 5 | * Time: 23:55. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\EventBus\Contracts; 12 | 13 | /** 14 | * Interface EventBusMiddleware. 15 | */ 16 | interface EventBusMiddleware 17 | { 18 | /** 19 | * @param Event $event 20 | * @param callable|null $next 21 | */ 22 | public function __invoke(Event $event, callable $next = null); 23 | } 24 | -------------------------------------------------------------------------------- /src/EventBus/Contracts/EventHandler.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 17/03/16 5 | * Time: 22:01. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\EventBus\Contracts; 12 | 13 | /** 14 | * Interface EventHandler. 15 | */ 16 | interface EventHandler 17 | { 18 | /** 19 | * Returns the name of the event subscribed to. 20 | * 21 | * @return string 22 | */ 23 | public static function subscribedTo() : string; 24 | } 25 | -------------------------------------------------------------------------------- /src/EventBus/Contracts/EventHandlerPriority.php: -------------------------------------------------------------------------------- 1 | middleware = $middleware; 29 | } 30 | 31 | /** 32 | * @param Event $event 33 | * @param callable|null $next 34 | */ 35 | public function __invoke(Event $event, callable $next = null) 36 | { 37 | $middleware = $this->middleware; 38 | $current = array_shift($middleware); 39 | 40 | if (empty($middleware) && !empty($current)) { 41 | $current->__invoke($event); 42 | 43 | return; 44 | } 45 | 46 | foreach ($middleware as $eventBusMiddleware) { 47 | $callable = function ($event) use ($eventBusMiddleware) { 48 | return $eventBusMiddleware($event); 49 | }; 50 | 51 | $current->__invoke($event, $callable); 52 | $current = $eventBusMiddleware; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/EventBus/EventBusMiddleware.php: -------------------------------------------------------------------------------- 1 | eventTranslator = $eventTranslator; 28 | $this->handlerResolver = $handlerResolver; 29 | } 30 | 31 | /** 32 | * @param Event $event 33 | * @param callable|null $next 34 | */ 35 | public function __invoke(Event $event, callable $next = null) 36 | { 37 | $handlerNames = $this->eventTranslator->handlerName($event); 38 | 39 | foreach ($handlerNames as $handlerLists) { 40 | foreach ($handlerLists as $handlerName) { 41 | $handlerInstance = $this->handlerResolver->instantiate($handlerName); 42 | $handlerInstance($event); 43 | } 44 | } 45 | 46 | if ($next) { 47 | $next($event); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/EventBus/LoggerEventBusMiddleware.php: -------------------------------------------------------------------------------- 1 | logger = $logger; 26 | } 27 | 28 | /** 29 | * @param Event $event 30 | * @param callable|null $next 31 | */ 32 | public function __invoke(Event $event, callable $next = null) 33 | { 34 | try { 35 | if ($next) { 36 | $this->preEventLog($event); 37 | $next($event); 38 | $this->postEventLog($event); 39 | } 40 | } catch (Exception $e) { 41 | $this->logException($e); 42 | } 43 | } 44 | 45 | /** 46 | * @param Event $event 47 | */ 48 | protected function preEventLog(Event $event) 49 | { 50 | $this->logger->info(sprintf('Starting %s handling.', get_class($event))); 51 | } 52 | 53 | /** 54 | * @param Event $event 55 | */ 56 | protected function postEventLog(Event $event) 57 | { 58 | $this->logger->info(sprintf('%s was handled successfully.', get_class($event))); 59 | } 60 | 61 | /** 62 | * @param Exception $e 63 | */ 64 | protected function logException(Exception $e) 65 | { 66 | $this->logger->alert(sprintf('[%s:%s] %s', $e->getFile(), $e->getLine(), $e->getMessage())); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/EventBus/Resolver/InteropContainerResolver.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:11. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\EventBus\Resolver; 12 | 13 | use Interop\Container\ContainerInterface; 14 | use InvalidArgumentException; 15 | use NilPortugues\MessageBus\EventBus\Contracts\EventHandler; 16 | use NilPortugues\MessageBus\EventBus\Contracts\EventHandlerResolver; 17 | 18 | /** 19 | * Class InteropContainerResolver. 20 | */ 21 | class InteropContainerResolver implements EventHandlerResolver 22 | { 23 | /** @var ContainerInterface */ 24 | protected $container; 25 | 26 | /** 27 | * InteropContainerResolver constructor. 28 | * 29 | * @param ContainerInterface $container 30 | */ 31 | public function __construct(ContainerInterface $container) 32 | { 33 | $this->container = $container; 34 | } 35 | 36 | /** 37 | * Given a string to identify the Event Handler, return the instance. 38 | * 39 | * @param string $handler 40 | * 41 | * @return EventHandler 42 | */ 43 | public function instantiate(string $handler) : EventHandler 44 | { 45 | if (false === $this->container->has($handler)) { 46 | throw new InvalidArgumentException( 47 | sprintf('Handler %s could not be found. Did you register it?', $handler) 48 | ); 49 | } 50 | 51 | return $this->container->get($handler); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/EventBus/Resolver/PsrContainerResolver.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:11. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\EventBus\Resolver; 12 | 13 | use Psr\Container\ContainerInterface; 14 | 15 | /** 16 | * Class PsrContainerResolver. 17 | */ 18 | class PsrContainerResolver extends InteropContainerResolver 19 | { 20 | /** 21 | * PsrContainerResolver constructor. 22 | * 23 | * @param ContainerInterface $container 24 | */ 25 | public function __construct(ContainerInterface $container) 26 | { 27 | $this->container = $container; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/EventBus/Resolver/SimpleArrayResolver.php: -------------------------------------------------------------------------------- 1 | handlers = $handlers; 22 | } 23 | 24 | /** 25 | * Given a string to identify the Event Handler, return the instance. 26 | * 27 | * @param string $handler 28 | * 29 | * @return EventHandler 30 | * 31 | * @throws InvalidArgumentException 32 | */ 33 | public function instantiate(string $handler) : EventHandler 34 | { 35 | if (false === isset($this->handlers[$handler])) { 36 | throw new InvalidArgumentException( 37 | sprintf('Handler %s could not be found. Did you register it?', $handler) 38 | ); 39 | } 40 | 41 | $callable = $this->handlers[$handler]; 42 | 43 | return ($callable instanceof \Closure) ? $callable() : new $callable(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/EventBus/Resolver/SymfonyContainerResolver.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:11. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\EventBus\Resolver; 12 | 13 | use Symfony\Component\DependencyInjection\ContainerInterface; 14 | use InvalidArgumentException; 15 | use NilPortugues\MessageBus\EventBus\Contracts\EventHandler; 16 | use NilPortugues\MessageBus\EventBus\Contracts\EventHandlerResolver; 17 | 18 | /** 19 | * Class SymfonyContainerResolver. 20 | */ 21 | class SymfonyContainerResolver implements EventHandlerResolver 22 | { 23 | /** @var ContainerInterface */ 24 | protected $container; 25 | 26 | /** 27 | * SymfonyContainerResolver constructor. 28 | * 29 | * @param ContainerInterface $container 30 | */ 31 | public function __construct(ContainerInterface $container) 32 | { 33 | $this->container = $container; 34 | } 35 | 36 | /** 37 | * Given a string to identify the Event Handler, return the instance. 38 | * 39 | * @param string $handler 40 | * 41 | * @return EventHandler 42 | */ 43 | public function instantiate(string $handler) : EventHandler 44 | { 45 | $handler = ltrim($handler, '\\'); 46 | if (false === $this->container->has($handler)) { 47 | throw new InvalidArgumentException( 48 | sprintf('Handler %s could not be found. Did you register it?', $handler) 49 | ); 50 | } 51 | 52 | return $this->container->get($handler); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/EventBus/TransactionalEventBusMiddleware.php: -------------------------------------------------------------------------------- 1 | pdo = $pdo; 25 | } 26 | 27 | /** 28 | * @param Event $event 29 | * @param callable|null $next 30 | */ 31 | public function __invoke(Event $event, callable $next = null) 32 | { 33 | try { 34 | $this->pdo->beginTransaction(); 35 | $next($event); 36 | $this->pdo->commit(); 37 | } catch (\PDOException $exception) { 38 | $this->pdo->rollBack(); 39 | throw $exception; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/EventBus/Translator/EventFullyQualifiedClassNameStrategy.php: -------------------------------------------------------------------------------- 1 | listeners[$handler::subscribedTo()][$priority][] = $handler; 46 | } 47 | } 48 | 49 | /** 50 | * {@inheritdoc} 51 | */ 52 | public function handlerName(Event $event) : array 53 | { 54 | $eventClass = get_class($event); 55 | 56 | if (empty($this->listeners[$eventClass])) { 57 | throw new RuntimeException(sprintf('Event %s has no EventHandler defined.', $eventClass)); 58 | } 59 | 60 | ksort($this->listeners[$eventClass], SORT_NUMERIC); 61 | 62 | return $this->listeners[$eventClass]; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/QueryBus/CacheQueryBusMiddleware.php: -------------------------------------------------------------------------------- 1 | cache = $cacheItemPool; 36 | $this->serializer = $serializer; 37 | $this->ttl = $expirationInSeconds; 38 | } 39 | 40 | /** 41 | * @param Query $query 42 | * @param callable|null $next 43 | * 44 | * @return QueryResponse 45 | */ 46 | public function __invoke(Query $query, callable $next = null) : QueryResponse 47 | { 48 | if (null === $next) { 49 | throw new InvalidArgumentException('callable $next must not be null.'); 50 | } 51 | 52 | $cache = $this->cache->getItem($this->queryHashing($query)); 53 | 54 | if ($cache->isHit()) { 55 | return $this->serializer->unserialize($cache->get()); 56 | } 57 | 58 | $response = $next($query); 59 | 60 | $cache->set($this->serializer->serialize($response)); 61 | $cache->expiresAfter($this->ttl); 62 | $this->cache->save($cache); 63 | 64 | return $response; 65 | } 66 | 67 | /** 68 | * @param Query $query 69 | * 70 | * @return string 71 | */ 72 | protected function queryHashing(Query $query) : string 73 | { 74 | return md5(serialize($query)); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/QueryBus/Contracts/Query.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 27/02/16 5 | * Time: 10:25. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\QueryBus\Contracts; 12 | 13 | /** 14 | * Interface Query. 15 | */ 16 | interface Query 17 | { 18 | } 19 | -------------------------------------------------------------------------------- /src/QueryBus/Contracts/QueryBusMiddleware.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 29/02/16 5 | * Time: 23:55. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\QueryBus\Contracts; 12 | 13 | /** 14 | * Interface QueryBusMiddleware. 15 | */ 16 | interface QueryBusMiddleware 17 | { 18 | /** 19 | * @param Query $query 20 | * @param callable|null $next 21 | * 22 | * @return QueryResponse 23 | */ 24 | public function __invoke(Query $query, callable $next = null) : QueryResponse; 25 | } 26 | -------------------------------------------------------------------------------- /src/QueryBus/Contracts/QueryHandler.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 27/02/16 5 | * Time: 10:25. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\QueryBus\Contracts; 12 | 13 | /** 14 | * Interface QueryHandler. 15 | */ 16 | interface QueryHandler 17 | { 18 | } 19 | -------------------------------------------------------------------------------- /src/QueryBus/Contracts/QueryHandlerResolver.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 17/03/16 5 | * Time: 21:56. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\QueryBus\Contracts; 12 | 13 | /** 14 | * Interface QueryResponse. 15 | */ 16 | interface QueryResponse 17 | { 18 | } 19 | -------------------------------------------------------------------------------- /src/QueryBus/Contracts/QueryTranslator.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 29/03/16 5 | * Time: 22:40. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\QueryBus; 12 | 13 | use NilPortugues\MessageBus\QueryBus\Contracts\QueryResponse; 14 | 15 | /** 16 | * Class EmptyResponse. 17 | */ 18 | class EmptyResponse implements QueryResponse 19 | { 20 | /** 21 | * @var EmptyResponse The reference to *Singleton* instance of this class 22 | */ 23 | private static $instance; 24 | 25 | /** 26 | * Protected constructor to prevent creating a new instance of the 27 | * *Singleton* via the `new` operator from outside of this class. 28 | */ 29 | protected function __construct() 30 | { 31 | } 32 | 33 | /** 34 | * Returns the *Singleton* instance of this class. 35 | * 36 | * @return EmptyResponse The *Singleton* instance 37 | */ 38 | public static function create() : EmptyResponse 39 | { 40 | if (null === static::$instance) { 41 | static::$instance = new static(); 42 | } 43 | 44 | return static::$instance; 45 | } 46 | 47 | /** 48 | * Private clone method to prevent cloning of the instance of the 49 | * *Singleton* instance. 50 | * 51 | * @codeCoverageIgnore 52 | */ 53 | private function __clone() 54 | { 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/QueryBus/LoggerQueryBusMiddleware.php: -------------------------------------------------------------------------------- 1 | logger = $logger; 24 | } 25 | 26 | /** 27 | * @param Query $query 28 | * @param callable|null $next 29 | * 30 | * @return QueryResponse 31 | * 32 | * @throws Exception 33 | */ 34 | public function __invoke(Query $query, callable $next = null) : QueryResponse 35 | { 36 | $response = EmptyResponse::create(); 37 | 38 | try { 39 | if (null !== $next) { 40 | $this->preQueryLog($query); 41 | $response = $next($query); 42 | $this->postQueryLog($query); 43 | 44 | return $response; 45 | } 46 | } catch (Exception $e) { 47 | $this->logException($e); 48 | } 49 | 50 | return $response; 51 | } 52 | 53 | /** 54 | * @param Query $query 55 | */ 56 | protected function preQueryLog(Query $query) 57 | { 58 | $this->logger->info(sprintf('Starting %s handling.', get_class($query))); 59 | } 60 | 61 | /** 62 | * @param Query $query 63 | */ 64 | protected function postQueryLog(Query $query) 65 | { 66 | $this->logger->info(sprintf('%s was handled successfully.', get_class($query))); 67 | } 68 | 69 | /** 70 | * @param Exception $e 71 | */ 72 | protected function logException(Exception $e) 73 | { 74 | $this->logger->alert(sprintf('[%s:%s] %s', $e->getFile(), $e->getLine(), $e->getMessage())); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/QueryBus/QueryBus.php: -------------------------------------------------------------------------------- 1 | middleware = $middleware; 27 | } 28 | 29 | /** 30 | * @param Query $query 31 | * @param callable|null $next 32 | * 33 | * @return QueryResponse 34 | */ 35 | public function __invoke(Query $query, callable $next = null) : QueryResponse 36 | { 37 | $middleware = $this->middleware; 38 | $current = array_shift($middleware); 39 | 40 | if (!empty($middleware)) { 41 | foreach ($middleware as $queryBusMiddleware) { 42 | $callable = function ($query) use ($queryBusMiddleware) { 43 | return $queryBusMiddleware->__invoke($query); 44 | }; 45 | 46 | $response = $current->__invoke($query, $callable); 47 | $current = $queryBusMiddleware; 48 | } 49 | } elseif ($current) { 50 | $response = $current->__invoke($query); 51 | } 52 | 53 | return (!empty($response)) ? $response : EmptyResponse::create(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/QueryBus/QueryBusMiddleware.php: -------------------------------------------------------------------------------- 1 | queryTranslator = $queryTranslator; 27 | $this->handlerResolver = $handlerResolver; 28 | } 29 | 30 | /** 31 | * @param Query $query 32 | * @param callable|null $next 33 | * 34 | * @return QueryResponse 35 | */ 36 | public function __invoke(Query $query, callable $next = null) : QueryResponse 37 | { 38 | $handlerName = $this->queryTranslator->handlerName($query); 39 | 40 | /** @var $handlerInstance QueryHandler */ 41 | $handlerInstance = $this->handlerResolver->instantiate($handlerName); 42 | 43 | return $handlerInstance($query); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/QueryBus/Resolver/InteropContainerResolver.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:11. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\QueryBus\Resolver; 12 | 13 | use Interop\Container\ContainerInterface; 14 | use InvalidArgumentException; 15 | use NilPortugues\MessageBus\QueryBus\Contracts\QueryHandler; 16 | use NilPortugues\MessageBus\QueryBus\Contracts\QueryHandlerResolver; 17 | 18 | /** 19 | * Class InteropContainerResolver. 20 | */ 21 | class InteropContainerResolver implements QueryHandlerResolver 22 | { 23 | /** @var ContainerInterface */ 24 | protected $container; 25 | 26 | /** 27 | * InteropContainerResolver constructor. 28 | * 29 | * @param ContainerInterface $container 30 | */ 31 | public function __construct(ContainerInterface $container) 32 | { 33 | $this->container = $container; 34 | } 35 | 36 | /** 37 | * Given a string to identify the Query Handler, return the instance. 38 | * 39 | * @param string $handler 40 | * 41 | * @return QueryHandler 42 | */ 43 | public function instantiate(string $handler) : QueryHandler 44 | { 45 | if (false === $this->container->has($handler)) { 46 | throw new InvalidArgumentException( 47 | sprintf('Handler %s could not be found. Did you register it?', $handler) 48 | ); 49 | } 50 | 51 | return $this->container->get($handler); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/QueryBus/Resolver/PsrContainerResolver.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:11. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\QueryBus\Resolver; 12 | 13 | use Psr\Container\ContainerInterface; 14 | 15 | /** 16 | * Class PsrContainerResolver. 17 | */ 18 | class PsrContainerResolver extends InteropContainerResolver 19 | { 20 | /** 21 | * PsrContainerResolver constructor. 22 | * 23 | * @param ContainerInterface $container 24 | */ 25 | public function __construct(ContainerInterface $container) 26 | { 27 | $this->container = $container; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/QueryBus/Resolver/SimpleArrayResolver.php: -------------------------------------------------------------------------------- 1 | handlers = $handlers; 22 | } 23 | 24 | /** 25 | * Given a string to identify the Query Handler, return the instance. 26 | * 27 | * @param string $handler 28 | * 29 | * @return QueryHandler 30 | * 31 | * @throws InvalidArgumentException 32 | */ 33 | public function instantiate(string $handler) : QueryHandler 34 | { 35 | if (false === isset($this->handlers[$handler])) { 36 | throw new InvalidArgumentException( 37 | sprintf('Handler %s could not be found. Did you register it?', $handler) 38 | ); 39 | } 40 | 41 | $callable = $this->handlers[$handler]; 42 | 43 | return ($callable instanceof \Closure) ? $callable() : new $callable(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/QueryBus/Resolver/SymfonyContainerResolver.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:11. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\QueryBus\Resolver; 12 | 13 | use Symfony\Component\DependencyInjection\ContainerInterface; 14 | use InvalidArgumentException; 15 | use NilPortugues\MessageBus\QueryBus\Contracts\QueryHandler; 16 | use NilPortugues\MessageBus\QueryBus\Contracts\QueryHandlerResolver; 17 | 18 | /** 19 | * Class SymfonyContainerResolver. 20 | */ 21 | class SymfonyContainerResolver implements QueryHandlerResolver 22 | { 23 | /** @var ContainerInterface */ 24 | protected $container; 25 | 26 | /** 27 | * SymfonyContainerResolver constructor. 28 | * 29 | * @param ContainerInterface $container 30 | */ 31 | public function __construct(ContainerInterface $container) 32 | { 33 | $this->container = $container; 34 | } 35 | 36 | /** 37 | * Given a string to identify the Query Handler, return the instance. 38 | * 39 | * @param string $handler 40 | * 41 | * @return QueryHandler 42 | */ 43 | public function instantiate(string $handler) : QueryHandler 44 | { 45 | $handler = ltrim($handler, '\\'); 46 | if (false === $this->container->has($handler)) { 47 | throw new InvalidArgumentException( 48 | sprintf('Handler %s could not be found. Did you register it?', $handler) 49 | ); 50 | } 51 | 52 | return $this->container->get($handler); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/QueryBus/Translator/AppendStrategy.php: -------------------------------------------------------------------------------- 1 | append = $append; 28 | } 29 | 30 | /** 31 | * Given a query, find the Query Handler's name. 32 | * 33 | * @param Query $query 34 | * 35 | * @return string 36 | */ 37 | public function handlerName(Query $query) : string 38 | { 39 | return sprintf('%s%s', get_class($query), $this->append); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Serializer/Contracts/Serializer.php: -------------------------------------------------------------------------------- 1 | transformer = new DeepCopySerializer(new JsonTransformer()); 20 | } 21 | 22 | /** 23 | * Turns a data structure into a string that can be recovered. 24 | * 25 | * @param mixed $data 26 | * 27 | * @return string 28 | */ 29 | public function serialize($data) : string 30 | { 31 | return $this->transformer->serialize($data); 32 | } 33 | 34 | /** 35 | * Turns string data structure into an usable $data structure. 36 | * 37 | * @param string $data 38 | * 39 | * @return \stdClass 40 | */ 41 | public function unserialize(string $data) 42 | { 43 | return (object) json_decode($data); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Serializer/JsonSerializer.php: -------------------------------------------------------------------------------- 1 | serializer = new \NilPortugues\Serializer\JsonSerializer(); 18 | } 19 | 20 | /** 21 | * Turns a data structure into a string that can be recovered. 22 | * 23 | * @param mixed $data 24 | * 25 | * @return string 26 | */ 27 | public function serialize($data) : string 28 | { 29 | return $this->serializer->serialize($data); 30 | } 31 | 32 | /** 33 | * Turns string data structure into an usable $data structure. 34 | * 35 | * @param string $data 36 | * 37 | * @return mixed 38 | */ 39 | public function unserialize(string $data) 40 | { 41 | return $this->serializer->unserialize($data); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Serializer/NativeSerializer.php: -------------------------------------------------------------------------------- 1 | function () { 18 | return new DummyCommandHandler(); 19 | }, 20 | ]; 21 | 22 | $this->commandBus = new CommandBusMiddleware(new AppendStrategy('Handler'), new SimpleArrayResolver($handlers)); 23 | } 24 | 25 | public function testItCanHandle() 26 | { 27 | $this->commandBus->__invoke(new DummyCommand(), function () { 28 | return; 29 | }); 30 | $this->assertTrue(true); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/CommandBus/CommandBusTest.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 24/03/16 5 | * Time: 0:07. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus\CommandBus; 12 | 13 | use NilPortugues\MessageBus\CommandBus\CommandBus; 14 | use NilPortugues\MessageBus\CommandBus\CommandBusMiddleware; 15 | use NilPortugues\MessageBus\CommandBus\Contracts\CommandHandlerResolver; 16 | use NilPortugues\MessageBus\CommandBus\Contracts\CommandTranslator; 17 | use NilPortugues\MessageBus\CommandBus\LoggerCommandBusMiddleware; 18 | use NilPortugues\MessageBus\CommandBus\Resolver\SimpleArrayResolver; 19 | use NilPortugues\MessageBus\CommandBus\Translator\AppendStrategy; 20 | use NilPortugues\Tests\MessageBus\InMemoryLogger; 21 | 22 | class CommandBusTest extends \PHPUnit_Framework_TestCase 23 | { 24 | /** @var array */ 25 | protected $handlers; 26 | 27 | /** @var CommandTranslator */ 28 | protected $translator; 29 | 30 | /** @var CommandHandlerResolver */ 31 | protected $resolver; 32 | 33 | public function setUp() 34 | { 35 | $this->handlers = $handlers = [ 36 | DummyCommandHandler::class => function () { 37 | return new DummyCommandHandler(); 38 | }, 39 | ]; 40 | 41 | $this->translator = new AppendStrategy('Handler'); 42 | $this->resolver = new SimpleArrayResolver($handlers); 43 | } 44 | 45 | public function testItCanStackMiddleware() 46 | { 47 | $logger = new InMemoryLogger(); 48 | 49 | $middleware = [ 50 | new LoggerCommandBusMiddleware($logger), 51 | new CommandBusMiddleware($this->translator, $this->resolver), 52 | ]; 53 | 54 | $commandBus = new CommandBus($middleware); 55 | $commandBus->__invoke(new DummyCommand()); 56 | $this->assertNotEmpty($logger->logs()); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /tests/CommandBus/DummyCommand.php: -------------------------------------------------------------------------------- 1 | handlers = $handlers = [ 26 | DummyCommandHandler::class => function () { 27 | return new DummyCommandHandler(); 28 | }, 29 | ]; 30 | 31 | $this->translator = new AppendStrategy('Handler'); 32 | $this->resolver = new SimpleArrayResolver($handlers); 33 | } 34 | 35 | public function testItCanLog() 36 | { 37 | $logger = new InMemoryLogger(); 38 | 39 | $commandBus = new LoggerCommandBusMiddleware($logger); 40 | $commandBus->__invoke(new DummyCommand(), function ($command) { 41 | }); 42 | 43 | $this->assertNotEmpty($logger->logs()); 44 | $this->assertArrayHasKey('info', $logger->logs()); 45 | } 46 | 47 | public function testItCanLogError() 48 | { 49 | $logger = new InMemoryLogger(); 50 | 51 | $commandBus = new LoggerCommandBusMiddleware($logger); 52 | $commandBus->__invoke(new DummyCommand(), function () { 53 | throw new \Exception('Fail happens.'); 54 | }); 55 | 56 | $this->assertNotEmpty($logger->logs()); 57 | $this->assertArrayHasKey('alert', $logger->logs()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /tests/CommandBus/Resolver/InteropContainerResolverTest.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:43. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus\CommandBus\Resolver; 12 | 13 | use InvalidArgumentException; 14 | use NilPortugues\MessageBus\CommandBus\Resolver\InteropContainerResolver; 15 | use NilPortugues\Tests\MessageBus\CommandBus\DummyCommandHandler; 16 | use NilPortugues\Tests\MessageBus\InMemoryInteropContainer; 17 | 18 | class InteropContainerResolverTest extends \PHPUnit_Framework_TestCase 19 | { 20 | public function testItCanResolve() 21 | { 22 | $handlers = [ 23 | 'NilPortugues\Tests\MessageBus\CommandBus\DummyCommandHandler' => function () { 24 | return new DummyCommandHandler(); 25 | }, 26 | ]; 27 | 28 | $resolver = new InteropContainerResolver(new InMemoryInteropContainer($handlers)); 29 | $instance = $resolver->instantiate( 30 | 'NilPortugues\Tests\MessageBus\CommandBus\DummyCommandHandler' 31 | ); 32 | 33 | $this->assertInstanceOf(DummyCommandHandler::class, $instance); 34 | } 35 | 36 | public function testItThrowsExceptionIfCannotResolve() 37 | { 38 | $this->expectException(InvalidArgumentException::class); 39 | $resolver = new InteropContainerResolver(new InMemoryInteropContainer([])); 40 | $resolver->instantiate('Hello\World'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/CommandBus/Resolver/PsrContainerResolverTest.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:43. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus\CommandBus\Resolver; 12 | 13 | use InvalidArgumentException; 14 | use NilPortugues\MessageBus\CommandBus\Resolver\PsrContainerResolver; 15 | use NilPortugues\Tests\MessageBus\CommandBus\DummyCommandHandler; 16 | use NilPortugues\Tests\MessageBus\InMemoryPsrContainer; 17 | 18 | class PsrContainerResolverTest extends \PHPUnit_Framework_TestCase 19 | { 20 | public function testItCanResolve() 21 | { 22 | $handlers = [ 23 | 'NilPortugues\Tests\MessageBus\CommandBus\DummyCommandHandler' => function () { 24 | return new DummyCommandHandler(); 25 | }, 26 | ]; 27 | 28 | $resolver = new PsrContainerResolver(new InMemoryPsrContainer($handlers)); 29 | $instance = $resolver->instantiate( 30 | 'NilPortugues\Tests\MessageBus\CommandBus\DummyCommandHandler' 31 | ); 32 | 33 | $this->assertInstanceOf(DummyCommandHandler::class, $instance); 34 | } 35 | 36 | public function testItThrowsExceptionIfCannotResolve() 37 | { 38 | $this->expectException(InvalidArgumentException::class); 39 | $resolver = new PsrContainerResolver(new InMemoryPsrContainer([])); 40 | $resolver->instantiate('Hello\World'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/CommandBus/Resolver/SimpleArrayResolverTest.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:28. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\CommandBus\Resolver; 12 | 13 | use InvalidArgumentException; 14 | use NilPortugues\Tests\MessageBus\CommandBus\DummyCommandHandler; 15 | 16 | class SimpleArrayResolverTest extends \PHPUnit_Framework_TestCase 17 | { 18 | public function testItCanResolve() 19 | { 20 | $handlers = [ 21 | 'NilPortugues\Tests\MessageBus\CommandBus\DummyCommandHandler' => function () { 22 | return new DummyCommandHandler(); 23 | }, 24 | ]; 25 | 26 | $resolver = new SimpleArrayResolver($handlers); 27 | $instance = $resolver->instantiate( 28 | 'NilPortugues\Tests\MessageBus\CommandBus\DummyCommandHandler' 29 | ); 30 | 31 | $this->assertInstanceOf(DummyCommandHandler::class, $instance); 32 | } 33 | 34 | public function testItThrowsExceptionIfCannotResolve() 35 | { 36 | $this->expectException(InvalidArgumentException::class); 37 | $resolver = new SimpleArrayResolver([]); 38 | $resolver->instantiate('Hello\World'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/CommandBus/Resolver/SymfonyContainerResolverTest.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:43. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus\CommandBus\Resolver; 12 | 13 | use InvalidArgumentException; 14 | use NilPortugues\MessageBus\CommandBus\Resolver\SymfonyContainerResolver; 15 | use NilPortugues\Tests\MessageBus\InMemorySymfonyContainer; 16 | use NilPortugues\Tests\MessageBus\CommandBus\DummyCommandHandler; 17 | 18 | class SymfonyContainerResolverTest extends \PHPUnit_Framework_TestCase 19 | { 20 | public function testItCanResolve() 21 | { 22 | $handlers = [ 23 | 'NilPortugues\Tests\MessageBus\CommandBus\DummyQueryHandler' => function () { 24 | return new DummyCommandHandler(); 25 | }, 26 | ]; 27 | 28 | $resolver = new SymfonyContainerResolver(new InMemorySymfonyContainer($handlers)); 29 | $instance = $resolver->instantiate( 30 | 'NilPortugues\Tests\MessageBus\CommandBus\DummyQueryHandler' 31 | ); 32 | 33 | $this->assertInstanceOf(DummyCommandHandler::class, $instance); 34 | } 35 | 36 | public function testItThrowsExceptionIfCannotResolve() 37 | { 38 | $this->expectException(InvalidArgumentException::class); 39 | $resolver = new SymfonyContainerResolver(new InMemorySymfonyContainer([])); 40 | $resolver->instantiate('Hello\World'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/CommandBus/SqliteCommand.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 29/03/16 5 | * Time: 21:56. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus\CommandBus; 12 | 13 | use NilPortugues\MessageBus\CommandBus\Contracts\Command; 14 | use PDO; 15 | 16 | /** 17 | * Class SqliteCommand. 18 | */ 19 | class SqliteCommand implements Command 20 | { 21 | /** @var PDO */ 22 | protected $pdo; 23 | 24 | /** 25 | * SqliteCommand constructor. 26 | * 27 | * @param PDO $pdo 28 | */ 29 | public function __construct(PDO $pdo) 30 | { 31 | $this->pdo = $pdo; 32 | } 33 | 34 | public function __invoke() 35 | { 36 | $this->pdo->exec('INSERT INTO users(id, name) VALUES(1, "Username")'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/CommandBus/TransactionalCommandBusMiddlewareTest.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 29/03/16 5 | * Time: 21:56. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus\CommandBus; 12 | 13 | use NilPortugues\MessageBus\CommandBus\Contracts\Command; 14 | use NilPortugues\MessageBus\CommandBus\TransactionalCommandBusMiddleware; 15 | use PDO; 16 | use PDOException; 17 | 18 | class TransactionalCommandBusMiddlewareTest extends \PHPUnit_Framework_TestCase 19 | { 20 | /** @var PDO */ 21 | protected $pdo; 22 | /** @var Command */ 23 | protected $command; 24 | 25 | public function setUp() 26 | { 27 | $this->pdo = new PDO('sqlite::memory:'); 28 | $this->pdo->exec('CREATE TABLE IF NOT EXISTS users (id INTEGER, name TEXT);'); 29 | $this->command = new SqliteCommand($this->pdo); 30 | } 31 | 32 | public function testItCanRunTransaction() 33 | { 34 | $middleware = new TransactionalCommandBusMiddleware($this->pdo); 35 | $middleware->__invoke($this->command, function ($command) { 36 | return new DummyCommandHandler($command); 37 | }); 38 | $this->assertTrue(true); 39 | } 40 | 41 | public function testItCanCatchTransactionalError() 42 | { 43 | $middleware = new TransactionalCommandBusMiddleware($this->pdo); 44 | 45 | $this->expectException(PDOException::class); 46 | $middleware->__invoke($this->command, function () { 47 | throw new PDOException('Sometimes things fail'); 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tests/CommandBus/Translator/AppendStrategyTest.php: -------------------------------------------------------------------------------- 1 | assertEquals( 17 | DummyCommand::class.'Handler', 18 | $strategy->handlerName($command) 19 | ); 20 | } 21 | 22 | public function testItWillThrowException() 23 | { 24 | $this->expectException(InvalidArgumentException::class); 25 | new AppendStrategy(''); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/ContainerException.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 23:24. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus; 12 | 13 | use InvalidArgumentException; 14 | 15 | /** 16 | * Class ContainerException. 17 | */ 18 | class ContainerException extends InvalidArgumentException implements \Interop\Container\Exception\ContainerException 19 | { 20 | } 21 | -------------------------------------------------------------------------------- /tests/EventBus/DummyEvent.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 29/03/16 5 | * Time: 23:03. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus\EventBus; 12 | 13 | use NilPortugues\MessageBus\EventBus\EventBusMiddleware; 14 | use NilPortugues\MessageBus\EventBus\Resolver\SimpleArrayResolver; 15 | use NilPortugues\MessageBus\EventBus\Translator\EventFullyQualifiedClassNameStrategy; 16 | 17 | class EventBusMiddlewareTest extends \PHPUnit_Framework_TestCase 18 | { 19 | /** @var EventBusMiddleware */ 20 | protected $eventBus; 21 | 22 | public function setUp() 23 | { 24 | $handlers = [ 25 | DummyEventHandler::class => function () { 26 | return new DummyEventHandler(); 27 | }, 28 | ]; 29 | 30 | $this->eventBus = new EventBusMiddleware( 31 | new EventFullyQualifiedClassNameStrategy([DummyEventHandler::class]), 32 | new SimpleArrayResolver($handlers) 33 | ); 34 | } 35 | 36 | public function testItCanHandle() 37 | { 38 | $this->eventBus->__invoke(new DummyEvent(), function () { 39 | return; 40 | }); 41 | $this->assertTrue(true); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/EventBus/EventBusTest.php: -------------------------------------------------------------------------------- 1 | handlers = $handlers = [ 33 | DummyEventHandler::class => function () { 34 | return new DummyEventHandler(); 35 | }, 36 | ]; 37 | 38 | $this->translator = new EventFullyQualifiedClassNameStrategy([ 39 | DummyEventHandler::class, 40 | ]); 41 | 42 | $this->resolver = new SimpleArrayResolver($handlers); 43 | 44 | $this->pdo = new PDO('sqlite::memory:'); 45 | $this->pdo->exec('CREATE TABLE IF NOT EXISTS users (id INTEGER, name TEXT);'); 46 | } 47 | 48 | public function testItCanStackMiddleware() 49 | { 50 | $logger = new InMemoryLogger(); 51 | 52 | $middleware = [ 53 | new TransactionalEventBusMiddleware($this->pdo), 54 | new LoggerEventBusMiddleware($logger), 55 | new EventBusMiddleware($this->translator, $this->resolver), 56 | ]; 57 | 58 | $eventBus = new EventBus($middleware); 59 | $eventBus->__invoke(new SqliteEvent($this->pdo)); 60 | $this->assertNotEmpty($logger->logs()); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /tests/EventBus/LoggerEventBusMiddlewareTest.php: -------------------------------------------------------------------------------- 1 | handlers = $handlers = [ 26 | DummyEventHandler::class => function () { 27 | return new DummyEventHandler(); 28 | }, 29 | ]; 30 | 31 | $this->translator = new EventFullyQualifiedClassNameStrategy([ 32 | DummyEventHandler::class, 33 | ]); 34 | 35 | $this->resolver = new SimpleArrayResolver($handlers); 36 | } 37 | 38 | public function testItCanLog() 39 | { 40 | $logger = new InMemoryLogger(); 41 | 42 | $eventBus = new LoggerEventBusMiddleware($logger); 43 | $eventBus->__invoke(new DummyEvent(), function ($event) { 44 | }); 45 | 46 | $this->assertNotEmpty($logger->logs()); 47 | $this->assertArrayHasKey('info', $logger->logs()); 48 | } 49 | 50 | public function testItCanLogError() 51 | { 52 | $logger = new InMemoryLogger(); 53 | 54 | $eventBus = new LoggerEventBusMiddleware($logger); 55 | $eventBus->__invoke(new DummyEvent(), function () { 56 | throw new \Exception('Fail happens.'); 57 | }); 58 | 59 | $this->assertNotEmpty($logger->logs()); 60 | $this->assertArrayHasKey('alert', $logger->logs()); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /tests/EventBus/Resolver/InteropContainerResolverTest.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:43. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus\EventBus\Resolver; 12 | 13 | use InvalidArgumentException; 14 | use NilPortugues\MessageBus\EventBus\Resolver\InteropContainerResolver; 15 | use NilPortugues\Tests\MessageBus\EventBus\DummyEventHandler; 16 | use NilPortugues\Tests\MessageBus\InMemoryInteropContainer; 17 | 18 | class InteropContainerResolverTest extends \PHPUnit_Framework_TestCase 19 | { 20 | public function testItCanResolve() 21 | { 22 | $handlers = [ 23 | 'NilPortugues\Tests\MessageBus\EventBus\DummyEventHandler' => function () { 24 | return new DummyEventHandler(); 25 | }, 26 | ]; 27 | 28 | $resolver = new InteropContainerResolver(new InMemoryInteropContainer($handlers)); 29 | $instance = $resolver->instantiate( 30 | 'NilPortugues\Tests\MessageBus\EventBus\DummyEventHandler' 31 | ); 32 | 33 | $this->assertInstanceOf(DummyEventHandler::class, $instance); 34 | } 35 | 36 | public function testItThrowsExceptionIfCannotResolve() 37 | { 38 | $this->expectException(InvalidArgumentException::class); 39 | $resolver = new InteropContainerResolver(new InMemoryInteropContainer([])); 40 | $resolver->instantiate('Hello\World'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/EventBus/Resolver/PsrContainerResolverTest.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:43. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus\EventBus\Resolver; 12 | 13 | use InvalidArgumentException; 14 | use NilPortugues\MessageBus\EventBus\Resolver\PsrContainerResolver; 15 | use NilPortugues\Tests\MessageBus\EventBus\DummyEventHandler; 16 | use NilPortugues\Tests\MessageBus\InMemoryPsrContainer; 17 | 18 | class PsrContainerResolverTest extends \PHPUnit_Framework_TestCase 19 | { 20 | public function testItCanResolve() 21 | { 22 | $handlers = [ 23 | 'NilPortugues\Tests\MessageBus\EventBus\DummyEventHandler' => function () { 24 | return new DummyEventHandler(); 25 | }, 26 | ]; 27 | 28 | $resolver = new PsrContainerResolver(new InMemoryPsrContainer($handlers)); 29 | $instance = $resolver->instantiate( 30 | 'NilPortugues\Tests\MessageBus\EventBus\DummyEventHandler' 31 | ); 32 | 33 | $this->assertInstanceOf(DummyEventHandler::class, $instance); 34 | } 35 | 36 | public function testItThrowsExceptionIfCannotResolve() 37 | { 38 | $this->expectException(InvalidArgumentException::class); 39 | $resolver = new PsrContainerResolver(new InMemoryPsrContainer([])); 40 | $resolver->instantiate('Hello\World'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/EventBus/Resolver/SimpleArrayResolverTest.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:28. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\EventBus\Resolver; 12 | 13 | use InvalidArgumentException; 14 | use NilPortugues\Tests\MessageBus\EventBus\DummyEventHandler; 15 | 16 | class SimpleArrayResolverTest extends \PHPUnit_Framework_TestCase 17 | { 18 | public function testItCanResolve() 19 | { 20 | $handlers = [ 21 | 'NilPortugues\Tests\MessageBus\EventBus\DummyEventHandler' => function () { 22 | return new DummyEventHandler(); 23 | }, 24 | ]; 25 | 26 | $resolver = new SimpleArrayResolver($handlers); 27 | $instance = $resolver->instantiate( 28 | 'NilPortugues\Tests\MessageBus\EventBus\DummyEventHandler' 29 | ); 30 | 31 | $this->assertInstanceOf(DummyEventHandler::class, $instance); 32 | } 33 | 34 | public function testItThrowsExceptionIfCannotResolve() 35 | { 36 | $this->expectException(InvalidArgumentException::class); 37 | $resolver = new SimpleArrayResolver([]); 38 | $resolver->instantiate('Hello\World'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/EventBus/Resolver/SymfonyContainerResolverTest.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:43. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus\EventBus\Resolver; 12 | 13 | use InvalidArgumentException; 14 | use NilPortugues\MessageBus\EventBus\Resolver\SymfonyContainerResolver; 15 | use NilPortugues\Tests\MessageBus\InMemorySymfonyContainer; 16 | use NilPortugues\Tests\MessageBus\EventBus\DummyEventHandler; 17 | 18 | class SymfonyContainerResolverTest extends \PHPUnit_Framework_TestCase 19 | { 20 | public function testItCanResolve() 21 | { 22 | $handlers = [ 23 | 'NilPortugues\Tests\MessageBus\EventBus\DummyQueryHandler' => function () { 24 | return new DummyEventHandler(); 25 | }, 26 | ]; 27 | 28 | $resolver = new SymfonyContainerResolver(new InMemorySymfonyContainer($handlers)); 29 | $instance = $resolver->instantiate( 30 | 'NilPortugues\Tests\MessageBus\EventBus\DummyQueryHandler' 31 | ); 32 | 33 | $this->assertInstanceOf(DummyEventHandler::class, $instance); 34 | } 35 | 36 | public function testItThrowsExceptionIfCannotResolve() 37 | { 38 | $this->expectException(InvalidArgumentException::class); 39 | $resolver = new SymfonyContainerResolver(new InMemorySymfonyContainer([])); 40 | $resolver->instantiate('Hello\World'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/EventBus/SqliteEvent.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 29/03/16 5 | * Time: 21:56. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus\EventBus; 12 | 13 | use NilPortugues\MessageBus\EventBus\Contracts\Event; 14 | use PDO; 15 | 16 | /** 17 | * Class SqliteEvent. 18 | */ 19 | class SqliteEvent implements Event 20 | { 21 | /** @var PDO */ 22 | protected $pdo; 23 | 24 | /** 25 | * SqliteEvent constructor. 26 | * 27 | * @param PDO $pdo 28 | */ 29 | public function __construct(PDO $pdo) 30 | { 31 | $this->pdo = $pdo; 32 | } 33 | 34 | public function __invoke() 35 | { 36 | $this->pdo->exec('INSERT INTO users(id, name) VALUES(1, "Username")'); 37 | } 38 | 39 | /** 40 | * Returns a unique id. 41 | * 42 | * @return string 43 | */ 44 | public function id() : string 45 | { 46 | return (string) uniqid(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/EventBus/SqliteEventHandler.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 29/03/16 5 | * Time: 21:56. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus\EventBus; 12 | 13 | use NilPortugues\MessageBus\EventBus\Contracts\Event; 14 | use NilPortugues\MessageBus\EventBus\TransactionalEventBusMiddleware; 15 | use PDO; 16 | use PDOException; 17 | 18 | class TransactionalEventBusMiddlewareTest extends \PHPUnit_Framework_TestCase 19 | { 20 | /** @var PDO */ 21 | protected $pdo; 22 | /** @var Event */ 23 | protected $event; 24 | 25 | public function setUp() 26 | { 27 | $this->pdo = new PDO('sqlite::memory:'); 28 | $this->pdo->exec('CREATE TABLE IF NOT EXISTS users (id INTEGER, name TEXT);'); 29 | $this->event = new SqliteEvent($this->pdo); 30 | } 31 | 32 | public function testItCanRunTransaction() 33 | { 34 | $middleware = new TransactionalEventBusMiddleware($this->pdo); 35 | $middleware->__invoke($this->event, function ($command) { 36 | return new SqliteEventHandler($command); 37 | }); 38 | $this->assertTrue(true); 39 | } 40 | 41 | public function testItCanCatchTransactionalError() 42 | { 43 | $middleware = new TransactionalEventBusMiddleware($this->pdo); 44 | 45 | $this->expectException(PDOException::class); 46 | $middleware->__invoke($this->event, function () { 47 | throw new PDOException('Sometimes things fail'); 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tests/EventBus/Translator/EventFullyQualifiedClassNameStrategyTest.php: -------------------------------------------------------------------------------- 1 | handlerName($event); 20 | 21 | $this->assertContains(DummyEvent::class.'Handler', reset($handlers)); 22 | } 23 | 24 | public function testItWillThrowExceptionIfClassDoesNotExist() 25 | { 26 | $this->expectException(RuntimeException::class); 27 | new EventFullyQualifiedClassNameStrategy(['RandomHandler']); 28 | } 29 | 30 | public function testItWillThrowExceptionIfClassDoesNotImplementEventHandler() 31 | { 32 | $this->expectException(RuntimeException::class); 33 | new EventFullyQualifiedClassNameStrategy(['DateTime']); 34 | } 35 | 36 | public function testItWillThrowExceptionIfEventNotSupported() 37 | { 38 | $strategy = new EventFullyQualifiedClassNameStrategy([]); 39 | $event = new DummyEvent(); 40 | 41 | $this->expectException(RuntimeException::class); 42 | $strategy->handlerName($event); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tests/InMemoryCache.php: -------------------------------------------------------------------------------- 1 | deleteItems([$key]); 29 | } 30 | 31 | /** 32 | * {@inheritdoc} 33 | */ 34 | public function deleteItems(array $keys) 35 | { 36 | foreach ($keys as $key) { 37 | unset($this->data[$key]); 38 | } 39 | } 40 | 41 | /** 42 | * {@inheritdoc} 43 | */ 44 | public function save(CacheItemInterface $item) 45 | { 46 | return $this->write([$item]); 47 | } 48 | 49 | /** 50 | * {@inheritdoc} 51 | */ 52 | protected function write(array $items) 53 | { 54 | /** @var \Psr\Cache\CacheItemInterface $item */ 55 | foreach ($items as $item) { 56 | $this->data[$item->getKey()] = [ 57 | // Assumes use of the BasicCacheItemAccessorsTrait. 58 | 'value' => $item->getRawValue(), 59 | 'ttd' => $item->getExpiration(), 60 | 'hit' => true, 61 | ]; 62 | } 63 | 64 | return true; 65 | } 66 | 67 | /** 68 | * {@inheritdoc} 69 | */ 70 | public function saveDeferred(CacheItemInterface $item) 71 | { 72 | $this->deferred[] = $item; 73 | 74 | return true; 75 | } 76 | 77 | /** 78 | * {@inheritdoc} 79 | */ 80 | public function commit() 81 | { 82 | $success = $this->write($this->deferred); 83 | if ($success) { 84 | $this->deferred = []; 85 | } 86 | 87 | return $success; 88 | } 89 | 90 | /** 91 | * {@inheritdoc} 92 | */ 93 | public function getItems(array $keys = []) 94 | { 95 | // This method will throw an appropriate exception if any key is not valid. 96 | array_map([$this, 'validateKey'], $keys); 97 | $collection = []; 98 | foreach ($keys as $key) { 99 | $collection[$key] = $this->getItem($key); 100 | } 101 | 102 | return $collection; 103 | } 104 | 105 | /** 106 | * {@inheritdoc} 107 | */ 108 | public function getItem($key) 109 | { 110 | // This method will either return True or throw an appropriate exception. 111 | $this->validateKey($key); 112 | if (!$this->hasItem($key)) { 113 | $this->data[$key] = $this->emptyItem(); 114 | } 115 | 116 | return new InMemoryCacheItem($key, $this->data[$key]); 117 | } 118 | 119 | /** 120 | * {@inheritdoc} 121 | */ 122 | protected function validateKey($key) 123 | { 124 | return true; 125 | } 126 | 127 | /** 128 | * {@inheritdoc} 129 | */ 130 | public function hasItem($key) 131 | { 132 | return array_key_exists($key, $this->data) && $this->data[$key]['ttd'] > new \DateTime(); 133 | } 134 | 135 | /** 136 | * Returns an empty item definition. 137 | * 138 | * @return array 139 | */ 140 | protected function emptyItem() 141 | { 142 | return [ 143 | 'value' => null, 144 | 'hit' => false, 145 | 'ttd' => null, 146 | ]; 147 | } 148 | 149 | /** 150 | * {@inheritdoc} 151 | */ 152 | public function clear() 153 | { 154 | $this->data = []; 155 | 156 | return true; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /tests/InMemoryCacheItem.php: -------------------------------------------------------------------------------- 1 | key = $key; 37 | $this->value = $data['value']; 38 | $this->expiration = $data['ttd']; 39 | $this->hit = $data['hit']; 40 | } 41 | 42 | /** 43 | * {@inheritdoc} 44 | */ 45 | public function getKey() 46 | { 47 | return $this->key; 48 | } 49 | 50 | /** 51 | * {@inheritdoc} 52 | */ 53 | public function get() 54 | { 55 | return $this->isHit() ? $this->value : null; 56 | } 57 | 58 | /** 59 | * {@inheritdoc} 60 | */ 61 | public function isHit() 62 | { 63 | return $this->hit; 64 | } 65 | 66 | /** 67 | * {@inheritdoc} 68 | */ 69 | public function set($value = null) 70 | { 71 | $this->value = $value; 72 | 73 | return $this; 74 | } 75 | 76 | /** 77 | * {@inheritdoc} 78 | */ 79 | public function expiresAt($expiration) 80 | { 81 | if (is_null($expiration)) { 82 | $this->expiration = new \DateTime('now +1 year'); 83 | } else { 84 | assert('$expiration instanceof \DateTimeInterface'); 85 | $this->expiration = $expiration; 86 | } 87 | 88 | return $this; 89 | } 90 | 91 | /** 92 | * {@inheritdoc} 93 | */ 94 | public function expiresAfter($time) 95 | { 96 | if (is_null($time)) { 97 | $this->expiration = new \DateTime('now +1 year'); 98 | } elseif (is_numeric($time)) { 99 | $this->expiration = new \DateTime('now +'.$time.' seconds'); 100 | } else { 101 | assert('$time instanceof DateInterval'); 102 | $expiration = new \DateTime(); 103 | $expiration->add($time); 104 | $this->expiration = $expiration; 105 | } 106 | 107 | return $this; 108 | } 109 | 110 | /** 111 | * {@inheritdoc} 112 | */ 113 | public function getExpiration() 114 | { 115 | return $this->expiration ?: new \DateTime('now +1 year'); 116 | } 117 | 118 | /** 119 | * {@inheritdoc} 120 | */ 121 | public function getRawValue() 122 | { 123 | return $this->value; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /tests/InMemoryInteropContainer.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:45. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus; 12 | 13 | use Interop\Container\ContainerInterface; 14 | 15 | /** 16 | * Class InMemoryInteropContainer. 17 | */ 18 | class InMemoryInteropContainer implements ContainerInterface 19 | { 20 | /** @var array */ 21 | protected $container = []; 22 | 23 | /** 24 | * InMemoryInteropContainer constructor. 25 | * 26 | * @param array $container 27 | * 28 | * @throws ContainerException 29 | */ 30 | public function __construct(array $container) 31 | { 32 | foreach ($container as $item) { 33 | if (false === ($item instanceof \Closure)) { 34 | throw new ContainerException('Container values must be instance of \Closure.'); 35 | } 36 | } 37 | 38 | $this->container = $container; 39 | } 40 | 41 | /** 42 | * Finds an entry of the container by its identifier and returns it. 43 | * 44 | * @param string $id Identifier of the entry to look for 45 | * 46 | * @throws NotFoundException No entry was found for this identifier 47 | * @throws ContainerException Error while retrieving the entry 48 | * 49 | * @return mixed Entry 50 | */ 51 | public function get($id) 52 | { 53 | if (false === $this->has($id)) { 54 | throw new NotFoundException('Identifier not found in container'); 55 | } 56 | 57 | return $this->container[$id](); 58 | } 59 | 60 | /** 61 | * Returns true if the container can return an entry for the given identifier. 62 | * Returns false otherwise. 63 | * 64 | * @param string $id Identifier of the entry to look for 65 | * 66 | * @return bool 67 | */ 68 | public function has($id) 69 | { 70 | return isset($this->container[$id]); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tests/InMemoryLogger.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 24/03/16 5 | * Time: 0:14. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus; 12 | 13 | use Psr\Log\AbstractLogger; 14 | 15 | /** 16 | * Class InMemoryLogger. 17 | */ 18 | class InMemoryLogger extends AbstractLogger 19 | { 20 | /** @var array */ 21 | protected $logs = []; 22 | 23 | /** 24 | * Logs with an arbitrary level. 25 | * 26 | * @param mixed $level 27 | * @param string $message 28 | * @param array $context 29 | */ 30 | public function log($level, $message, array $context = array()) 31 | { 32 | $this->logs[$level][] = $message; 33 | } 34 | 35 | /** 36 | * @return array 37 | */ 38 | public function logs() 39 | { 40 | return $this->logs; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/InMemoryPsrContainer.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:45. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus; 12 | 13 | use Psr\Container\ContainerInterface; 14 | 15 | /** 16 | * Class InMemoryPsrContainer. 17 | */ 18 | class InMemoryPsrContainer extends InMemoryInteropContainer implements ContainerInterface 19 | { 20 | } 21 | -------------------------------------------------------------------------------- /tests/InMemorySymfonyContainer.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:45. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus; 12 | 13 | use Symfony\Component\DependencyInjection\ContainerInterface; 14 | use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 15 | use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; 16 | use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; 17 | 18 | /** 19 | * Class InMemorySymfonyContainer. 20 | */ 21 | class InMemorySymfonyContainer implements ContainerInterface 22 | { 23 | /** @var array */ 24 | protected $container = []; 25 | /** @var array */ 26 | protected $parameters = []; 27 | 28 | /** 29 | * InMemoryInteropContainer constructor. 30 | * 31 | * @param array $container 32 | * 33 | * @throws ContainerException 34 | */ 35 | public function __construct(array $container) 36 | { 37 | foreach ($container as $item) { 38 | if (false === ($item instanceof \Closure)) { 39 | throw new ContainerException('Container values must be instance of \Closure.'); 40 | } 41 | } 42 | 43 | $this->container = $container; 44 | } 45 | 46 | /** 47 | * Sets a service. 48 | * 49 | * @param string $id The service identifier 50 | * @param object $service The service instance 51 | */ 52 | public function set($id, $service) 53 | { 54 | $this->container[$id] = function () use ($service) { 55 | return $service; 56 | }; 57 | } 58 | 59 | /** 60 | * Gets a service. 61 | * 62 | * @param string $id The service identifier 63 | * @param int $invalidBehavior The behavior when the service does not exist 64 | * 65 | * @return object The associated service 66 | * 67 | * @throws ServiceCircularReferenceException When a circular reference is detected 68 | * @throws ServiceNotFoundException When the service is not defined 69 | * 70 | * @see Reference 71 | */ 72 | public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE) 73 | { 74 | if (false === $this->has($id)) { 75 | if ($invalidBehavior) { 76 | throw new NotFoundException('Identifier not found in container'); 77 | } 78 | 79 | return null; 80 | } 81 | 82 | return $this->container[$id](); 83 | } 84 | 85 | /** 86 | * Returns true if the given service is defined. 87 | * 88 | * @param string $id The service identifier 89 | * 90 | * @return bool true if the service is defined, false otherwise 91 | */ 92 | public function has($id) 93 | { 94 | return isset($this->container[$id]); 95 | } 96 | 97 | /** 98 | * Check for whether or not a service has been initialized. 99 | * 100 | * @param string $id 101 | * 102 | * @return bool true if the service has been initialized, false otherwise 103 | */ 104 | public function initialized($id) 105 | { 106 | return false; 107 | } 108 | 109 | /** 110 | * Gets a parameter. 111 | * 112 | * @param string $name The parameter name 113 | * 114 | * @return mixed The parameter value 115 | * 116 | * @throws InvalidArgumentException if the parameter is not defined 117 | */ 118 | public function getParameter($name) 119 | { 120 | return ($this->hasParameter($name)) ? $this->parameters[$name] : null; 121 | } 122 | 123 | /** 124 | * Checks if a parameter exists. 125 | * 126 | * @param string $name The parameter name 127 | * 128 | * @return bool The presence of parameter in container 129 | */ 130 | public function hasParameter($name) 131 | { 132 | return array_key_exists($name, $this->parameters); 133 | } 134 | 135 | /** 136 | * Sets a parameter. 137 | * 138 | * @param string $name The parameter name 139 | * @param mixed $value The parameter value 140 | */ 141 | public function setParameter($name, $value) 142 | { 143 | $this->parameters[$name] = $value; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /tests/NotFoundException.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 23:23. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus; 12 | 13 | use InvalidArgumentException; 14 | 15 | /** 16 | * Class NotFoundException. 17 | */ 18 | class NotFoundException extends InvalidArgumentException implements \Interop\Container\Exception\NotFoundException 19 | { 20 | } 21 | -------------------------------------------------------------------------------- /tests/QueryBus/CacheQueryBusMiddlewareTest.php: -------------------------------------------------------------------------------- 1 | handlers = $handlers = [ 33 | DummyQueryHandler::class => function () { 34 | return new DummyQueryHandler(); 35 | }, 36 | ]; 37 | 38 | $this->translator = new AppendStrategy('Handler'); 39 | $this->resolver = new SimpleArrayResolver($handlers); 40 | 41 | $this->cacheMiddleware = new CacheQueryBusMiddleware(new NativeSerializer(), new InMemoryCache(), 60); 42 | } 43 | 44 | public function testItCanCache() 45 | { 46 | $response = $this->cacheMiddleware->__invoke(new DummyQuery(), function ($command) { 47 | $queryBus = new QueryBusMiddleware($this->translator, $this->resolver); 48 | 49 | return $queryBus->__invoke($command); 50 | }); 51 | 52 | $this->assertInstanceOf(QueryResponse::class, $response); 53 | } 54 | 55 | public function testItHitsCache() 56 | { 57 | for ($i = 0; $i <= 2; ++$i) { 58 | $response = $this->cacheMiddleware->__invoke(new DummyQuery(), function ($command) { 59 | $queryBus = new QueryBusMiddleware($this->translator, $this->resolver); 60 | 61 | return $queryBus->__invoke($command); 62 | }); 63 | 64 | $this->assertInstanceOf(QueryResponse::class, $response); 65 | } 66 | } 67 | 68 | public function testItThrowsExceptionIfCacheMiddlewareHasNoNextCallable() 69 | { 70 | $this->expectException(InvalidArgumentException::class); 71 | $this->cacheMiddleware->__invoke(new DummyQuery()); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /tests/QueryBus/DummyQuery.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 29/03/16 5 | * Time: 23:54. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus\QueryBus; 12 | 13 | use NilPortugues\MessageBus\QueryBus\Contracts\Query; 14 | 15 | /** 16 | * Class DummyQuery. 17 | */ 18 | class DummyQuery implements Query 19 | { 20 | public function __invoke() 21 | { 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/QueryBus/DummyQueryHandler.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 29/03/16 5 | * Time: 23:54. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus\QueryBus; 12 | 13 | use NilPortugues\MessageBus\QueryBus\Contracts\Query; 14 | use NilPortugues\MessageBus\QueryBus\Contracts\QueryHandler; 15 | use NilPortugues\MessageBus\QueryBus\Contracts\QueryResponse; 16 | 17 | /** 18 | * Class DummyQueryHandler. 19 | */ 20 | class DummyQueryHandler implements QueryHandler 21 | { 22 | /** 23 | * @param Query $query 24 | * 25 | * @return QueryResponse 26 | */ 27 | public function __invoke($query) : QueryResponse 28 | { 29 | return new DummyQueryResponse(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/QueryBus/DummyQueryResponse.php: -------------------------------------------------------------------------------- 1 | handlers = $handlers = [ 28 | DummyQueryHandler::class => function () { 29 | return new DummyQueryHandler(); 30 | }, 31 | ]; 32 | 33 | $this->translator = new AppendStrategy('Handler'); 34 | $this->resolver = new SimpleArrayResolver($handlers); 35 | } 36 | 37 | public function testItCanLog() 38 | { 39 | $logger = new InMemoryLogger(); 40 | 41 | $loggerQueryBus = new LoggerQueryBusMiddleware($logger); 42 | 43 | $response = $loggerQueryBus->__invoke(new DummyQuery(), function ($command) { 44 | $queryBus = new QueryBusMiddleware($this->translator, $this->resolver); 45 | 46 | return $queryBus->__invoke($command); 47 | }); 48 | 49 | $this->assertNotEmpty($logger->logs()); 50 | $this->assertArrayHasKey('info', $logger->logs()); 51 | $this->assertInstanceOf(QueryResponse::class, $response); 52 | } 53 | 54 | public function testItCanLogError() 55 | { 56 | $logger = new InMemoryLogger(); 57 | 58 | $loggerQueryBus = new LoggerQueryBusMiddleware($logger); 59 | 60 | $response = $loggerQueryBus->__invoke(new DummyQuery(), function () { 61 | throw new \Exception('Fail happens.'); 62 | }); 63 | 64 | $this->assertNotEmpty($logger->logs()); 65 | $this->assertArrayHasKey('alert', $logger->logs()); 66 | $this->assertInstanceOf(QueryResponse::class, $response); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tests/QueryBus/QueryBusMiddlewareTest.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 29/03/16 5 | * Time: 23:03. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus\QueryBus; 12 | 13 | use NilPortugues\MessageBus\QueryBus\Contracts\QueryResponse; 14 | use NilPortugues\MessageBus\QueryBus\QueryBusMiddleware; 15 | use NilPortugues\MessageBus\QueryBus\Resolver\SimpleArrayResolver; 16 | use NilPortugues\MessageBus\QueryBus\Translator\AppendStrategy; 17 | 18 | class QueryBusMiddlewareTest extends \PHPUnit_Framework_TestCase 19 | { 20 | /** @var QueryBusMiddleware */ 21 | protected $queryBus; 22 | 23 | public function setUp() 24 | { 25 | $handlers = [ 26 | DummyQueryHandler::class => function () { 27 | return new DummyQueryHandler(); 28 | }, 29 | ]; 30 | 31 | $this->queryBus = new QueryBusMiddleware(new AppendStrategy('Handler'), new SimpleArrayResolver($handlers)); 32 | } 33 | 34 | public function testItCanHandle() 35 | { 36 | $response = $this->queryBus->__invoke(new DummyQuery()); 37 | $this->assertInstanceOf(QueryResponse::class, $response); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/QueryBus/QueryBusTest.php: -------------------------------------------------------------------------------- 1 | handlers = $handlers = [ 32 | DummyQueryHandler::class => function () { 33 | return new DummyQueryHandler(); 34 | }, 35 | ]; 36 | 37 | $this->translator = new AppendStrategy('Handler'); 38 | $this->resolver = new SimpleArrayResolver($handlers); 39 | } 40 | 41 | public function testItCanStackMiddleware() 42 | { 43 | $logger = new InMemoryLogger(); 44 | 45 | $middleware = [ 46 | new LoggerQueryBusMiddleware($logger), 47 | new CacheQueryBusMiddleware(new NativeSerializer(), new InMemoryCache(), 60), 48 | new QueryBusMiddleware($this->translator, $this->resolver), 49 | ]; 50 | 51 | $queryBus = new QueryBus($middleware); 52 | $response = $queryBus->__invoke(new DummyQuery()); 53 | $this->assertNotEmpty($logger->logs()); 54 | $this->assertInstanceOf(DummyQueryResponse::class, $response); 55 | } 56 | 57 | public function testItWillReturnEmptyResponse() 58 | { 59 | $queryBus = new QueryBus([]); 60 | $response = $queryBus->__invoke(new DummyQuery()); 61 | $this->assertInstanceOf(EmptyResponse::class, $response); 62 | } 63 | 64 | public function testItWillReturnDummyQueryResponse() 65 | { 66 | $queryBus = new QueryBus([new QueryBusMiddleware($this->translator, $this->resolver)]); 67 | $response = $queryBus->__invoke(new DummyQuery()); 68 | $this->assertInstanceOf(DummyQueryResponse::class, $response); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /tests/QueryBus/Resolver/InteropContainerResolverTest.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:43. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus\QueryBus\Resolver; 12 | 13 | use InvalidArgumentException; 14 | use NilPortugues\MessageBus\QueryBus\Resolver\InteropContainerResolver; 15 | use NilPortugues\Tests\MessageBus\InMemoryInteropContainer; 16 | use NilPortugues\Tests\MessageBus\QueryBus\DummyQueryHandler; 17 | 18 | class InteropContainerResolverTest extends \PHPUnit_Framework_TestCase 19 | { 20 | public function testItCanResolve() 21 | { 22 | $handlers = [ 23 | 'NilPortugues\Tests\MessageBus\QueryBus\DummyQueryHandler' => function () { 24 | return new DummyQueryHandler(); 25 | }, 26 | ]; 27 | 28 | $resolver = new InteropContainerResolver(new InMemoryInteropContainer($handlers)); 29 | $instance = $resolver->instantiate( 30 | 'NilPortugues\Tests\MessageBus\QueryBus\DummyQueryHandler' 31 | ); 32 | 33 | $this->assertInstanceOf(DummyQueryHandler::class, $instance); 34 | } 35 | 36 | public function testItThrowsExceptionIfCannotResolve() 37 | { 38 | $this->expectException(InvalidArgumentException::class); 39 | $resolver = new InteropContainerResolver(new InMemoryInteropContainer([])); 40 | $resolver->instantiate('Hello\World'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/QueryBus/Resolver/PsrContainerResolverTest.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:43. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus\QueryBus\Resolver; 12 | 13 | use InvalidArgumentException; 14 | use NilPortugues\MessageBus\QueryBus\Resolver\PsrContainerResolver; 15 | use NilPortugues\Tests\MessageBus\InMemoryPsrContainer; 16 | use NilPortugues\Tests\MessageBus\QueryBus\DummyQueryHandler; 17 | 18 | class PsrContainerResolverTest extends \PHPUnit_Framework_TestCase 19 | { 20 | public function testItCanResolve() 21 | { 22 | $handlers = [ 23 | 'NilPortugues\Tests\MessageBus\QueryBus\DummyQueryHandler' => function () { 24 | return new DummyQueryHandler(); 25 | }, 26 | ]; 27 | 28 | $resolver = new PsrContainerResolver(new InMemoryPsrContainer($handlers)); 29 | $instance = $resolver->instantiate( 30 | 'NilPortugues\Tests\MessageBus\QueryBus\DummyQueryHandler' 31 | ); 32 | 33 | $this->assertInstanceOf(DummyQueryHandler::class, $instance); 34 | } 35 | 36 | public function testItThrowsExceptionIfCannotResolve() 37 | { 38 | $this->expectException(InvalidArgumentException::class); 39 | $resolver = new PsrContainerResolver(new InMemoryPsrContainer([])); 40 | $resolver->instantiate('Hello\World'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/QueryBus/Resolver/SimpleArrayResolverTest.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:28. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\MessageBus\QueryBus\Resolver; 12 | 13 | use InvalidArgumentException; 14 | use NilPortugues\Tests\MessageBus\QueryBus\DummyQueryHandler; 15 | 16 | class SimpleArrayResolverTest extends \PHPUnit_Framework_TestCase 17 | { 18 | public function testItCanResolve() 19 | { 20 | $handlers = [ 21 | 'NilPortugues\Tests\MessageBus\QueryBus\DummyQueryHandler' => function () { 22 | return new DummyQueryHandler(); 23 | }, 24 | ]; 25 | 26 | $resolver = new SimpleArrayResolver($handlers); 27 | $instance = $resolver->instantiate( 28 | 'NilPortugues\Tests\MessageBus\QueryBus\DummyQueryHandler' 29 | ); 30 | 31 | $this->assertInstanceOf(DummyQueryHandler::class, $instance); 32 | } 33 | 34 | public function testItThrowsExceptionIfCannotResolve() 35 | { 36 | $this->expectException(InvalidArgumentException::class); 37 | $resolver = new SimpleArrayResolver([]); 38 | $resolver->instantiate('Hello\World'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/QueryBus/Resolver/SymfonyContainerResolverTest.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 23/03/16 5 | * Time: 22:43. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace NilPortugues\Tests\MessageBus\QueryBus\Resolver; 12 | 13 | use InvalidArgumentException; 14 | use NilPortugues\MessageBus\QueryBus\Resolver\SymfonyContainerResolver; 15 | use NilPortugues\Tests\MessageBus\InMemorySymfonyContainer; 16 | use NilPortugues\Tests\MessageBus\QueryBus\DummyQueryHandler; 17 | 18 | class SymfonyContainerResolverTest extends \PHPUnit_Framework_TestCase 19 | { 20 | public function testItCanResolve() 21 | { 22 | $handlers = [ 23 | 'NilPortugues\Tests\MessageBus\QueryBus\DummyQueryHandler' => function () { 24 | return new DummyQueryHandler(); 25 | }, 26 | ]; 27 | 28 | $resolver = new SymfonyContainerResolver(new InMemorySymfonyContainer($handlers)); 29 | $instance = $resolver->instantiate( 30 | 'NilPortugues\Tests\MessageBus\QueryBus\DummyQueryHandler' 31 | ); 32 | 33 | $this->assertInstanceOf(DummyQueryHandler::class, $instance); 34 | } 35 | 36 | public function testItThrowsExceptionIfCannotResolve() 37 | { 38 | $this->expectException(InvalidArgumentException::class); 39 | $resolver = new SymfonyContainerResolver(new InMemorySymfonyContainer([])); 40 | $resolver->instantiate('Hello\World'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/QueryBus/Translator/AppendStrategyTest.php: -------------------------------------------------------------------------------- 1 | assertEquals( 17 | DummyQuery::class.'Handler', 18 | $strategy->handlerName($query) 19 | ); 20 | } 21 | 22 | public function testItWillThrowException() 23 | { 24 | $this->expectException(InvalidArgumentException::class); 25 | new AppendStrategy(''); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/Serializer/JsonObjectSerializerTest.php: -------------------------------------------------------------------------------- 1 | id = 1; 13 | $stdClass->name = ['name' => 'Nil', 'surname' => 'Portugués']; 14 | 15 | $serializer = new JsonObjectSerializer(); 16 | 17 | $unserialized = $serializer->unserialize($serializer->serialize($stdClass)); 18 | 19 | $this->assertEquals($stdClass->id, $unserialized->id); 20 | $this->assertEquals($stdClass->name['name'], $unserialized->name->name); 21 | $this->assertEquals($stdClass->name['surname'], $unserialized->name->surname); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/Serializer/JsonSerializerTest.php: -------------------------------------------------------------------------------- 1 | assertEquals( 15 | $serializer->unserialize($serializer->serialize($stdClass)), 16 | $stdClass 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/Serializer/NativeSerializerTest.php: -------------------------------------------------------------------------------- 1 | assertEquals( 15 | $serializer->unserialize($serializer->serialize($stdClass)), 16 | $stdClass 17 | ); 18 | } 19 | } 20 | --------------------------------------------------------------------------------