├── couscous.yml ├── README.md ├── LICENSE ├── CHANGELOG.md ├── src ├── MessageBus │ └── WrapsMessageHandlingInTransaction.php └── EventListener │ └── CollectsEventsFromEntities.php └── composer.json /couscous.yml: -------------------------------------------------------------------------------- 1 | title: SimpleBus/DoctrineORMBridge 2 | subTitle: Integrate SimpleBus/MessageBus with Doctrine ORM 3 | baseUrl: //simplebus.github.io/DoctrineORMBridge 4 | menu: 5 | items: 6 | home: 7 | itemId: home 8 | text: Home 9 | relativeUrl: "" 10 | getting_started: 11 | itemId: getting_started 12 | text: Getting started 13 | relativeUrl: doc/getting_started.html 14 | transactions: 15 | itemId: transactions 16 | text: Transactions 17 | relativeUrl: doc/transactions.html 18 | domain_events: 19 | itemId: domain_events 20 | text: Domain events 21 | relativeUrl: doc/domain_events.html 22 | symfony_integration: 23 | text: Symfony integration 24 | absoluteUrl: http://simplebus.github.io/SymfonyBridge/ 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SimpleBus/DoctrineORMBridge 2 | 3 | [![Tests Actions Status](https://github.com/SimpleBus/SimpleBus/workflows/Tests/badge.svg)](https://github.com/SimpleBus/SimpleBus/actions) 4 | 5 | By [Matthias Noback](http://php-and-symfony.matthiasnoback.nl/), Cliff Odijk, Ruud Kamphuis 6 | 7 | This package provides command bus middlewares that can be used to integrate 8 | [SimpleBus/MessageBus](https://github.com/SimpleBus/MessageBus) with [Doctrine 9 | ORM](https://github.com/doctrine/doctrine2). 10 | 11 | It provides an easy way to [wrap command handling in a database transaction](http://docs.simplebus.io/en/latest/Components/DoctrineDBALBridge.html#transactions) and [handle domain events generated by entities](http://docs.simplebus.io/en/latest/Components/DoctrineORMBridge.html#domain-events). 12 | 13 | Resources 14 | --------- 15 | 16 | * [Report issues](https://github.com/SimpleBus/SimpleBus/issues) and 17 | [send Pull Requests](https://github.com/SimpleBus/SimpleBus/pulls) 18 | in the [main SimpleBus repository](https://github.com/SimpleBus/SimpleBus) 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2015-2018 Matthias Noback, Cliff Odijk, Ruud Kamphuis 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 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change log 2 | 3 | ## [Unreleased][unreleased] 4 | 5 | - Update change log 6 | 7 | ## [3.0.0] - 23-01-2015 8 | 9 | ### Added 10 | 11 | - Added a change log 12 | 13 | ### Changed 14 | 15 | - When a database transaction fails, the entity manager closes itself down. This used to make the command bus useless. 16 | Now the command bus is able to restore itself by asking the manager registry to reset the manager. 17 | 18 | ## [2.0.1] - 20-01-2015 19 | 20 | ### Changed 21 | 22 | - When domain events are collected from entities, they are now also erased, to prevent processing the same events again. 23 | - Tests were added, which uncovered a serious bug, which has been fixed as well. 24 | 25 | ## [2.0.0] - 19-01-2015 26 | 27 | ### Changed 28 | 29 | - Instead of SimpleBus/CommandBus and SimpleBus/EventBus 1.0 this library now uses SimpleBus/MessageBus 1.0. 30 | 31 | [unreleased]: https://github.com/SimpleBus/DoctrineORMBridge/compare/v3.0.0...HEAD 32 | [3.0.0]: https://github.com/SimpleBus/DoctrineORMBridge/compare/v2.0.1...v3.0.0 33 | [2.0.1]: https://github.com/SimpleBus/DoctrineORMBridge/compare/v2.0.0...v2.0.1 34 | [2.0.0]: https://github.com/SimpleBus/DoctrineORMBridge/compare/v1.0.0...v2.0.0 35 | -------------------------------------------------------------------------------- /src/MessageBus/WrapsMessageHandlingInTransaction.php: -------------------------------------------------------------------------------- 1 | managerRegistry = $managerRegistry; 19 | $this->entityManagerName = $entityManagerName; 20 | } 21 | 22 | public function handle(object $message, callable $next): void 23 | { 24 | /** @var EntityManager $entityManager */ 25 | $entityManager = $this->managerRegistry->getManager($this->entityManagerName); 26 | 27 | try { 28 | $entityManager->transactional( 29 | function () use ($message, $next) { 30 | $next($message); 31 | } 32 | ); 33 | } catch (Throwable $error) { 34 | $this->managerRegistry->resetManager($this->entityManagerName); 35 | 36 | throw $error; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple-bus/doctrine-orm-bridge", 3 | "type": "library", 4 | "description": "Doctrine ORM bridge for using command and event buses", 5 | "keywords": [ 6 | "Doctrine", 7 | "event bus", 8 | "command bus" 9 | ], 10 | "homepage": "http://github.com/SimpleBus/DoctrineORMBridge", 11 | "license": "MIT", 12 | "authors": [ 13 | { 14 | "name": "Cliff Odijk", 15 | "email": "cliff@jcid.nl" 16 | }, 17 | { 18 | "name": "Ruud Kamphuis", 19 | "homepage": "https://github.com/ruudk" 20 | }, 21 | { 22 | "name": "Matthias Noback", 23 | "email": "matthiasnoback@gmail.com", 24 | "homepage": "http://php-and-symfony.matthiasnoback.nl" 25 | } 26 | ], 27 | "require": { 28 | "php": "^8.0", 29 | "doctrine/dbal": "^2.12 || ^3.0", 30 | "doctrine/orm": "^2.8.5", 31 | "simple-bus/message-bus": "^6.0" 32 | }, 33 | "conflict": { 34 | "doctrine/dbal": "<2.13.3", 35 | "doctrine/persistence": "<2.2.2" 36 | }, 37 | "require-dev": { 38 | "ergebnis/composer-normalize": "^2.11", 39 | "phpunit/phpunit": "^9.5.5", 40 | "pimple/pimple": "^3.5", 41 | "symfony/cache": "^5.4 || ^6.0", 42 | "symfony/phpunit-bridge": "^6.0" 43 | }, 44 | "suggest": { 45 | "simple-bus/symfony-bridge": "Bridge for using command buses and event buses with Symfony" 46 | }, 47 | "config": { 48 | "sort-packages": true 49 | }, 50 | "autoload": { 51 | "psr-4": { 52 | "SimpleBus\\DoctrineORMBridge\\": "src" 53 | } 54 | }, 55 | "autoload-dev": { 56 | "psr-4": { 57 | "SimpleBus\\DoctrineORMBridge\\Tests\\": "tests" 58 | } 59 | }, 60 | "minimum-stability": "dev", 61 | "prefer-stable": true 62 | } 63 | -------------------------------------------------------------------------------- /src/EventListener/CollectsEventsFromEntities.php: -------------------------------------------------------------------------------- 1 | getEntityManager(); 30 | $uow = $em->getUnitOfWork(); 31 | foreach ($uow->getIdentityMap() as $entities) { 32 | foreach ($entities as $entity) { 33 | if (null === $entity) { 34 | continue; 35 | } 36 | 37 | $this->collectEventsFromEntity($entity); 38 | } 39 | } 40 | foreach ($uow->getScheduledEntityDeletions() as $entity) { 41 | $this->collectEventsFromEntity($entity); 42 | } 43 | } 44 | 45 | /** 46 | * We need to listen on postFlush for Lifecycle Events 47 | * All Lifecycle callback events are triggered after the onFlush event. 48 | */ 49 | public function postFlush(PostFlushEventArgs $eventArgs): void 50 | { 51 | $em = $eventArgs->getEntityManager(); 52 | $uow = $em->getUnitOfWork(); 53 | foreach ($uow->getIdentityMap() as $entities) { 54 | foreach ($entities as $entity) { 55 | if (null === $entity) { 56 | continue; 57 | } 58 | 59 | $this->collectEventsFromEntity($entity); 60 | } 61 | } 62 | } 63 | 64 | /** 65 | * @return object[] 66 | */ 67 | public function recordedMessages(): array 68 | { 69 | return $this->collectedEvents; 70 | } 71 | 72 | public function eraseMessages(): void 73 | { 74 | $this->collectedEvents = []; 75 | } 76 | 77 | private function collectEventsFromEntity(object $entity): void 78 | { 79 | if ($entity instanceof ContainsRecordedMessages 80 | && ( 81 | !$entity instanceof Proxy 82 | || ($entity instanceof Proxy && $entity->__isInitialized__) 83 | ) 84 | ) { 85 | foreach ($entity->recordedMessages() as $event) { 86 | $this->collectedEvents[] = $event; 87 | } 88 | $entity->eraseMessages(); 89 | } 90 | } 91 | } 92 | --------------------------------------------------------------------------------