From 0612f9554b2b32134c660415a8f995161751d66d Mon Sep 17 00:00:00 2001 From: Christopher Gammie Date: Sun, 13 Oct 2024 16:49:17 +0100 Subject: [PATCH 1/8] docs: add php 8.4 deprecation message fixes to changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cc21cd..fadfedf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,10 @@ All notable changes to this project will be documented in this file. This projec is already implemented. - New `AggregateRoot` interface so that an aggregate root can be distinguished from a regular aggregate or entity. +### Changed + +- Remove deprecation message in PHP 8.4. + ## [2.0.0-rc.2] - 2024-07-27 ### Added From 01feb5fae16f29784f5f37a6eae732183ded671d Mon Sep 17 00:00:00 2001 From: Christopher Gammie Date: Wed, 16 Oct 2024 18:00:47 +0100 Subject: [PATCH 2/8] style: add nullable type declarations --- pint.json | 3 ++- src/Toolkit/Result/Error.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pint.json b/pint.json index 3a56850..3de4dce 100644 --- a/pint.json +++ b/pint.json @@ -4,6 +4,7 @@ "declare_strict_types": true, "trailing_comma_in_multiline": { "elements": ["arguments", "arrays", "match", "parameters"] - } + }, + "nullable_type_declaration": true } } diff --git a/src/Toolkit/Result/Error.php b/src/Toolkit/Result/Error.php index ab8bff6..0b2e446 100644 --- a/src/Toolkit/Result/Error.php +++ b/src/Toolkit/Result/Error.php @@ -30,7 +30,7 @@ final class Error implements IError * @param BackedEnum|null $code */ public function __construct( - string|null $key = null, + ?string $key = null, private readonly string $message = '', private readonly ?BackedEnum $code = null, ) { From c25a80549e121165a4105969ada682f6e9ede90c Mon Sep 17 00:00:00 2001 From: Christopher Gammie Date: Tue, 12 Nov 2024 18:50:05 +0000 Subject: [PATCH 3/8] feat: upgrade to phpstan v2 --- CHANGELOG.md | 4 ++ composer.json | 2 +- .../Toolkit/Iterables/ListIterator.php | 2 +- .../OutboundEventBus/ComponentPublisher.php | 2 +- src/Toolkit/Identifiers/ListOfIdentifiers.php | 2 +- src/Toolkit/Iterables/IsList.php | 2 +- src/Toolkit/Iterables/IsNonEmptyList.php | 2 +- src/Toolkit/Pipeline/PipelineBuilder.php | 2 +- src/Toolkit/Result/KeyedSetOfErrors.php | 1 - src/Toolkit/Result/ListOfErrors.php | 2 +- tests/Unit/Application/Bus/ValidatorTest.php | 6 +-- .../SwallowInboundEventTest.php | 1 + tests/Unit/Toolkit/ContractsTest.php | 1 + .../Identifiers/PossiblyNumericIdTest.php | 6 +-- ...zyListTraitTest.php => IsLazyListTest.php} | 2 +- .../Toolkit/Iterables/IsNonEmptyListTest.php | 44 +++++++++++++++++++ 16 files changed, 63 insertions(+), 18 deletions(-) rename tests/Unit/Toolkit/Iterables/{LazyListTraitTest.php => IsLazyListTest.php} (97%) create mode 100644 tests/Unit/Toolkit/Iterables/IsNonEmptyListTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index fadfedf..3e2105d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. This projec ## Unreleased +### Changed + +- Upgraded to PHPStan v2. + ## [2.0.0-rc.3] - 2024-10-13 ### Added diff --git a/composer.json b/composer.json index 0654157..13cedba 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ }, "require-dev": { "laravel/pint": "^1.15", - "phpstan/phpstan": "^1.10", + "phpstan/phpstan": "^2.0", "phpunit/phpunit": "^10.4" }, "autoload": { diff --git a/src/Contracts/Toolkit/Iterables/ListIterator.php b/src/Contracts/Toolkit/Iterables/ListIterator.php index d3bacd6..6df270b 100644 --- a/src/Contracts/Toolkit/Iterables/ListIterator.php +++ b/src/Contracts/Toolkit/Iterables/ListIterator.php @@ -16,7 +16,7 @@ /** * @template TValue - * @extends IteratorAggregate + * @extends IteratorAggregate */ interface ListIterator extends IteratorAggregate, Countable { diff --git a/src/Infrastructure/OutboundEventBus/ComponentPublisher.php b/src/Infrastructure/OutboundEventBus/ComponentPublisher.php index f1e4e07..00b9ec9 100644 --- a/src/Infrastructure/OutboundEventBus/ComponentPublisher.php +++ b/src/Infrastructure/OutboundEventBus/ComponentPublisher.php @@ -47,7 +47,7 @@ public function through(array $pipes): void { assert(array_is_list($pipes), 'Expecting an array list of middleware.'); - $this->pipes = array_values($pipes); + $this->pipes = $pipes; } /** diff --git a/src/Toolkit/Identifiers/ListOfIdentifiers.php b/src/Toolkit/Identifiers/ListOfIdentifiers.php index ac68793..3cfa2b8 100644 --- a/src/Toolkit/Identifiers/ListOfIdentifiers.php +++ b/src/Toolkit/Identifiers/ListOfIdentifiers.php @@ -30,7 +30,7 @@ final class ListOfIdentifiers implements ListIterator */ public function __construct(Identifier ...$identifiers) { - $this->stack = $identifiers; + $this->stack = array_values($identifiers); } /** diff --git a/src/Toolkit/Iterables/IsList.php b/src/Toolkit/Iterables/IsList.php index bf557d7..55b71f8 100644 --- a/src/Toolkit/Iterables/IsList.php +++ b/src/Toolkit/Iterables/IsList.php @@ -19,7 +19,7 @@ trait IsList { /** - * @var array + * @var list */ private array $stack = []; diff --git a/src/Toolkit/Iterables/IsNonEmptyList.php b/src/Toolkit/Iterables/IsNonEmptyList.php index 9df89e5..8ff28e5 100644 --- a/src/Toolkit/Iterables/IsNonEmptyList.php +++ b/src/Toolkit/Iterables/IsNonEmptyList.php @@ -21,7 +21,7 @@ trait IsNonEmptyList /** * @var non-empty-list */ - private array $stack = []; + private array $stack; /** * @return Generator diff --git a/src/Toolkit/Pipeline/PipelineBuilder.php b/src/Toolkit/Pipeline/PipelineBuilder.php index 99825c6..dd608a1 100644 --- a/src/Toolkit/Pipeline/PipelineBuilder.php +++ b/src/Toolkit/Pipeline/PipelineBuilder.php @@ -83,7 +83,7 @@ private function normalize(callable|string $stage): callable return $stage; } - if (is_string($stage) && $this->container) { + if ($this->container) { return new LazyPipe($this->container, $stage); } diff --git a/src/Toolkit/Result/KeyedSetOfErrors.php b/src/Toolkit/Result/KeyedSetOfErrors.php index 4896a02..4dcbc3f 100644 --- a/src/Toolkit/Result/KeyedSetOfErrors.php +++ b/src/Toolkit/Result/KeyedSetOfErrors.php @@ -85,7 +85,6 @@ public function merge(IListOfErrors|self $other): self $copy = clone $this; foreach (self::from($other) as $key => $errors) { - assert(is_string($key) && $errors instanceof IListOfErrors); $copy->stack[$key] = $copy->get($key)->merge($errors); } diff --git a/src/Toolkit/Result/ListOfErrors.php b/src/Toolkit/Result/ListOfErrors.php index e5c4ac5..9aa8929 100644 --- a/src/Toolkit/Result/ListOfErrors.php +++ b/src/Toolkit/Result/ListOfErrors.php @@ -42,7 +42,7 @@ public static function from(IListOfErrors|IError|BackedEnum|array|string $value) */ public function __construct(IError ...$errors) { - $this->stack = $errors; + $this->stack = array_values($errors); } /** diff --git a/tests/Unit/Application/Bus/ValidatorTest.php b/tests/Unit/Application/Bus/ValidatorTest.php index 5933d69..f7a28f4 100644 --- a/tests/Unit/Application/Bus/ValidatorTest.php +++ b/tests/Unit/Application/Bus/ValidatorTest.php @@ -13,11 +13,11 @@ use CloudCreativity\Modules\Application\Bus\Validator; use CloudCreativity\Modules\Contracts\Application\Messages\Command; -use CloudCreativity\Modules\Contracts\Application\Messages\Message; use CloudCreativity\Modules\Contracts\Application\Messages\Query; use CloudCreativity\Modules\Contracts\Toolkit\Pipeline\PipeContainer; use CloudCreativity\Modules\Toolkit\Result\Error; use CloudCreativity\Modules\Toolkit\Result\ListOfErrors; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class ValidatorTest extends TestCase @@ -34,13 +34,13 @@ public static function messageProvider(): array } /** - * @param class-string $message + * @param class-string $message * @return void * @dataProvider messageProvider */ public function test(string $message): void { - /** @var Command|Query $query */ + /** @var (Command&MockObject)|(Query&MockObject) $query */ $query = $this->createMock($message); $error1 = new Error(null, 'Message 1'); $error2 = new Error(null, 'Message 2'); diff --git a/tests/Unit/Application/InboundEventBus/SwallowInboundEventTest.php b/tests/Unit/Application/InboundEventBus/SwallowInboundEventTest.php index a8ad653..44e37cf 100644 --- a/tests/Unit/Application/InboundEventBus/SwallowInboundEventTest.php +++ b/tests/Unit/Application/InboundEventBus/SwallowInboundEventTest.php @@ -26,6 +26,7 @@ public function testItDoesNothing(): void { $handler = new SwallowInboundEvent(); $handler->handle(new TestInboundEvent()); + /** @phpstan-ignore-next-line */ $this->assertTrue(true); } diff --git a/tests/Unit/Toolkit/ContractsTest.php b/tests/Unit/Toolkit/ContractsTest.php index e42ff69..17451ee 100644 --- a/tests/Unit/Toolkit/ContractsTest.php +++ b/tests/Unit/Toolkit/ContractsTest.php @@ -23,6 +23,7 @@ class ContractsTest extends TestCase public function testItDoesNotThrowWhenPreconditionIsTrue(): void { Contracts::assert(true, 'Not expected error.'); + /** @phpstan-ignore-next-line */ $this->assertTrue(true); } diff --git a/tests/Unit/Toolkit/Identifiers/PossiblyNumericIdTest.php b/tests/Unit/Toolkit/Identifiers/PossiblyNumericIdTest.php index cc4cf41..886386d 100644 --- a/tests/Unit/Toolkit/Identifiers/PossiblyNumericIdTest.php +++ b/tests/Unit/Toolkit/Identifiers/PossiblyNumericIdTest.php @@ -42,11 +42,7 @@ public static function valueProvider(): array public function test(string|int $value, string|int $expected): void { $actual = new PossiblyNumericId($value); - $expectedId = match (true) { - is_string($expected) => new StringId($expected), - is_int($expected) => new IntegerId($expected), - default => $this->fail('Unexpected value.'), - }; + $expectedId = is_string($expected) ? new StringId($expected) : new IntegerId($expected); $this->assertSame($expected, $actual->value); $this->assertSame($expected, PossiblyNumericId::from($value)->value); diff --git a/tests/Unit/Toolkit/Iterables/LazyListTraitTest.php b/tests/Unit/Toolkit/Iterables/IsLazyListTest.php similarity index 97% rename from tests/Unit/Toolkit/Iterables/LazyListTraitTest.php rename to tests/Unit/Toolkit/Iterables/IsLazyListTest.php index 1771351..4992b61 100644 --- a/tests/Unit/Toolkit/Iterables/LazyListTraitTest.php +++ b/tests/Unit/Toolkit/Iterables/IsLazyListTest.php @@ -15,7 +15,7 @@ use CloudCreativity\Modules\Toolkit\Iterables\IsLazyList; use PHPUnit\Framework\TestCase; -class LazyListTraitTest extends TestCase +class IsLazyListTest extends TestCase { /** * @return void diff --git a/tests/Unit/Toolkit/Iterables/IsNonEmptyListTest.php b/tests/Unit/Toolkit/Iterables/IsNonEmptyListTest.php new file mode 100644 index 0000000..4218175 --- /dev/null +++ b/tests/Unit/Toolkit/Iterables/IsNonEmptyListTest.php @@ -0,0 +1,44 @@ + + */ + $list = new class (...$expected) implements NonEmptyList { + /** @use IsNonEmptyList */ + use IsNonEmptyList; + + public function __construct(string $value, string ...$values) + { + $this->stack = [$value, ...array_values($values)]; + } + }; + + $this->assertSame($expected, iterator_to_array($list)); + $this->assertSame($expected, $list->all()); + $this->assertCount(count($expected), $list); + } +} From 2099076f672614ca7fb218f880147d551357db7e Mon Sep 17 00:00:00 2001 From: Christopher Gammie Date: Tue, 12 Nov 2024 20:04:36 +0000 Subject: [PATCH 4/8] feat: upgrade to phpstan level 10 --- phpstan.neon | 2 +- src/Application/Bus/CommandHandler.php | 6 ++- src/Application/Bus/QueryHandler.php | 6 ++- .../DomainEventDispatching/Dispatcher.php | 2 +- src/Toolkit/Identifiers/UuidFactory.php | 8 ++- src/Toolkit/Pipeline/MiddlewareProcessor.php | 2 + src/Toolkit/Pipeline/PipeContainer.php | 6 ++- .../DeferredDispatcherTest.php | 6 ++- .../DomainEventDispatching/DispatcherTest.php | 4 +- .../UnitOfWorkAwareDispatcherTest.php | 4 +- .../Pipeline/InterruptibleProcessorTest.php | 2 +- .../Pipeline/MiddlewareProcessorTest.php | 52 +++++++++---------- 12 files changed, 61 insertions(+), 39 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 42888f2..bb836b2 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,5 @@ parameters: - level: 9 + level: 10 paths: - src - tests diff --git a/src/Application/Bus/CommandHandler.php b/src/Application/Bus/CommandHandler.php index 58e1449..baa30c5 100644 --- a/src/Application/Bus/CommandHandler.php +++ b/src/Application/Bus/CommandHandler.php @@ -38,7 +38,11 @@ public function __invoke(Command $command): Result $this->handler::class, )); - return $this->handler->execute($command); + $result = $this->handler->execute($command); + + assert($result instanceof Result, 'Expecting command handler to return a result.'); + + return $result; } /** diff --git a/src/Application/Bus/QueryHandler.php b/src/Application/Bus/QueryHandler.php index 263fdf9..ed8e5ee 100644 --- a/src/Application/Bus/QueryHandler.php +++ b/src/Application/Bus/QueryHandler.php @@ -38,7 +38,11 @@ public function __invoke(Query $query): Result $this->handler::class, )); - return $this->handler->execute($query); + $result = $this->handler->execute($query); + + assert($result instanceof Result, 'Expecting query handler to return a result.'); + + return $result; } /** diff --git a/src/Application/DomainEventDispatching/Dispatcher.php b/src/Application/DomainEventDispatching/Dispatcher.php index 0ebe9bf..7c14868 100644 --- a/src/Application/DomainEventDispatching/Dispatcher.php +++ b/src/Application/DomainEventDispatching/Dispatcher.php @@ -67,7 +67,7 @@ public function listen(string $event, string|Closure|array $listener): void { $bindings = $this->bindings[$event] ?? []; - foreach ((array) $listener as $name) { + foreach (is_array($listener) ? $listener : [$listener] as $name) { if ($this->canAttach($name)) { $bindings[] = $name; continue; diff --git a/src/Toolkit/Identifiers/UuidFactory.php b/src/Toolkit/Identifiers/UuidFactory.php index 9244355..64f0119 100644 --- a/src/Toolkit/Identifiers/UuidFactory.php +++ b/src/Toolkit/Identifiers/UuidFactory.php @@ -145,7 +145,9 @@ public function uuid6(?Hexadecimal $node = null, ?int $clockSeq = null): Uuid public function uuid7(?DateTimeInterface $dateTime = null): Uuid { if (method_exists($this->baseFactory, 'uuid7')) { - return new Uuid($this->baseFactory->uuid7($dateTime)); + $base = $this->baseFactory->uuid7($dateTime); + assert($base instanceof UuidInterface); + return new Uuid($base); } throw new RuntimeException('UUID version 7 is not supported by the underlying factory.'); @@ -157,7 +159,9 @@ public function uuid7(?DateTimeInterface $dateTime = null): Uuid public function uuid8(string $bytes): Uuid { if (method_exists($this->baseFactory, 'uuid8')) { - return new Uuid($this->baseFactory->uuid8($bytes)); + $base = $this->baseFactory->uuid8($bytes); + assert($base instanceof UuidInterface); + return new Uuid($base); } throw new RuntimeException('UUID version 8 is not supported by the underlying factory.'); diff --git a/src/Toolkit/Pipeline/MiddlewareProcessor.php b/src/Toolkit/Pipeline/MiddlewareProcessor.php index dcaf511..00f2fd0 100644 --- a/src/Toolkit/Pipeline/MiddlewareProcessor.php +++ b/src/Toolkit/Pipeline/MiddlewareProcessor.php @@ -66,6 +66,8 @@ public function process(mixed $payload, callable ...$stages): mixed $this->destination, ); + assert(is_callable($pipeline)); + return $pipeline($payload); } diff --git a/src/Toolkit/Pipeline/PipeContainer.php b/src/Toolkit/Pipeline/PipeContainer.php index 948a744..e104f3b 100644 --- a/src/Toolkit/Pipeline/PipeContainer.php +++ b/src/Toolkit/Pipeline/PipeContainer.php @@ -41,8 +41,10 @@ public function get(string $pipeName): callable { $factory = $this->pipes[$pipeName] ?? null; - if ($factory) { - return $factory(); + if (is_callable($factory)) { + $pipe = $factory(); + assert(is_callable($pipe), 'Expecting pipe from factory to be callable.'); + return $pipe; } throw new RuntimeException('Unrecognised pipe name: ' . $pipeName); diff --git a/tests/Unit/Application/DomainEventDispatching/DeferredDispatcherTest.php b/tests/Unit/Application/DomainEventDispatching/DeferredDispatcherTest.php index de77ea9..b8e7312 100644 --- a/tests/Unit/Application/DomainEventDispatching/DeferredDispatcherTest.php +++ b/tests/Unit/Application/DomainEventDispatching/DeferredDispatcherTest.php @@ -63,7 +63,7 @@ public function testItDispatchesImmediately(): void $listener3 = $this->createMock(TestListener::class); $listener4 = $this->createMock(TestListener::class); - $listener2Closure = static fn ($event) => $listener2->handle($event); + $listener2Closure = static fn (DomainEvent $event) => $listener2->handle($event); $this->listeners ->expects($this->exactly(2)) @@ -130,7 +130,7 @@ public function testItFlushesDeferredEvents(): void $listener3 = $this->createMock(TestListener::class); $listener4 = $this->createMock(TestListener::class); - $listener2Closure = static fn ($event) => $listener2->handle($event1); + $listener2Closure = static fn (DomainEvent $event) => $listener2->handle($event1); $this->listeners ->expects($this->exactly(3)) @@ -399,11 +399,13 @@ public function testItDispatchesThroughMiddleware(): void $a = function ($actual, Closure $next) use ($event1, $event2): DomainEvent { $this->assertSame($event1, $actual); + /** @phpstan-ignore-next-line */ return $next($event2); }; $b = function ($actual, Closure $next) use ($event2, $event3): DomainEvent { $this->assertSame($event2, $actual); + /** @phpstan-ignore-next-line */ return $next($event3); }; diff --git a/tests/Unit/Application/DomainEventDispatching/DispatcherTest.php b/tests/Unit/Application/DomainEventDispatching/DispatcherTest.php index 79b2893..d4d0756 100644 --- a/tests/Unit/Application/DomainEventDispatching/DispatcherTest.php +++ b/tests/Unit/Application/DomainEventDispatching/DispatcherTest.php @@ -64,7 +64,7 @@ public function testItDispatchesImmediately(): void $listener3 = $this->createMock(TestListener::class); $listener4 = $this->createMock(TestListener::class); - $listener2Closure = static fn ($event) => $listener2->handle($event); + $listener2Closure = static fn (DomainEvent $event) => $listener2->handle($event); $this->listeners ->expects($this->exactly(2)) @@ -136,11 +136,13 @@ public function testItDispatchesThroughMiddleware(): void $a = function ($actual, Closure $next) use ($event1, $event2): DomainEvent { $this->assertSame($event1, $actual); + /** @phpstan-ignore-next-line */ return $next($event2); }; $b = function ($actual, Closure $next) use ($event2, $event3): DomainEvent { $this->assertSame($event2, $actual); + /** @phpstan-ignore-next-line */ return $next($event3); }; diff --git a/tests/Unit/Application/DomainEventDispatching/UnitOfWorkAwareDispatcherTest.php b/tests/Unit/Application/DomainEventDispatching/UnitOfWorkAwareDispatcherTest.php index 4719ddc..c0d6273 100644 --- a/tests/Unit/Application/DomainEventDispatching/UnitOfWorkAwareDispatcherTest.php +++ b/tests/Unit/Application/DomainEventDispatching/UnitOfWorkAwareDispatcherTest.php @@ -75,7 +75,7 @@ public function testItDispatchesImmediately(): void $listener6 = $this->createMock(TestListenerAfterCommit::class); $listener7 = $this->createMock(TestListener::class); - $listener2Closure = static fn ($event) => $listener2->handle($event); + $listener2Closure = static fn (DomainEvent $event) => $listener2->handle($event); $this->listeners ->expects($this->exactly(5)) @@ -327,11 +327,13 @@ public function testItDispatchesThroughMiddleware(): void $a = function ($actual, Closure $next) use ($event1, $event2): DomainEvent { $this->assertSame($event1, $actual); + /** @phpstan-ignore-next-line */ return $next($event2); }; $b = function ($actual, Closure $next) use ($event2, $event3): DomainEvent { $this->assertSame($event2, $actual); + /** @phpstan-ignore-next-line */ return $next($event3); }; diff --git a/tests/Unit/Toolkit/Pipeline/InterruptibleProcessorTest.php b/tests/Unit/Toolkit/Pipeline/InterruptibleProcessorTest.php index 0921db5..8c2b878 100644 --- a/tests/Unit/Toolkit/Pipeline/InterruptibleProcessorTest.php +++ b/tests/Unit/Toolkit/Pipeline/InterruptibleProcessorTest.php @@ -19,7 +19,7 @@ class InterruptibleProcessorTest extends TestCase public function test(): void { $processor = new InterruptibleProcessor( - static fn ($value): bool => 0 === (intval($value) % 10), + static fn (int|float $value): bool => 0 === (intval($value) % 10), ); $a = static fn (int $value): int => $value * 10; diff --git a/tests/Unit/Toolkit/Pipeline/MiddlewareProcessorTest.php b/tests/Unit/Toolkit/Pipeline/MiddlewareProcessorTest.php index 089a27d..d1c191f 100644 --- a/tests/Unit/Toolkit/Pipeline/MiddlewareProcessorTest.php +++ b/tests/Unit/Toolkit/Pipeline/MiddlewareProcessorTest.php @@ -11,39 +11,21 @@ namespace CloudCreativity\Modules\Tests\Unit\Toolkit\Pipeline; +use Closure; use CloudCreativity\Modules\Toolkit\Pipeline\MiddlewareProcessor; use PHPUnit\Framework\TestCase; class MiddlewareProcessorTest extends TestCase { - /** - * @var \Closure - */ - private \Closure $middleware; - - protected function setUp(): void - { - parent::setUp(); - - $this->middleware = static function (string $step): \Closure { - return static function (array $values, \Closure $next) use ($step) { - $values[] = "{$step}1"; - $result = $next($values); - $result[] = "{$step}2"; - return $result; - }; - }; - } - public function test(): void { $processor = new MiddlewareProcessor(); $result = $processor->process( [], - ($this->middleware)('A'), - ($this->middleware)('B'), - ($this->middleware)('C'), + $this->createMiddleware('A'), + $this->createMiddleware('B'), + $this->createMiddleware('C'), ); $this->assertSame(['A1', 'B1', 'C1', 'C2', 'B2', 'A2'], $result); @@ -52,14 +34,17 @@ public function test(): void public function testWithDestination(): void { $processor = new MiddlewareProcessor( - static fn (array $values): array => array_map('strtolower', $values), + static fn (array $values): array => array_map( + static fn (string $v): string => strtolower($v), /** @phpstan-ignore-line */ + $values, + ), ); $result = $processor->process( [], - ($this->middleware)('A'), - ($this->middleware)('B'), - ($this->middleware)('C'), + $this->createMiddleware('A'), + $this->createMiddleware('B'), + $this->createMiddleware('C'), ); $this->assertSame(['a1', 'b1', 'c1', 'C2', 'B2', 'A2'], $result); @@ -84,4 +69,19 @@ public function testNoStagesWithDestination(): void $this->assertSame('FOO', $result); } + + /** + * @param string $step + * @return Closure + */ + private function createMiddleware(string $step): Closure + { + return static function (array $values, Closure $next) use ($step) { + $values[] = "{$step}1"; + $result = $next($values); + assert(is_array($result)); + $result[] = "{$step}2"; + return $result; + }; + } } From 3b52d79122224c35b841113a9be7c0daf4ce2aa2 Mon Sep 17 00:00:00 2001 From: Christopher Gammie Date: Sat, 7 Dec 2024 15:28:19 +0000 Subject: [PATCH 5/8] style: updates for new php cs rule for blank lines --- src/Application/Bus/CommandDispatcher.php | 1 + src/Application/Bus/CommandHandler.php | 1 + src/Application/Bus/CommandHandlerContainer.php | 1 + src/Application/Bus/Exceptions/AbortOnFailureException.php | 1 + src/Application/Bus/Middleware/ExecuteInUnitOfWork.php | 1 + src/Application/Bus/Middleware/FlushDeferredEvents.php | 1 + src/Application/Bus/Middleware/LogMessageDispatch.php | 1 + src/Application/Bus/Middleware/SetupBeforeDispatch.php | 1 + src/Application/Bus/Middleware/TearDownAfterDispatch.php | 1 + src/Application/Bus/Middleware/ValidateCommand.php | 1 + src/Application/Bus/Middleware/ValidateQuery.php | 1 + src/Application/Bus/QueryDispatcher.php | 1 + src/Application/Bus/QueryHandler.php | 1 + src/Application/Bus/QueryHandlerContainer.php | 1 + src/Application/Bus/Validator.php | 1 + src/Application/DomainEventDispatching/DeferredDispatcher.php | 1 + src/Application/DomainEventDispatching/Dispatcher.php | 1 + src/Application/DomainEventDispatching/EventHandler.php | 1 + src/Application/DomainEventDispatching/ListenerContainer.php | 1 + .../DomainEventDispatching/Middleware/LogDomainEventDispatch.php | 1 + .../DomainEventDispatching/UnitOfWorkAwareDispatcher.php | 1 + src/Application/InboundEventBus/EventDispatcher.php | 1 + src/Application/InboundEventBus/EventHandler.php | 1 + src/Application/InboundEventBus/EventHandlerContainer.php | 1 + .../InboundEventBus/Middleware/FlushDeferredEvents.php | 1 + .../InboundEventBus/Middleware/HandleInUnitOfWork.php | 1 + src/Application/InboundEventBus/Middleware/LogInboundEvent.php | 1 + src/Application/InboundEventBus/Middleware/SetupBeforeEvent.php | 1 + .../InboundEventBus/Middleware/TearDownAfterEvent.php | 1 + src/Application/InboundEventBus/SwallowInboundEvent.php | 1 + src/Application/UnitOfWork/UnitOfWorkManager.php | 1 + src/Contracts/Application/Bus/BusMiddleware.php | 1 + src/Contracts/Application/Bus/CommandHandler.php | 1 + src/Contracts/Application/Bus/CommandHandlerContainer.php | 1 + src/Contracts/Application/Bus/CommandMiddleware.php | 1 + src/Contracts/Application/Bus/QueryHandler.php | 1 + src/Contracts/Application/Bus/QueryHandlerContainer.php | 1 + src/Contracts/Application/Bus/QueryMiddleware.php | 1 + src/Contracts/Application/Bus/Validator.php | 1 + .../Application/DomainEventDispatching/DeferredDispatcher.php | 1 + .../Application/DomainEventDispatching/DomainEventMiddleware.php | 1 + .../Application/DomainEventDispatching/ListenerContainer.php | 1 + src/Contracts/Application/InboundEventBus/EventHandler.php | 1 + .../Application/InboundEventBus/EventHandlerContainer.php | 1 + .../Application/InboundEventBus/InboundEventMiddleware.php | 1 + src/Contracts/Application/Messages/Command.php | 1 + src/Contracts/Application/Messages/DispatchThroughMiddleware.php | 1 + src/Contracts/Application/Messages/IntegrationEvent.php | 1 + src/Contracts/Application/Messages/Message.php | 1 + src/Contracts/Application/Messages/Query.php | 1 + .../Application/Ports/Driven/Exceptions/ExceptionReporter.php | 1 + .../Application/Ports/Driven/OutboundEventBus/EventPublisher.php | 1 + src/Contracts/Application/Ports/Driven/Queue/Queue.php | 1 + src/Contracts/Application/Ports/Driven/UnitOfWork/UnitOfWork.php | 1 + .../Application/Ports/Driving/Commands/CommandDispatcher.php | 1 + .../Application/Ports/Driving/InboundEvents/EventDispatcher.php | 1 + .../Application/Ports/Driving/Queries/QueryDispatcher.php | 1 + src/Contracts/Application/UnitOfWork/DispatchAfterCommit.php | 1 + src/Contracts/Application/UnitOfWork/DispatchBeforeCommit.php | 1 + src/Contracts/Application/UnitOfWork/UnitOfWorkManager.php | 1 + src/Contracts/Domain/Aggregate.php | 1 + src/Contracts/Domain/AggregateRoot.php | 1 + src/Contracts/Domain/Entity.php | 1 + src/Contracts/Domain/Events/DomainEvent.php | 1 + src/Contracts/Domain/Events/DomainEventDispatcher.php | 1 + src/Contracts/Domain/Events/OccursImmediately.php | 1 + .../Infrastructure/OutboundEventBus/OutboundEventMiddleware.php | 1 + .../Infrastructure/OutboundEventBus/PublisherHandler.php | 1 + .../OutboundEventBus/PublisherHandlerContainer.php | 1 + src/Contracts/Infrastructure/Queue/Enqueuer.php | 1 + src/Contracts/Infrastructure/Queue/EnqueuerContainer.php | 1 + src/Contracts/Infrastructure/Queue/QueueMiddleware.php | 1 + src/Contracts/Toolkit/Identifiers/Identifier.php | 1 + src/Contracts/Toolkit/Identifiers/IdentifierFactory.php | 1 + src/Contracts/Toolkit/Identifiers/UuidFactory.php | 1 + src/Contracts/Toolkit/Iterables/KeyedSet.php | 1 + src/Contracts/Toolkit/Iterables/LazyList.php | 1 + src/Contracts/Toolkit/Iterables/ListIterator.php | 1 + src/Contracts/Toolkit/Iterables/NonEmptyList.php | 1 + src/Contracts/Toolkit/Loggable/ContextProvider.php | 1 + src/Contracts/Toolkit/Pipeline/PipeContainer.php | 1 + src/Contracts/Toolkit/Pipeline/Pipeline.php | 1 + src/Contracts/Toolkit/Pipeline/PipelineBuilder.php | 1 + src/Contracts/Toolkit/Pipeline/Processor.php | 1 + src/Contracts/Toolkit/Result/Error.php | 1 + src/Contracts/Toolkit/Result/ListOfErrors.php | 1 + src/Contracts/Toolkit/Result/Result.php | 1 + src/Domain/IdentifierOrEntity.php | 1 + src/Domain/IsEntity.php | 1 + src/Domain/IsEntityWithNullableId.php | 1 + src/Infrastructure/InfrastructureException.php | 1 + src/Infrastructure/OutboundEventBus/ClosurePublisher.php | 1 + src/Infrastructure/OutboundEventBus/ComponentPublisher.php | 1 + .../OutboundEventBus/Middleware/LogOutboundEvent.php | 1 + src/Infrastructure/OutboundEventBus/PublisherHandler.php | 1 + .../OutboundEventBus/PublisherHandlerContainer.php | 1 + src/Infrastructure/Queue/ClosureQueue.php | 1 + src/Infrastructure/Queue/ComponentQueue.php | 1 + src/Infrastructure/Queue/Enqueuer.php | 1 + src/Infrastructure/Queue/EnqueuerContainer.php | 1 + src/Infrastructure/Queue/Middleware/LogPushedToQueue.php | 1 + src/Toolkit/ContractException.php | 1 + src/Toolkit/Contracts.php | 1 + src/Toolkit/Identifiers/Guid.php | 1 + src/Toolkit/Identifiers/GuidTypeMap.php | 1 + src/Toolkit/Identifiers/IdentifierFactory.php | 1 + src/Toolkit/Identifiers/IntegerId.php | 1 + src/Toolkit/Identifiers/LazyListOfGuids.php | 1 + src/Toolkit/Identifiers/LazyListOfIdentifiers.php | 1 + src/Toolkit/Identifiers/LazyListOfIntegerIds.php | 1 + src/Toolkit/Identifiers/LazyListOfStringIds.php | 1 + src/Toolkit/Identifiers/LazyListOfUuids.php | 1 + src/Toolkit/Identifiers/ListOfIdentifiers.php | 1 + src/Toolkit/Identifiers/PossiblyNumericId.php | 1 + src/Toolkit/Identifiers/StringId.php | 1 + src/Toolkit/Identifiers/Uuid.php | 1 + src/Toolkit/Identifiers/UuidFactory.php | 1 + src/Toolkit/Iterables/IsKeyedSet.php | 1 + src/Toolkit/Iterables/IsLazyList.php | 1 + src/Toolkit/Iterables/IsList.php | 1 + src/Toolkit/Iterables/IsNonEmptyList.php | 1 + src/Toolkit/Loggable/ObjectContext.php | 1 + src/Toolkit/Loggable/ResultContext.php | 1 + src/Toolkit/ModuleBasename.php | 1 + src/Toolkit/Pipeline/AccumulationProcessor.php | 1 + src/Toolkit/Pipeline/InterruptibleProcessor.php | 1 + src/Toolkit/Pipeline/LazyPipe.php | 1 + src/Toolkit/Pipeline/MiddlewareProcessor.php | 1 + src/Toolkit/Pipeline/PipeContainer.php | 1 + src/Toolkit/Pipeline/Pipeline.php | 1 + src/Toolkit/Pipeline/PipelineBuilder.php | 1 + src/Toolkit/Pipeline/SimpleProcessor.php | 1 + src/Toolkit/Result/Error.php | 1 + src/Toolkit/Result/FailedResultException.php | 1 + src/Toolkit/Result/KeyedSetOfErrors.php | 1 + src/Toolkit/Result/ListOfErrors.php | 1 + src/Toolkit/Result/Meta.php | 1 + src/Toolkit/Result/Result.php | 1 + tests/Unit/Application/Bus/CommandDispatcherTest.php | 1 + tests/Unit/Application/Bus/CommandHandlerContainerTest.php | 1 + tests/Unit/Application/Bus/CommandHandlerTest.php | 1 + .../Unit/Application/Bus/Middleware/ExecuteInUnitOfWorkTest.php | 1 + .../Unit/Application/Bus/Middleware/FlushDeferredEventsTest.php | 1 + tests/Unit/Application/Bus/Middleware/LogMessageDispatchTest.php | 1 + .../Unit/Application/Bus/Middleware/SetupBeforeDispatchTest.php | 1 + .../Application/Bus/Middleware/TearDownAfterDispatchTest.php | 1 + tests/Unit/Application/Bus/Middleware/ValidateCommandTest.php | 1 + tests/Unit/Application/Bus/Middleware/ValidateQueryTest.php | 1 + tests/Unit/Application/Bus/QueryDispatcherTest.php | 1 + tests/Unit/Application/Bus/QueryHandlerContainerTest.php | 1 + tests/Unit/Application/Bus/QueryHandlerTest.php | 1 + tests/Unit/Application/Bus/TestCommand.php | 1 + tests/Unit/Application/Bus/TestCommandHandler.php | 1 + tests/Unit/Application/Bus/TestQuery.php | 1 + tests/Unit/Application/Bus/TestQueryHandler.php | 1 + tests/Unit/Application/Bus/ValidatorTest.php | 1 + .../DomainEventDispatching/DeferredDispatcherTest.php | 1 + tests/Unit/Application/DomainEventDispatching/DispatcherTest.php | 1 + .../Application/DomainEventDispatching/ListenerContainerTest.php | 1 + .../Middleware/LogDomainEventDispatchTest.php | 1 + .../Unit/Application/DomainEventDispatching/TestDomainEvent.php | 1 + .../DomainEventDispatching/TestImmediateDomainEvent.php | 1 + tests/Unit/Application/DomainEventDispatching/TestListener.php | 1 + .../DomainEventDispatching/TestListenerAfterCommit.php | 1 + .../DomainEventDispatching/TestListenerBeforeCommit.php | 1 + .../DomainEventDispatching/UnitOfWorkAwareDispatcherTest.php | 1 + tests/Unit/Application/InboundEventBus/EventDispatcherTest.php | 1 + .../Application/InboundEventBus/EventHandlerContainerTest.php | 1 + tests/Unit/Application/InboundEventBus/EventHandlerTest.php | 1 + .../InboundEventBus/Middleware/FlushDeferredEventsTest.php | 1 + .../InboundEventBus/Middleware/HandleInUnitOfWorkTest.php | 1 + .../InboundEventBus/Middleware/LogInboundEventTest.php | 1 + .../InboundEventBus/Middleware/SetupBeforeEventTest.php | 1 + .../InboundEventBus/Middleware/TearDownAfterEventTest.php | 1 + .../Unit/Application/InboundEventBus/SwallowInboundEventTest.php | 1 + tests/Unit/Application/InboundEventBus/TestEventHandler.php | 1 + tests/Unit/Application/InboundEventBus/TestInboundEvent.php | 1 + tests/Unit/Application/UnitOfWork/UnitOfWorkManagerTest.php | 1 + tests/Unit/Domain/EntityTest.php | 1 + tests/Unit/Domain/EntityWithNullableGuidTest.php | 1 + tests/Unit/Domain/IdentifierOrEntityTest.php | 1 + tests/Unit/Domain/TestEntity.php | 1 + tests/Unit/Domain/TestEntityWithNullableId.php | 1 + .../Infrastructure/OutboundEventBus/ClosurePublisherTest.php | 1 + .../Infrastructure/OutboundEventBus/ComponentPublisherTest.php | 1 + .../OutboundEventBus/Middleware/LogOutboundEventTest.php | 1 + .../OutboundEventBus/PublisherHandlerContainerTest.php | 1 + .../Infrastructure/OutboundEventBus/PublisherHandlerTest.php | 1 + tests/Unit/Infrastructure/OutboundEventBus/TestOutboundEvent.php | 1 + tests/Unit/Infrastructure/OutboundEventBus/TestPublisher.php | 1 + tests/Unit/Infrastructure/Queue/ClosureQueueTest.php | 1 + tests/Unit/Infrastructure/Queue/ComponentQueueTest.php | 1 + tests/Unit/Infrastructure/Queue/EnqueuerContainerTest.php | 1 + tests/Unit/Infrastructure/Queue/EnqueuerTest.php | 1 + .../Infrastructure/Queue/Middleware/LogPushedToQueueTest.php | 1 + tests/Unit/Infrastructure/Queue/TestEnqueuer.php | 1 + tests/Unit/Toolkit/ContractsTest.php | 1 + tests/Unit/Toolkit/Identifiers/GuidTest.php | 1 + tests/Unit/Toolkit/Identifiers/GuidTypeMapTest.php | 1 + tests/Unit/Toolkit/Identifiers/IntegerIdTest.php | 1 + tests/Unit/Toolkit/Identifiers/LazyListOfGuidsTest.php | 1 + tests/Unit/Toolkit/Identifiers/LazyListOfIdentifiersTest.php | 1 + tests/Unit/Toolkit/Identifiers/ListOfIdentifiersTest.php | 1 + tests/Unit/Toolkit/Identifiers/PossiblyNumericIdTest.php | 1 + tests/Unit/Toolkit/Identifiers/StringIdTest.php | 1 + tests/Unit/Toolkit/Identifiers/UuidFactoryTest.php | 1 + tests/Unit/Toolkit/Identifiers/UuidTest.php | 1 + tests/Unit/Toolkit/Iterables/IsLazyListTest.php | 1 + tests/Unit/Toolkit/Iterables/IsNonEmptyListTest.php | 1 + tests/Unit/Toolkit/Loggable/ObjectContextTest.php | 1 + tests/Unit/Toolkit/Loggable/ResultContextTest.php | 1 + tests/Unit/Toolkit/Loggable/TestEnum.php | 1 + tests/Unit/Toolkit/ModuleBasenameTest.php | 1 + tests/Unit/Toolkit/Pipeline/AccumulationProcessorTest.php | 1 + tests/Unit/Toolkit/Pipeline/InterruptibleProcessorTest.php | 1 + tests/Unit/Toolkit/Pipeline/LazyPipeTest.php | 1 + tests/Unit/Toolkit/Pipeline/MiddlewareProcessorTest.php | 1 + tests/Unit/Toolkit/Pipeline/PipeContainerTest.php | 1 + tests/Unit/Toolkit/Pipeline/PipelineBuilderTest.php | 1 + tests/Unit/Toolkit/Pipeline/PipelineTest.php | 1 + tests/Unit/Toolkit/Pipeline/SimpleProcessorTest.php | 1 + tests/Unit/Toolkit/Result/ErrorTest.php | 1 + tests/Unit/Toolkit/Result/FailedResultExceptionTest.php | 1 + tests/Unit/Toolkit/Result/KeyedSetOfErrorsTest.php | 1 + tests/Unit/Toolkit/Result/ListOfErrorsTest.php | 1 + tests/Unit/Toolkit/Result/MetaTest.php | 1 + tests/Unit/Toolkit/Result/ResultTest.php | 1 + 227 files changed, 227 insertions(+) diff --git a/src/Application/Bus/CommandDispatcher.php b/src/Application/Bus/CommandDispatcher.php index 3b97cc8..723c16c 100644 --- a/src/Application/Bus/CommandDispatcher.php +++ b/src/Application/Bus/CommandDispatcher.php @@ -1,4 +1,5 @@ Date: Tue, 3 Dec 2024 18:48:59 +0000 Subject: [PATCH 6/8] docs: update docs to clarify hexagonal concepts --- .../application/asynchronous-processing.md | 16 +++--- docs/guide/application/commands.md | 46 ++++++++-------- docs/guide/application/domain-events.md | 18 +++--- docs/guide/application/integration-events.md | 55 +++++++++---------- docs/guide/application/queries.md | 38 ++++++------- docs/guide/application/units-of-work.md | 2 +- docs/guide/concepts/layers.md | 17 ++++-- docs/guide/concepts/modularisation.md | 4 +- .../infrastructure/dependency-injection.md | 10 ++-- docs/guide/infrastructure/queues.md | 4 +- docs/guide/upgrade.md | 14 +++-- 11 files changed, 114 insertions(+), 110 deletions(-) diff --git a/docs/guide/application/asynchronous-processing.md b/docs/guide/application/asynchronous-processing.md index df04b72..039deff 100644 --- a/docs/guide/application/asynchronous-processing.md +++ b/docs/guide/application/asynchronous-processing.md @@ -95,7 +95,7 @@ processing. Some examples of where your application layer might need to push int Or anything else that fits with the specific use case of your bounded context! Our approach is to define this work as _internal_ command messages. These are queued and dispatched by a specific -_internal_ command bus - separating them from the command bus that is an adapter of the driving port in the application +_internal_ command bus - separating them from the command bus that implements the driving port in the application layer. This means internal commands are not exposed as use cases of our module - making them an internal implementation detail @@ -177,12 +177,12 @@ command is queued by an infrastructure adapter, it has left the application laye queue for processing, it needs to re-enter the application layer via a driving port. However, by defining this as a separate port to our public command bus, we can ensure that internal commands are only -dispatched by the internal command bus adapter. +dispatched by the internal command bus. -Define the port as follows: +Define the internal command bus as follows: ```php -namespace App\Modules\EventManagement\Application\Ports\Driving\CommandBus; +namespace App\Modules\EventManagement\Application\Ports\Driving; use CloudCreativity\Modules\Application\Ports\Driving\CommandBus\CommandDispatcher; @@ -191,15 +191,15 @@ interface InternalCommandBus extends CommandDispatcher } ``` -And then our adapter (the concrete implementation of the port) is as follows: +And then our port implementation is as follows: ```php -namespace App\Modules\EventManagement\Application\Adapters\CommandBus; +namespace App\Modules\EventManagement\Application\Bus; -use App\Modules\EventManagement\Application\Ports\Driving\CommandBus\InternalCommandBus; +use App\Modules\EventManagement\Application\Ports\Driving\InternalCommandBus; use CloudCreativity\Modules\Application\Bus\CommandDispatcher; -final class InternalCommandBusAdapter extends CommandDispatcher implements +final class InternalCommandBusService extends CommandDispatcher implements InternalCommandBus { } diff --git a/docs/guide/application/commands.md b/docs/guide/application/commands.md index 65f6984..fd476ba 100644 --- a/docs/guide/application/commands.md +++ b/docs/guide/application/commands.md @@ -126,7 +126,7 @@ Although there is a _generic_ command bus interface, our bounded context needs t We do this by defining an interface in our application's driving ports. ```php -namespace App\Modules\EventManagement\Application\Ports\Driving\CommandBus; +namespace App\Modules\EventManagement\Application\Ports\Driving; use CloudCreativity\Modules\Application\Ports\Driving\CommandBus\CommandDispatcher; @@ -135,23 +135,22 @@ interface CommandBus extends CommandDispatcher } ``` -And then our adapter (the concrete implementation of the port) is as follows: +And then our implementation is as follows: ```php -namespace App\Modules\EventManagement\Application\Adapters\CommandBus; +namespace App\Modules\EventManagement\Application\Bus; -use App\Modules\EventManagement\Application\Ports\Driving\CommandBus\CommandBus; +use App\Modules\EventManagement\Application\Ports\Driving\CommandBus as Port; use CloudCreativity\Modules\Application\Bus\CommandDispatcher; -final class CommandBusAdapter extends CommandDispatcher implements - CommandBus +final class CommandBus extends CommandDispatcher implements Port { } ``` ### Creating a Command Bus -The command dispatcher class that your adapter extended (in the above example) allows you to build a command bus +The command dispatcher class that your implementation extends (in the above example) allows you to build a command bus specific to your domain. You do this by: 1. Binding command handler factories into the command dispatcher; and @@ -164,29 +163,29 @@ handler or middleware are actually being used. For example: ```php -namespace App\Modules\EventManagement\Application\Adapters\CommandBus; +namespace App\Modules\EventManagement\Application\Bus; use App\Modules\EventManagement\Application\UsesCases\Commands\{ CancelAttendeeTicket\CancelAttendeeTicketCommand, CancelAttendeeTicket\CancelAttendeeTicketHandler, }; -use App\Modules\EventManagement\Application\Ports\Driving\CommandBus\CommandBus; +use App\Modules\EventManagement\Application\Ports\Driving\CommandBus as CommandBusPort; use App\Modules\EventManagement\Application\Ports\Driven\DependencyInjection\ExternalDependencies; use CloudCreativity\Modules\Application\Bus\CommandHandlerContainer; use CloudCreativity\Modules\Application\Bus\Middleware\ExecuteInUnitOfWork; use CloudCreativity\Modules\Application\Bus\Middleware\LogMessageDispatch; use CloudCreativity\Modules\Toolkit\Pipeline\PipeContainer; -final class CommandBusAdapterProvider +final class CommandBusProvider { public function __construct( private readonly ExternalDependencies $dependencies, ) { } - public function getCommandBus(): CommandBus + public function getCommandBus(): CommandBusPort { - $bus = new CommandBusAdapter( + $bus = new CommandBus( handlers: $handlers = new CommandHandlerContainer(), middleware: $middleware = new PipeContainer(), ); @@ -222,15 +221,15 @@ final class CommandBusAdapterProvider } ``` -As the presentation and delivery layer is the user of the driving ports, we can now bind the port and its adapter into a -service container. For example, in Laravel: +Adapters in the presentation and delivery layer will use the driving ports. Typically this means we need to bind the +port into a service container. For example, in Laravel: ```php namespace App\Providers; use App\Modules\EventManagement\Application\{ - Adapters\CommandBus\CommandBusAdapterProvider, - Ports\Driving\CommandBus\CommandBus, + Bus\CommandBusProvider, + Ports\Driving\CommandBus, }; use Illuminate\Contracts\Container\Container; use Illuminate\Support\ServiceProvider; @@ -242,13 +241,12 @@ final class EventManagementServiceProvider extends ServiceProvider $this->app->bind( CommandBus::class, static function (Container $app) { - $provider = $app->make(CommandBusAdapterProvider::class); + $provider = $app->make(CommandBusProvider::class); return $provider->getCommandBus(); }, ); } } - ``` ### Dispatching Commands @@ -260,8 +258,8 @@ a single action controller to handle a HTTP request in a Laravel application, we namespace App\Http\Controllers\Api\Attendees; use App\Modules\EventManagement\Application\{ - Ports\Driving\CommandBus\CommandBus, - UsesCases\Commands\CancelAttendeeTicket\CancelAttendeeTicketCommand, + Ports\Driving\CommandBus, + UseCases\Commands\CancelAttendeeTicket\CancelAttendeeTicketCommand, }; use CloudCreativity\Modules\Toolkit\Identifiers\IntegerId; use Illuminate\Validation\Rule; @@ -322,8 +320,8 @@ updated to return a `202 Accepted` response to indicate the command has been que namespace App\Http\Controllers\Api\Attendees; use App\Modules\EventManagement\Application\{ - Ports\Driving\CommandBus\CommandBus, - UsesCases\Commands\CancelAttendeeTicket\CancelAttendeeTicketCommand, + Ports\Driving\CommandBus, + UseCases\Commands\CancelAttendeeTicket\CancelAttendeeTicketCommand, }; use CloudCreativity\Modules\Toolkit\Identifiers\IntegerId; use Illuminate\Validation\Rule; @@ -573,7 +571,7 @@ You can write your own middleware to suit your specific needs. Middleware is a s following signature: ```php -namespace App\Modules\EventManagement\Application\Adapters\Middleware; +namespace App\Modules\EventManagement\Application\Bus\Middleware; use Closure; use CloudCreativity\Modules\Contracts\Application\Bus\CommandMiddleware; @@ -615,7 +613,7 @@ If you want to write middleware that can be used with both commands and queries, instead: ```php -namespace App\Modules\EventManagement\Application\Adapters\Middleware; +namespace App\Modules\EventManagement\Application\Bus\Middleware; use Closure; use CloudCreativity\Modules\Contracts\Application\Bus\BusMiddleware; diff --git a/docs/guide/application/domain-events.md b/docs/guide/application/domain-events.md index 283a947..d847065 100644 --- a/docs/guide/application/domain-events.md +++ b/docs/guide/application/domain-events.md @@ -169,9 +169,9 @@ Although this sounds like a lot of work, we provide the tools to make this easy. above: ```php -namespace App\Modules\EventManagement\Application\Adapters\CommandBus; +namespace App\Modules\EventManagement\Application\Bus; -use App\Modules\EventManagement\Application\Ports\Driving\CommandBus\CommandBus; +use App\Modules\EventManagement\Application\Ports\Driving\CommandBus; use App\Modules\EventManagement\Application\Ports\Driven\DependencyInjection\ExternalDependencies; use App\Modules\EventManagement\Application\Internal\DomainEvents\DomainEventDispatcher; use App\Modules\EventManagement\Application\Internal\DomainEvents\DomainEventDispatcherProvider; @@ -182,7 +182,7 @@ use CloudCreativity\Modules\Application\Bus\Middleware\SetupBeforeDispatch; use CloudCreativity\Modules\Application\UnitOfWork\UnitOfWorkManager; use CloudCreativity\Modules\Toolkit\Pipeline\PipeContainer; -final class CommandBusAdapterProvider +final class CommandBusProvider { /** * @var UnitOfWorkManager|null @@ -202,7 +202,7 @@ final class CommandBusAdapterProvider public function getCommandBus(): CommandBus { - $bus = new CommandBusAdapter( + $bus = new CommandBus( handlers: $handlers = new CommandHandlerContainer(), middleware: $middleware = new PipeContainer(), ); @@ -407,9 +407,9 @@ into the middleware that flushes deferred events. Here's an example: ```php -namespace App\Modules\EventManagement\Application\Adapters\CommandBus; +namespace App\Modules\EventManagement\Application\Bus; -use App\Modules\EventManagement\Application\Ports\Driving\CommandBus\CommandBus; +use App\Modules\EventManagement\Application\Ports\Driving\CommandBus as CommandBusPort; use App\Modules\EventManagement\Application\Ports\Driven\DependencyInjection\ExternalDependencies; use App\Modules\EventManagement\Application\Internal\DomainEvents\DomainEventDispatcher; use App\Modules\EventManagement\Application\Internal\DomainEvents\DomainEventDispatcherProvider; @@ -419,7 +419,7 @@ use CloudCreativity\Modules\Application\Bus\Middleware\FlushDeferredEvents; use CloudCreativity\Modules\Application\Bus\Middleware\SetupBeforeDispatch; use CloudCreativity\Modules\Toolkit\Pipeline\PipeContainer; -final class CommandBusAdapterProvider +final class CommandBusProvider { /** * @var DomainEventDispatcher|null @@ -432,9 +432,9 @@ final class CommandBusAdapterProvider ) { } - public function getCommandBus(): CommandBus + public function getCommandBus(): CommandBusPort { - $bus = new CommandBusAdapter( + $bus = new CommandBus( handlers: $handlers = new CommandHandlerContainer(), middleware: $middleware = new PipeContainer(), ); diff --git a/docs/guide/application/integration-events.md b/docs/guide/application/integration-events.md index 28e07e1..28031a3 100644 --- a/docs/guide/application/integration-events.md +++ b/docs/guide/application/integration-events.md @@ -12,8 +12,8 @@ and any consuming bounded contexts. Integration events are bidirectional. They are both _published_ by a bounded context, and _consumed_ by other bounded contexts. This means we can refer to them in terms of their direction - specifically: -- **Inbound** integration events, are those a bounded context _consumes_ via a driving port and an adapter - implementation within the application layer. +- **Inbound** integration events, are those a bounded context _consumes_ via a driving port that is implemented by a + service in the application layer. - **Outbound** integration events, are those _published_ by a bounded context. Publishing occurs via a driven port, with the infrastructure layer implementing the adapter. @@ -401,7 +401,7 @@ needs to expose its _specific_ inbound event bus. We do this by defining an interface in our application's driving ports: ```php -namespace App\Modules\EventManagement\Application\Ports\Driving\InboundEventBus; +namespace App\Modules\EventManagement\Application\Ports\Driving; use CloudCreativity\Modules\Contracts\Application\Ports\Driving\InboundEvents\EventDispatcher; @@ -410,24 +410,23 @@ interface InboundEventBus extends EventDispatcher } ``` -And then our adapter (the concrete implementation of the port) is as follows: +And then our implementation is as follows: ```php -namespace App\Modules\EventManagement\Application\Adapters\InboundEventBus; +namespace App\Modules\EventManagement\Application\Bus; -use App\Modules\EventManagement\Application\Ports\Driving\InboundEventBus\InboundEventBus; +use App\Modules\EventManagement\Application\Ports\Driving\InboundEventBus as Port; use CloudCreativity\Modules\Application\InboundEventBus\EventDispatcher; -final class InboundEventBusAdapter extends EventDispatcher implements - InboundEventBus +final class InboundEventBus extends EventDispatcher implements Port { } ``` ### Creating a Bus -The event dispatcher class that your adapter extended (in the above example) allows you to build an inbound event bus -specific to your domain. You do this by: +The event dispatcher class that your implementation extends (in the above example) allows you to build an inbound event +bus specific to your domain. You do this by: 1. Binding event handler factories into the event dispatcher; and 2. Binding factories for any middleware used by your bounded context; and @@ -439,11 +438,11 @@ or middleware are actually being used. For example: ```php -namespace App\Modules\EventManagement\Application\Adapters\InboundEventBus; +namespace App\Modules\EventManagement\Application\Bus; -use App\Modules\EventManagement\Application\Adapters\CommandBus\CommandBusAdapterProvider; +use App\Modules\EventManagement\Application\Bus\CommandBusProvider; use App\Modules\EventManagement\Application\UsesCases\InboundEvents\OrderWasFulfilledHandler; -use App\Modules\EventManagement\Application\Ports\Driving\InboundEventBus\InboundEventBus; +use App\Modules\EventManagement\Application\Ports\Driving\InboundEventBus as InboundEventBusPort; use App\Modules\EventManagement\Application\Ports\Driven\DependencyInjection\ExternalDependencies; use CloudCreativity\Modules\Application\InboundEventBus\EventHandlerContainer; use CloudCreativity\Modules\Application\InboundEventBus\Middleware\HandleInUnitOfWork; @@ -451,17 +450,17 @@ use CloudCreativity\Modules\Application\InboundEventBus\Middleware\LogInboundEve use CloudCreativity\Modules\Toolkit\Pipeline\PipeContainer; use VendorName\Ordering\Shared\IntegrationEvents\V1\OrderWasFulfilled; -final class InboundEventBusAdapterProvider +final class InboundEventBusProvider { public function __construct( - private readonly CommandBusAdapterProvider $commandBusProvider, + private readonly CommandBusProvider $commandBusProvider, private readonly ExternalDependencies $dependencies, ) { } - public function getEventBus(): InboundEventBus + public function getEventBus(): InboundEventBusPort { - $bus = new InboundEventBusAdapter( + $bus = new InboundEventBus( handlers: $handlers = new EventHandlerContainer(), middleware: $middleware = new PipeContainer(), ); @@ -498,15 +497,15 @@ final class InboundEventBusAdapterProvider ``` Inbound events are received by the presentation and delivery layer of your application. For example, a controller that -receives a push message from Google Cloud Pub/Sub. We therefore need to bind the driving port and its adapter into a +receives a push message from Google Cloud Pub/Sub. Typically this means we need to bind the driving port into a service container. For example, in Laravel: ```php namespace App\Providers; use App\Modules\EventManagement\Application\{ - Adapters\InboundEventBus\InboundEventBusAdapterProvider, - Ports\Driving\InboundEvents\InboundEventBus, + Bus\InboundEventBusProvider, + Ports\Driving\InboundEventBus, }; use Illuminate\Contracts\Container\Container; use Illuminate\Support\ServiceProvider; @@ -518,7 +517,7 @@ final class EventManagementServiceProvider extends ServiceProvider $this->app->bind( InboundEventBus::class, static function (Container $app) { - $provider = $app->make(InboundEventBusAdapterProvider::class); + $provider = $app->make(InboundEventBusProvider::class); return $provider->getEventBus(); }, ); @@ -532,7 +531,7 @@ Integration events published by other bounded contexts will arrive in your prese a controller for an endpoint that Google Cloud Pub/Sub pushes events to. The implementation pattern here is to deserialize the incoming event data, converting it to the defined integration -event message. Then this is pushed into your bounded context via its event bus interface - i.e. the entry point for +event message. Then this is pushed into your bounded context via its inbound event bus port - i.e. the entry point for the bounded context. Here is an example controller from a Laravel application to demonstrate the pattern: @@ -540,7 +539,7 @@ Here is an example controller from a Laravel application to demonstrate the patt ```php namespace App\Http\Controllers\Api\PubSub; -use App\Modules\EventManagement\Application\Ports\Driving\InboundEvents\InboundEventBus; +use App\Modules\EventManagement\Application\Ports\Driving\InboundEventBus; use CloudCreativity\Modules\Contracts\Application\Messages\IntegrationEvent; use VendorName\Ordering\Shared\IntegrationEvents\V1\Serializers\JsonSerializer; @@ -594,7 +593,7 @@ the `SwallowInboundEvent` handler for this purpose: use CloudCreativity\Modules\Application\InboundEventBus\EventHandlerContainer; use CloudCreativity\Modules\Application\InboundEventBus\SwallowInboundEvent; -$bus = new InboundEventBusAdapter( +$bus = new InboundEventBus( handlers: $handlers = new EventHandlerContainer( default: fn() => new SwallowInboundEvent(), ), @@ -610,7 +609,7 @@ use CloudCreativity\Modules\Application\InboundEventBus\EventHandlerContainer; use CloudCreativity\Modules\Application\InboundEventBus\SwallowInboundEvent; use Psr\Log\LogLevel; -$bus = new InboundEventBusAdapter( +$bus = new InboundEventBus( handlers: $handlers = new EventHandlerContainer( default: fn() => new SwallowInboundEvent( logger: $this->dependencies->getLogger(), @@ -647,7 +646,7 @@ Firstly, our application layer will need an inbox driving port. This will allow example: ```php -namespace App\Modules\EventManagement\Application\Ports\Driving\InboundEvents; +namespace App\Modules\EventManagement\Application\Ports\Driving; use CloudCreativity\Modules\Contracts\Application\Messages\IntegrationEvent; @@ -657,7 +656,7 @@ interface Inbox } ``` -The adapter implementation would then check if the event has been received before, and if not, persist the event in the +The implementation would then check if the event has been received before, and if not, persist the event in the inbox. For both these actions - checking whether it exists, and storing - the adapter will need a driven port. That might look like this: @@ -887,7 +886,7 @@ You can write your own middleware to suit your specific needs. Middleware is a s following signature: ```php -namespace App\Modules\EventManagement\Application\Adapters\Middleware; +namespace App\Modules\EventManagement\Application\Bus\Middleware; use Closure; use CloudCreativity\Modules\Contracts\Application\InboundEventBus\InboundEventMiddleware; diff --git a/docs/guide/application/queries.md b/docs/guide/application/queries.md index 130f1ba..c0ca66c 100644 --- a/docs/guide/application/queries.md +++ b/docs/guide/application/queries.md @@ -104,7 +104,7 @@ Although there is a _generic_ query bus interface, our bounded context needs to We do this by defining an interface in our application's driving ports: ```php -namespace App\Modules\EventManagement\Application\Ports\Driving\QueryBus; +namespace App\Modules\EventManagement\Application\Ports\Driving; use CloudCreativity\Modules\Contracts\Application\Ports\Driving\Queries\QueryDispatcher; @@ -113,24 +113,23 @@ interface QueryBus extends QueryDispatcher } ``` -And then our adapter (the concrete implementation of the port) is as follows: +And then our implementation is as follows: ```php -namespace App\Modules\EventManagement\Application\Adapters\QueryBus; +namespace App\Modules\EventManagement\Application\Bus; -use App\Modules\EventManagement\Application\Ports\Driving\QueryBus\QueryBus; +use App\Modules\EventManagement\Application\Ports\Driving\QueryBus as Port; use CloudCreativity\Modules\Application\Bus\QueryDispatcher; -final class EventManagementQueryBus extends QueryDispatcher implements - QueryBus +final class QueryBus extends QueryDispatcher implements Port { } ``` ### Creating a Query Bus -The query dispatcher class that your adapter extended (in the above example) allows you to build a query bus specific to -your domain. You do this by: +The query dispatcher class that your implementation extends (in the above example) allows you to build a query bus +specific to your domain. You do this by: 1. Binding query handler factories into the query dispatcher; and 2. Binding factories for any middleware used by your bounded context; and @@ -142,28 +141,28 @@ handler or middleware are actually being used. For example: ```php -namespace App\Modules\EventManagement\Application\Adapters\QueryBus; +namespace App\Modules\EventManagement\Application\Bus; use App\Modules\EventManagement\Application\UseCases\Queries\{ GetAttendeeTickets\GetAttendeeTicketsQuery, GetAttendeeTickets\GetAttendeeTicketsHandler, }; -use App\Modules\EventManagement\Application\Ports\Driving\QueryBus\QueryBus; +use App\Modules\EventManagement\Application\Ports\Driving\QueryBus as QueryBusPort; use App\Modules\EventManagement\Application\Ports\Driven\DependencyInjection\ExternalDependencies; use CloudCreativity\Modules\Application\Bus\QueryHandlerContainer; use CloudCreativity\Modules\Application\Bus\Middleware\LogMessageDispatch; use CloudCreativity\Modules\Toolkit\Pipeline\PipeContainer; -final class QueryBusAdapterProvider +final class QueryBusProvider { public function __construct( private readonly ExternalDependencies $dependencies, ) { } - public function getQueryBus(): QueryBus + public function getQueryBus(): QueryBusPort { - $bus = new EventManagementQueryBus( + $bus = new QueryBus( handlers: $handlers = new QueryHandlerContainer(), middleware: $middleware = new PipeContainer(), ); @@ -194,15 +193,14 @@ final class QueryBusAdapterProvider } ``` -As the presentation and delivery layer is the user of the driving ports, we can now bind the port and its adapter into a -service container. For example, in Laravel: +Adapters in the presentation and delivery layer will use the driving ports. Typically this means we need to bind the port into a service container. For example, in Laravel: ```php namespace App\Providers; use App\Modules\EventManagement\Application\{ - Adapters\QueryBus\QueryBusAdapterProvider, - Ports\Driving\QueryBus\QueryBus, + Bus\QueryBusProvider, + Ports\Driving\QueryBus, }; use Illuminate\Contracts\Container\Container; use Illuminate\Support\ServiceProvider; @@ -214,7 +212,7 @@ final class EventManagementServiceProvider extends ServiceProvider $this->app->bind( QueryBus::class, static function (Container $app) { - $provider = $app->make(QueryBusAdapterProvider::class); + $provider = $app->make(QueryBusProvider::class); return $provider->getQueryBus(); }, ); @@ -399,7 +397,7 @@ You can write your own middleware to suit your specific needs. Middleware is a s following signature: ```php -namespace App\Modules\EventManagement\Application\Adapters\Middleware; +namespace App\Modules\EventManagement\Application\Bus\Middleware; use Closure; use CloudCreativity\Modules\Contracts\Application\Bus\QueryMiddleware; @@ -441,7 +439,7 @@ If you want to write middleware that can be used with both commands and queries, instead: ```php -namespace App\Modules\EventManagement\Application\Adapters\Middleware; +namespace App\Modules\EventManagement\Application\Bus\Middleware; use Closure; use CloudCreativity\Modules\Contracts\Application\Bus\BusMiddleware; diff --git a/docs/guide/application/units-of-work.md b/docs/guide/application/units-of-work.md index c3157bc..707ebf4 100644 --- a/docs/guide/application/units-of-work.md +++ b/docs/guide/application/units-of-work.md @@ -93,7 +93,7 @@ Given the above example, the correct order from the application perspective is: 1. Unit of work begins by starting a transaction. 2. The aggregate root state change occurs and the domain event is emitted by the aggregate. -3. The domain event dispatching is deferred until later in the unit of work. This means side-effects via event listeners +3. The domain event dispatching is deferred until later in the unit of work. This means side effects via event listeners will be triggered later. 4. The aggregate root is persisted via the repository port. Internally within the adapter this may result in multiple database writes, that are within the transaction. diff --git a/docs/guide/concepts/layers.md b/docs/guide/concepts/layers.md index 562f58b..724f516 100644 --- a/docs/guide/concepts/layers.md +++ b/docs/guide/concepts/layers.md @@ -35,15 +35,22 @@ this must never be exposed outside of the infrastructure layer. The application layer contains the use cases of the bounded context. These are the business processes that can be executed by passing information _into_ the application, and the information that can be read _out_ of the application. -This package embraces hexagonal architecture to define the boundary of the application layer. This boundary is expressed +This package embraces Hexagonal Architecture to define the boundary of the application layer. This boundary is expressed by _ports_ - interfaces that define the use cases of the module - and _adapters_ - the implementations of these interfaces. There are two types of ports: -- **Driving Ports** (aka _primary_ or _input_ ports) - interfaces that define the use cases of the bounded context. The - adapters that implement these interfaces are in the application layer and are used by the outside world to interact - with the module. +- **Driving Ports** (aka _primary_ or _input_ ports) - interfaces that define the use cases of the bounded context. + These are implemented by application services, and are used by adapters in the outside world to initiate interactions + with the application. For example, an adapter could be a HTTP controller that takes input from a request and passes it + to the application via a driving port. - **Driven Ports** (aka _secondary_ or _output_ ports) - interfaces that define the dependencies of the application - layer. The adapters that implement these interfaces are in the infrastructure layer. + layer. The adapters that implement these interfaces are in the infrastructure layer. For example, a persistence port + that has an adapter to read and write data to a database. + +:::tip +For a more detailed explanation of Hexagonal Architecture - along with some excellent diagrams - we +recommend [this article.](https://medium.com/ssense-tech/hexagonal-architecture-there-are-always-two-sides-to-every-story-bc0780ed7d9c) +::: When defining the driving ports in the application layer, we follow the Command Query Responsibility Segregation (CQRS) pattern. This pattern separates read (query) and write (command) operations, which makes it completely clear what is diff --git a/docs/guide/concepts/modularisation.md b/docs/guide/concepts/modularisation.md index c8645d3..7d4ee16 100644 --- a/docs/guide/concepts/modularisation.md +++ b/docs/guide/concepts/modularisation.md @@ -145,7 +145,7 @@ The application namespace can be structured as follows: - Queue - Persistence - ... - - Adapters + - Bus - CommandBus - QueryBus - InboundEventBus @@ -165,7 +165,7 @@ The namespaces shown here are as follows: - **Ports** - the driving and driven ports of the application layer expressed as interfaces. The driving ports are the interfaces that the application layer uses to interact with the outside world. The driven ports are the interfaces that the application layer expects to be implemented by the infrastructure layer. -- **Adapters** - contains the implementations of the driving ports. The concrete implementations are the command bus, +- **Bus** - contains the implementations of the driving ports. The concrete implementations are the command bus, query bus, and inbound event bus. Each bus ensures a message is dispatched to the correct handler. - **Use Cases** - the implementation of the business logic of the application layer. Use cases are expressed as the command and query messages that can enter the application, and the handlers that implement what happens when a diff --git a/docs/guide/infrastructure/dependency-injection.md b/docs/guide/infrastructure/dependency-injection.md index 544f774..9b2e10b 100644 --- a/docs/guide/infrastructure/dependency-injection.md +++ b/docs/guide/infrastructure/dependency-injection.md @@ -66,29 +66,29 @@ These external dependencies can then be type-hinted wherever the application lay creating a command bus: ```php -namespace App\Modules\EventManagement\Application\Adapters\CommandBus; +namespace App\Modules\EventManagement\Application\Bus; use App\Modules\EventManagement\Application\UsesCases\Commands\{ CancelAttendeeTicket\CancelAttendeeTicketCommand, CancelAttendeeTicket\CancelAttendeeTicketHandler, }; -use App\Modules\EventManagement\Application\Ports\Driving\CommandBus\CommandBus; +use App\Modules\EventManagement\Application\Ports\Driving\CommandBus as CommandBusPort; use App\Modules\EventManagement\Application\Ports\Driven\DependencyInjection\ExternalDependencies; use CloudCreativity\Modules\Application\Bus\CommandHandlerContainer; use CloudCreativity\Modules\Application\Bus\Middleware\ExecuteInUnitOfWork; use CloudCreativity\Modules\Application\Bus\Middleware\LogMessageDispatch; use CloudCreativity\Modules\Toolkit\Pipeline\PipeContainer; -final class CommandBusAdapterProvider +final class CommandBusProvider { public function __construct( private readonly ExternalDependencies $dependencies, ) { } - public function getCommandBus(): CommandBus + public function getCommandBus(): CommandBusPort { - $bus = new CommandBusAdapter( + $bus = new CommandBus( handlers: $handlers = new CommandHandlerContainer(), middleware: $middleware = new PipeContainer(), ); diff --git a/docs/guide/infrastructure/queues.md b/docs/guide/infrastructure/queues.md index 0c5e331..884f9d1 100644 --- a/docs/guide/infrastructure/queues.md +++ b/docs/guide/infrastructure/queues.md @@ -28,7 +28,7 @@ This port is injected into a command bus via a closure factory that ensures the lazy. For example: ```php -$bus = new CommandBusAdapter( +$bus = new CommandBus( handlers: $handlers = new CommandHandlerContainer(), middleware: $middleware = new PipeContainer(), queue: fn() => $this->dependencies->getQueue(), @@ -65,7 +65,7 @@ interface InternalQueue extends Port And then ensure the adapter of this internal port is injected into your internal command bus: ```php -$bus = new InternalCommandBusAdapter( +$bus = new InternalCommandBus( handlers: $handlers = new CommandHandlerContainer(), middleware: $middleware = new PipeContainer(), queue: fn() => $this->dependencies->getInternalQueue(), diff --git a/docs/guide/upgrade.md b/docs/guide/upgrade.md index bbd064d..ff08626 100644 --- a/docs/guide/upgrade.md +++ b/docs/guide/upgrade.md @@ -27,7 +27,7 @@ While the `1.x` version was good, the main problem it had was the relationship b infrastructure layers. The layering of domain, infrastructure then application did not quite work - it always felt like the right relationship was domain, application and then infrastructure as an external concern. -We have solved this problem by switching to _hexagonal architecture_. +We have solved this problem by switching to _Hexagonal Architecture_. The domain layer remains the core of your bounded context's implementation. This is wrapped by the application layer, i.e. the infrastructure layer is no longer between the domain and the application layers. @@ -36,17 +36,19 @@ Instead, the application layer has a clearly defined boundary. This boundary is define the use cases of the module - and _adapters_ - the implementations of these interfaces. There are two types of ports: -- **Driving Ports** (aka _primary_ or _input_ ports) - interfaces that define the use cases of the bounded context. The - adapters that implement these interfaces are in the application layer and are used by the outside world to interact - with the module. +- **Driving Ports** (aka _primary_ or _input_ ports) - interfaces that define the use cases of the bounded context. + These are implemented by application services, and are used by adapters in the outside world to initiate interactions + with the application. For example, an adapter could be a HTTP controller that takes input from a request and passes it + to the application via a driving port. - **Driven Ports** (aka _secondary_ or _output_ ports) - interfaces that define the dependencies of the application - layer. The adapters that implement these interfaces are in the infrastructure layer. + layer. The adapters that implement these interfaces are in the infrastructure layer. For example, a persistence port + that has an adapter to read and write data to a database. The _driving ports_ in this package continue to use the CQRS pattern. So they are your command bus and query bus, plus inbound integration events via an inbound event bus. The _driven ports_ define the boundary between the application and infrastructure layer. This uses a _dependency -inversion_ principle. The application layer defines the port as an interface, which is then implemented by the adapter +inversion_ principle. The application layer defines the port as an interface, which is then implemented by an adapter in the infrastructure layer. #### Interface Changes From 4648b4e2d366a91b772357da9287a7572934e7b6 Mon Sep 17 00:00:00 2001 From: Christopher Gammie Date: Tue, 3 Dec 2024 19:10:49 +0000 Subject: [PATCH 7/8] refactor!: simplify driving and driven port namespaces --- CHANGELOG.md | 5 +++++ docs/guide/application/asynchronous-processing.md | 4 ++-- docs/guide/application/commands.md | 2 +- docs/guide/application/integration-events.md | 12 ++++++------ docs/guide/application/queries.md | 2 +- docs/guide/application/units-of-work.md | 2 +- docs/guide/infrastructure/dependency-injection.md | 4 ++-- docs/guide/infrastructure/exception-reporting.md | 4 ++-- docs/guide/infrastructure/outbox.md | 2 +- docs/guide/infrastructure/publishing-events.md | 4 ++-- docs/guide/infrastructure/queues.md | 8 ++++---- docs/guide/upgrade.md | 6 +++--- src/Application/Bus/CommandDispatcher.php | 4 ++-- src/Application/Bus/QueryDispatcher.php | 2 +- ...ventDispatcher.php => InboundEventDispatcher.php} | 4 ++-- src/Application/UnitOfWork/UnitOfWorkManager.php | 4 ++-- .../Driven/{Exceptions => }/ExceptionReporter.php | 2 +- ...EventPublisher.php => OutboundEventPublisher.php} | 4 ++-- .../Application/Ports/Driven/{Queue => }/Queue.php | 2 +- .../Ports/Driven/{UnitOfWork => }/UnitOfWork.php | 2 +- .../Driving/{Commands => }/CommandDispatcher.php | 2 +- ...ventDispatcher.php => InboundEventDispatcher.php} | 4 ++-- .../Ports/Driving/{Queries => }/QueryDispatcher.php | 2 +- .../OutboundEventBus/ClosurePublisher.php | 4 ++-- .../OutboundEventBus/ComponentPublisher.php | 4 ++-- src/Infrastructure/Queue/ClosureQueue.php | 2 +- src/Infrastructure/Queue/ComponentQueue.php | 2 +- tests/Unit/Application/Bus/CommandDispatcherTest.php | 2 +- ...atcherTest.php => InboundEventDispatcherTest.php} | 10 +++++----- .../Application/UnitOfWork/UnitOfWorkManagerTest.php | 4 ++-- 30 files changed, 60 insertions(+), 55 deletions(-) rename src/Application/InboundEventBus/{EventDispatcher.php => InboundEventDispatcher.php} (95%) rename src/Contracts/Application/Ports/Driven/{Exceptions => }/ExceptionReporter.php (96%) rename src/Contracts/Application/Ports/Driven/{OutboundEventBus/EventPublisher.php => OutboundEventPublisher.php} (92%) rename src/Contracts/Application/Ports/Driven/{Queue => }/Queue.php (97%) rename src/Contracts/Application/Ports/Driven/{UnitOfWork => }/UnitOfWork.php (97%) rename src/Contracts/Application/Ports/Driving/{Commands => }/CommandDispatcher.php (98%) rename src/Contracts/Application/Ports/Driving/{InboundEvents/EventDispatcher.php => InboundEventDispatcher.php} (92%) rename src/Contracts/Application/Ports/Driving/{Queries => }/QueryDispatcher.php (97%) rename tests/Unit/Application/InboundEventBus/{EventDispatcherTest.php => InboundEventDispatcherTest.php} (94%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e2105d..038599b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ All notable changes to this project will be documented in this file. This projec ### Changed +- **BREAKING** Removed the sub-namespaces for ports provided by this package, i.e.: + - `Contracts\Application\Ports\Driven` all interfaces are no longer in sub-namespaces; and + - `Contracts\Application\Ports\Driven` also has the same change. +- **BREAKING** Renamed the `InboundEventBus\EventDispatcher` port to `InboundEventDispatcher`. +- **BREAKING** Renamed the `OutboundEventBus\EventPublisher` port to `OutboundEventPublisher`. - Upgraded to PHPStan v2. ## [2.0.0-rc.3] - 2024-10-13 diff --git a/docs/guide/application/asynchronous-processing.md b/docs/guide/application/asynchronous-processing.md index 039deff..587ae24 100644 --- a/docs/guide/application/asynchronous-processing.md +++ b/docs/guide/application/asynchronous-processing.md @@ -47,7 +47,7 @@ For example, an endpoint that triggers a recalculation of our sales report: namespace App\Http\Controllers\Api\AttendanceReport; use App\Modules\EventManagement\Application\{ - Ports\Driving\Commands\CommandBus, + Ports\Driving\CommandBus, UsesCases\Commands\RecalculateSalesAtEvent\RecalculateSalesAtEventCommand, }; use CloudCreativity\Modules\Toolkit\Identifiers\IntegerId; @@ -221,7 +221,7 @@ public commands. I.e.: ```php namespace App\Modules\EventManagement\Application\Ports\Driven\Queue; -use CloudCreativity\Modules\Contracts\Application\Ports\Driven\Queue\Queue as Port; +use CloudCreativity\Modules\Contracts\Application\Ports\Driven\Queue as Port; // queues public commands interface Queue extends Port diff --git a/docs/guide/application/commands.md b/docs/guide/application/commands.md index fd476ba..6152796 100644 --- a/docs/guide/application/commands.md +++ b/docs/guide/application/commands.md @@ -128,7 +128,7 @@ We do this by defining an interface in our application's driving ports. ```php namespace App\Modules\EventManagement\Application\Ports\Driving; -use CloudCreativity\Modules\Application\Ports\Driving\CommandBus\CommandDispatcher; +use CloudCreativity\Modules\Application\Ports\Driving\CommandDispatcher; interface CommandBus extends CommandDispatcher { diff --git a/docs/guide/application/integration-events.md b/docs/guide/application/integration-events.md index 28031a3..c74f845 100644 --- a/docs/guide/application/integration-events.md +++ b/docs/guide/application/integration-events.md @@ -151,9 +151,9 @@ Your application layer should define the driven port: ```php namespace App\Modules\EventManagement\Application\Ports\Driven\OutboundEventBus; -use CloudCreativity\Modules\Contracts\Application\Ports\Driven\OutboundEventBus\EventPublisher; +use CloudCreativity\Modules\Contracts\Application\Ports\Driven\OutboundEventPublisher; -interface OutboundEventBus extends EventPublisher +interface OutboundEventBus extends OutboundEventPublisher { } ``` @@ -403,9 +403,9 @@ We do this by defining an interface in our application's driving ports: ```php namespace App\Modules\EventManagement\Application\Ports\Driving; -use CloudCreativity\Modules\Contracts\Application\Ports\Driving\InboundEvents\EventDispatcher; +use CloudCreativity\Modules\Contracts\Application\Ports\Driving\InboundEventDispatcher; -interface InboundEventBus extends EventDispatcher +interface InboundEventBus extends InboundEventDispatcher { } ``` @@ -416,9 +416,9 @@ And then our implementation is as follows: namespace App\Modules\EventManagement\Application\Bus; use App\Modules\EventManagement\Application\Ports\Driving\InboundEventBus as Port; -use CloudCreativity\Modules\Application\InboundEventBus\EventDispatcher; +use CloudCreativity\Modules\Application\InboundEventBus\InboundEventDispatcher; -final class InboundEventBus extends EventDispatcher implements Port +final class InboundEventBus extends InboundEventDispatcher implements Port { } ``` diff --git a/docs/guide/application/queries.md b/docs/guide/application/queries.md index c0ca66c..2171e56 100644 --- a/docs/guide/application/queries.md +++ b/docs/guide/application/queries.md @@ -106,7 +106,7 @@ We do this by defining an interface in our application's driving ports: ```php namespace App\Modules\EventManagement\Application\Ports\Driving; -use CloudCreativity\Modules\Contracts\Application\Ports\Driving\Queries\QueryDispatcher; +use CloudCreativity\Modules\Contracts\Application\Ports\Driving\QueryDispatcher; interface QueryBus extends QueryDispatcher { diff --git a/docs/guide/application/units-of-work.md b/docs/guide/application/units-of-work.md index 707ebf4..4e1449b 100644 --- a/docs/guide/application/units-of-work.md +++ b/docs/guide/application/units-of-work.md @@ -189,7 +189,7 @@ implementation for Laravel could look like this: namespace App\Modules\Shared\Infrastructure; use Closure; -use CloudCreativity\Modules\Contracts\Application\Ports\Driven\UnitOfWork\UnitOfWork; +use CloudCreativity\Modules\Contracts\Application\Ports\Driven\UnitOfWork; use Illuminate\Database\ConnectionInterface; final readonly class IlluminateUnitOfWork implements UnitOfWork diff --git a/docs/guide/infrastructure/dependency-injection.md b/docs/guide/infrastructure/dependency-injection.md index 9b2e10b..2491935 100644 --- a/docs/guide/infrastructure/dependency-injection.md +++ b/docs/guide/infrastructure/dependency-injection.md @@ -47,7 +47,7 @@ This external dependencies port in effect provides other driven ports. For examp namespace App\Modules\EventManagement\Application\Ports\Driven\DependencyInjection; use App\Modules\EventManagement\Application\Ports\Driven\Persistence\AttendeeRepository; -use App\Modules\EventManagement\Application\Ports\Driven\Queue\Queue; +use App\Modules\EventManagement\Application\Ports\Driven\Queue; use Psr\Log\LoggerInterface; interface ExternalDependencies @@ -131,7 +131,7 @@ on a `RepositoryProvider` interface, that can be accessed via the external depen namespace App\Modules\EventManagement\Application\Ports\Driven\DependencyInjection; use App\Modules\EventManagement\Application\Ports\Driven\Persistence\RepositoryProvider; -use App\Modules\EventManagement\Application\Ports\Driven\Queue\Queue; +use App\Modules\EventManagement\Application\Ports\Driven\Queue; use Psr\Log\LoggerInterface; interface ExternalDependencies diff --git a/docs/guide/infrastructure/exception-reporting.md b/docs/guide/infrastructure/exception-reporting.md index ebb4b8c..d869d3f 100644 --- a/docs/guide/infrastructure/exception-reporting.md +++ b/docs/guide/infrastructure/exception-reporting.md @@ -59,7 +59,7 @@ try { This package provides a driven port in the application layer that allows that layer to report exceptions: ```php -namespace CloudCreativity\Modules\Application\Ports\Driven\Exceptions; +namespace CloudCreativity\Modules\Application\Ports\Driven; use Throwable; @@ -86,7 +86,7 @@ implementation looks like this: ```php namespace App\Modules\Shared\Infrastructure\Exceptions; -use CloudCreativity\Modules\Contracts\Application\Ports\Driven\Exceptions\ExceptionReporter; +use CloudCreativity\Modules\Contracts\Application\Ports\Driven\ExceptionReporter; use Illuminate\Contracts\Debug\ExceptionHandler; use Throwable; diff --git a/docs/guide/infrastructure/outbox.md b/docs/guide/infrastructure/outbox.md index 10802ee..c0f65f0 100644 --- a/docs/guide/infrastructure/outbox.md +++ b/docs/guide/infrastructure/outbox.md @@ -126,7 +126,7 @@ port `Queue` - as suggested by the [Queues chapter](./queues) - call it `Outbox` ```php namespace App\Modules\EventManagement\Application\Ports\Driven\Queue; -use CloudCreativity\Modules\Contracts\Application\Ports\Driven\Queue\Queue; +use CloudCreativity\Modules\Contracts\Application\Ports\Driven\Queue; interface Outbox extends Queue { diff --git a/docs/guide/infrastructure/publishing-events.md b/docs/guide/infrastructure/publishing-events.md index c372962..12e772f 100644 --- a/docs/guide/infrastructure/publishing-events.md +++ b/docs/guide/infrastructure/publishing-events.md @@ -16,9 +16,9 @@ The following is an example port: ```php namespace App\Modules\EventManagement\Application\Ports\Driven\OutboundEventBus; -use CloudCreativity\Modules\Contracts\Application\Ports\Driven\OutboundEventBus\EventPublisher; +use CloudCreativity\Modules\Contracts\Application\Ports\Driven\OutboundEventPublisher; -interface OutboundEventBus extends EventPublisher +interface OutboundEventBus extends OutboundEventPublisher { } ``` diff --git a/docs/guide/infrastructure/queues.md b/docs/guide/infrastructure/queues.md index 884f9d1..d8666a9 100644 --- a/docs/guide/infrastructure/queues.md +++ b/docs/guide/infrastructure/queues.md @@ -17,7 +17,7 @@ We do this by defining an interface in our application's driven ports: ```php namespace App\Modules\EventManagement\Application\Ports\Driven\Queue; -use CloudCreativity\Modules\Contracts\Application\Ports\Driven\Queue\Queue as Port; +use CloudCreativity\Modules\Contracts\Application\Ports\Driven\Queue as Port; interface Queue extends Port { @@ -55,7 +55,7 @@ In this scenario, define another driven port in your application layer: ```php namespace App\Modules\EventManagement\Application\Ports\Driven\Queue; -use CloudCreativity\Modules\Contracts\Application\Ports\Driven\Queue\Queue as Port; +use CloudCreativity\Modules\Contracts\Application\Ports\Driven\Queue as Port; interface InternalQueue extends Port { @@ -299,7 +299,7 @@ For example, a default Laravel job for queuing and dispatching commands would be ```php namespace App\Modules\EventManagement\Infrastructure\Queue; -use App\Modules\EventManagement\Application\Ports\Driving\Commands\CommandBus; +use App\Modules\EventManagement\Application\Ports\Driving\CommandBus; use CloudCreativity\Modules\Contracts\Application\Messages\Command; use CloudCreativity\Modules\Toolkit\Result\FailedResultException; use Illuminate\Bus\Queueable; @@ -340,7 +340,7 @@ An example of a queue job for a specific command might be: ```php namespace App\Modules\EventManagement\Infrastructure\Queue; -use App\Modules\EventManagement\Application\Ports\Driving\Commands\CommandBus; +use App\Modules\EventManagement\Application\Ports\Driving\CommandBus; use App\Modules\EventManagement\Application\UseCases\Commands\{ RecalculateSalesAtEvent\ErrorCodeEnum, RecalculateSalesAtEvent\RecalculateSalesAtEventCommand, diff --git a/docs/guide/upgrade.md b/docs/guide/upgrade.md index ff08626..5e9e4e3 100644 --- a/docs/guide/upgrade.md +++ b/docs/guide/upgrade.md @@ -73,7 +73,7 @@ For example, `EntityTrait` is now `IsEntity`. Command messages must now implement the `Contracts\Application\Messages\Command` interface. -The command dispatcher interface is now `Contracts\Application\Ports\Driving\Commands\CommandDispatcher`. +The command dispatcher interface is now `Contracts\Application\Ports\Driving\CommandDispatcher`. The concrete implementation has been moved from `Bus` to `Application\Bus`. The constructor argument for the middleware pipe container has been renamed `middleware` for clarity. This will only affect your implementation if you are using @@ -87,7 +87,7 @@ the `Application\Bus\Middleware` namespace. Query messages must now implement the `Contracts\Application\Messages\Query` interface. -The query dispatcher interface is now `Contracts\Application\Ports\Driving\Queries\QueryDispatcher`. +The query dispatcher interface is now `Contracts\Application\Ports\Driving\QueryDispatcher`. The concrete implementation has been moved from `Bus` to `Application\Bus`. The constructor argument for the middleware pipe container has been renamed `middleware` for clarity. This will only affect your implementation if you are using @@ -106,7 +106,7 @@ The previous event bus implementation has been split in two. This is due to the inbound events is now a _driving port_, whereas publishing outbound events occurs via a _driven port_. The new inbound implementation (previously referred to as a _notifier_) is now in the `Application\InboundEventBus` -namespace. The driving port is `Contracts\Application\Ports\Driving\InboundEvents\EventDispatcher`. +namespace. The driving port is `Contracts\Application\Ports\Driving\EventDispatcher`. The new outbound implementation (referred to as a _publisher_) is now in the `Infrastructure\OutboundEventBus` namespace. The driven port is `Contracts\Application\Ports\Driven\OutboundEvents\EventPublisher`. diff --git a/src/Application/Bus/CommandDispatcher.php b/src/Application/Bus/CommandDispatcher.php index 723c16c..0997f18 100644 --- a/src/Application/Bus/CommandDispatcher.php +++ b/src/Application/Bus/CommandDispatcher.php @@ -15,8 +15,8 @@ use Closure; use CloudCreativity\Modules\Contracts\Application\Bus\CommandHandlerContainer; use CloudCreativity\Modules\Contracts\Application\Messages\Command; -use CloudCreativity\Modules\Contracts\Application\Ports\Driven\Queue\Queue; -use CloudCreativity\Modules\Contracts\Application\Ports\Driving\Commands\CommandDispatcher as ICommandDispatcher; +use CloudCreativity\Modules\Contracts\Application\Ports\Driven\Queue; +use CloudCreativity\Modules\Contracts\Application\Ports\Driving\CommandDispatcher as ICommandDispatcher; use CloudCreativity\Modules\Contracts\Toolkit\Pipeline\PipeContainer; use CloudCreativity\Modules\Contracts\Toolkit\Result\Result; use CloudCreativity\Modules\Toolkit\Pipeline\MiddlewareProcessor; diff --git a/src/Application/Bus/QueryDispatcher.php b/src/Application/Bus/QueryDispatcher.php index 56af721..dcf4df9 100644 --- a/src/Application/Bus/QueryDispatcher.php +++ b/src/Application/Bus/QueryDispatcher.php @@ -14,7 +14,7 @@ use CloudCreativity\Modules\Contracts\Application\Bus\QueryHandlerContainer; use CloudCreativity\Modules\Contracts\Application\Messages\Query; -use CloudCreativity\Modules\Contracts\Application\Ports\Driving\Queries\QueryDispatcher as IQueryDispatcher; +use CloudCreativity\Modules\Contracts\Application\Ports\Driving\QueryDispatcher as IQueryDispatcher; use CloudCreativity\Modules\Contracts\Toolkit\Pipeline\PipeContainer; use CloudCreativity\Modules\Contracts\Toolkit\Result\Result; use CloudCreativity\Modules\Toolkit\Pipeline\MiddlewareProcessor; diff --git a/src/Application/InboundEventBus/EventDispatcher.php b/src/Application/InboundEventBus/InboundEventDispatcher.php similarity index 95% rename from src/Application/InboundEventBus/EventDispatcher.php rename to src/Application/InboundEventBus/InboundEventDispatcher.php index ea9c78a..4f18a17 100644 --- a/src/Application/InboundEventBus/EventDispatcher.php +++ b/src/Application/InboundEventBus/InboundEventDispatcher.php @@ -14,12 +14,12 @@ use CloudCreativity\Modules\Contracts\Application\InboundEventBus\EventHandlerContainer; use CloudCreativity\Modules\Contracts\Application\Messages\IntegrationEvent; -use CloudCreativity\Modules\Contracts\Application\Ports\Driving\InboundEvents\EventDispatcher as EventPort; +use CloudCreativity\Modules\Contracts\Application\Ports\Driving\InboundEventDispatcher as IInboundEventDispatcher; use CloudCreativity\Modules\Contracts\Toolkit\Pipeline\PipeContainer; use CloudCreativity\Modules\Toolkit\Pipeline\MiddlewareProcessor; use CloudCreativity\Modules\Toolkit\Pipeline\PipelineBuilder; -class EventDispatcher implements EventPort +class InboundEventDispatcher implements IInboundEventDispatcher { /** * @var array diff --git a/src/Application/UnitOfWork/UnitOfWorkManager.php b/src/Application/UnitOfWork/UnitOfWorkManager.php index 7ffd636..4fc63a3 100644 --- a/src/Application/UnitOfWork/UnitOfWorkManager.php +++ b/src/Application/UnitOfWork/UnitOfWorkManager.php @@ -13,8 +13,8 @@ namespace CloudCreativity\Modules\Application\UnitOfWork; use Closure; -use CloudCreativity\Modules\Contracts\Application\Ports\Driven\Exceptions\ExceptionReporter; -use CloudCreativity\Modules\Contracts\Application\Ports\Driven\UnitOfWork\UnitOfWork; +use CloudCreativity\Modules\Contracts\Application\Ports\Driven\ExceptionReporter; +use CloudCreativity\Modules\Contracts\Application\Ports\Driven\UnitOfWork; use CloudCreativity\Modules\Contracts\Application\UnitOfWork\UnitOfWorkManager as IUnitOfWorkManager; use RuntimeException; use Throwable; diff --git a/src/Contracts/Application/Ports/Driven/Exceptions/ExceptionReporter.php b/src/Contracts/Application/Ports/Driven/ExceptionReporter.php similarity index 96% rename from src/Contracts/Application/Ports/Driven/Exceptions/ExceptionReporter.php rename to src/Contracts/Application/Ports/Driven/ExceptionReporter.php index 4638be9..51bd83a 100644 --- a/src/Contracts/Application/Ports/Driven/Exceptions/ExceptionReporter.php +++ b/src/Contracts/Application/Ports/Driven/ExceptionReporter.php @@ -10,7 +10,7 @@ declare(strict_types=1); -namespace CloudCreativity\Modules\Contracts\Application\Ports\Driven\Exceptions; +namespace CloudCreativity\Modules\Contracts\Application\Ports\Driven; use Throwable; diff --git a/src/Contracts/Application/Ports/Driven/OutboundEventBus/EventPublisher.php b/src/Contracts/Application/Ports/Driven/OutboundEventPublisher.php similarity index 92% rename from src/Contracts/Application/Ports/Driven/OutboundEventBus/EventPublisher.php rename to src/Contracts/Application/Ports/Driven/OutboundEventPublisher.php index c9c4d36..dd92bf2 100644 --- a/src/Contracts/Application/Ports/Driven/OutboundEventBus/EventPublisher.php +++ b/src/Contracts/Application/Ports/Driven/OutboundEventPublisher.php @@ -10,11 +10,11 @@ declare(strict_types=1); -namespace CloudCreativity\Modules\Contracts\Application\Ports\Driven\OutboundEventBus; +namespace CloudCreativity\Modules\Contracts\Application\Ports\Driven; use CloudCreativity\Modules\Contracts\Application\Messages\IntegrationEvent; -interface EventPublisher +interface OutboundEventPublisher { /** * Publish an outbound integration event. diff --git a/src/Contracts/Application/Ports/Driven/Queue/Queue.php b/src/Contracts/Application/Ports/Driven/Queue.php similarity index 97% rename from src/Contracts/Application/Ports/Driven/Queue/Queue.php rename to src/Contracts/Application/Ports/Driven/Queue.php index 32d7efb..358b535 100644 --- a/src/Contracts/Application/Ports/Driven/Queue/Queue.php +++ b/src/Contracts/Application/Ports/Driven/Queue.php @@ -10,7 +10,7 @@ declare(strict_types=1); -namespace CloudCreativity\Modules\Contracts\Application\Ports\Driven\Queue; +namespace CloudCreativity\Modules\Contracts\Application\Ports\Driven; use CloudCreativity\Modules\Contracts\Application\Messages\Command; diff --git a/src/Contracts/Application/Ports/Driven/UnitOfWork/UnitOfWork.php b/src/Contracts/Application/Ports/Driven/UnitOfWork.php similarity index 97% rename from src/Contracts/Application/Ports/Driven/UnitOfWork/UnitOfWork.php rename to src/Contracts/Application/Ports/Driven/UnitOfWork.php index 5c55afc..ef716a2 100644 --- a/src/Contracts/Application/Ports/Driven/UnitOfWork/UnitOfWork.php +++ b/src/Contracts/Application/Ports/Driven/UnitOfWork.php @@ -10,7 +10,7 @@ declare(strict_types=1); -namespace CloudCreativity\Modules\Contracts\Application\Ports\Driven\UnitOfWork; +namespace CloudCreativity\Modules\Contracts\Application\Ports\Driven; use Closure; diff --git a/src/Contracts/Application/Ports/Driving/Commands/CommandDispatcher.php b/src/Contracts/Application/Ports/Driving/CommandDispatcher.php similarity index 98% rename from src/Contracts/Application/Ports/Driving/Commands/CommandDispatcher.php rename to src/Contracts/Application/Ports/Driving/CommandDispatcher.php index 6c6b42d..25be807 100644 --- a/src/Contracts/Application/Ports/Driving/Commands/CommandDispatcher.php +++ b/src/Contracts/Application/Ports/Driving/CommandDispatcher.php @@ -10,7 +10,7 @@ declare(strict_types=1); -namespace CloudCreativity\Modules\Contracts\Application\Ports\Driving\Commands; +namespace CloudCreativity\Modules\Contracts\Application\Ports\Driving; use CloudCreativity\Modules\Contracts\Application\Messages\Command; use CloudCreativity\Modules\Contracts\Toolkit\Result\Result; diff --git a/src/Contracts/Application/Ports/Driving/InboundEvents/EventDispatcher.php b/src/Contracts/Application/Ports/Driving/InboundEventDispatcher.php similarity index 92% rename from src/Contracts/Application/Ports/Driving/InboundEvents/EventDispatcher.php rename to src/Contracts/Application/Ports/Driving/InboundEventDispatcher.php index 79d8819..1591b6d 100644 --- a/src/Contracts/Application/Ports/Driving/InboundEvents/EventDispatcher.php +++ b/src/Contracts/Application/Ports/Driving/InboundEventDispatcher.php @@ -10,11 +10,11 @@ declare(strict_types=1); -namespace CloudCreativity\Modules\Contracts\Application\Ports\Driving\InboundEvents; +namespace CloudCreativity\Modules\Contracts\Application\Ports\Driving; use CloudCreativity\Modules\Contracts\Application\Messages\IntegrationEvent; -interface EventDispatcher +interface InboundEventDispatcher { /** * Dispatch an inbound integration event. diff --git a/src/Contracts/Application/Ports/Driving/Queries/QueryDispatcher.php b/src/Contracts/Application/Ports/Driving/QueryDispatcher.php similarity index 97% rename from src/Contracts/Application/Ports/Driving/Queries/QueryDispatcher.php rename to src/Contracts/Application/Ports/Driving/QueryDispatcher.php index a5e8933..50b2032 100644 --- a/src/Contracts/Application/Ports/Driving/Queries/QueryDispatcher.php +++ b/src/Contracts/Application/Ports/Driving/QueryDispatcher.php @@ -10,7 +10,7 @@ declare(strict_types=1); -namespace CloudCreativity\Modules\Contracts\Application\Ports\Driving\Queries; +namespace CloudCreativity\Modules\Contracts\Application\Ports\Driving; use CloudCreativity\Modules\Contracts\Application\Messages\Query; use CloudCreativity\Modules\Contracts\Toolkit\Result\Result; diff --git a/src/Infrastructure/OutboundEventBus/ClosurePublisher.php b/src/Infrastructure/OutboundEventBus/ClosurePublisher.php index 0faeb89..3df73e2 100644 --- a/src/Infrastructure/OutboundEventBus/ClosurePublisher.php +++ b/src/Infrastructure/OutboundEventBus/ClosurePublisher.php @@ -14,12 +14,12 @@ use Closure; use CloudCreativity\Modules\Contracts\Application\Messages\IntegrationEvent; -use CloudCreativity\Modules\Contracts\Application\Ports\Driven\OutboundEventBus\EventPublisher; +use CloudCreativity\Modules\Contracts\Application\Ports\Driven\OutboundEventPublisher; use CloudCreativity\Modules\Contracts\Toolkit\Pipeline\PipeContainer; use CloudCreativity\Modules\Toolkit\Pipeline\MiddlewareProcessor; use CloudCreativity\Modules\Toolkit\Pipeline\PipelineBuilder; -class ClosurePublisher implements EventPublisher +class ClosurePublisher implements OutboundEventPublisher { /** * @var array, Closure> diff --git a/src/Infrastructure/OutboundEventBus/ComponentPublisher.php b/src/Infrastructure/OutboundEventBus/ComponentPublisher.php index 7bf8e73..f90fe82 100644 --- a/src/Infrastructure/OutboundEventBus/ComponentPublisher.php +++ b/src/Infrastructure/OutboundEventBus/ComponentPublisher.php @@ -13,13 +13,13 @@ namespace CloudCreativity\Modules\Infrastructure\OutboundEventBus; use CloudCreativity\Modules\Contracts\Application\Messages\IntegrationEvent; -use CloudCreativity\Modules\Contracts\Application\Ports\Driven\OutboundEventBus\EventPublisher; +use CloudCreativity\Modules\Contracts\Application\Ports\Driven\OutboundEventPublisher; use CloudCreativity\Modules\Contracts\Infrastructure\OutboundEventBus\PublisherHandlerContainer; use CloudCreativity\Modules\Contracts\Toolkit\Pipeline\PipeContainer; use CloudCreativity\Modules\Toolkit\Pipeline\MiddlewareProcessor; use CloudCreativity\Modules\Toolkit\Pipeline\PipelineBuilder; -class ComponentPublisher implements EventPublisher +class ComponentPublisher implements OutboundEventPublisher { /** * @var array diff --git a/src/Infrastructure/Queue/ClosureQueue.php b/src/Infrastructure/Queue/ClosureQueue.php index c28ab10..de89dd0 100644 --- a/src/Infrastructure/Queue/ClosureQueue.php +++ b/src/Infrastructure/Queue/ClosureQueue.php @@ -14,7 +14,7 @@ use Closure; use CloudCreativity\Modules\Contracts\Application\Messages\Command; -use CloudCreativity\Modules\Contracts\Application\Ports\Driven\Queue\Queue; +use CloudCreativity\Modules\Contracts\Application\Ports\Driven\Queue; use CloudCreativity\Modules\Contracts\Toolkit\Pipeline\PipeContainer; use CloudCreativity\Modules\Toolkit\Pipeline\MiddlewareProcessor; use CloudCreativity\Modules\Toolkit\Pipeline\PipelineBuilder; diff --git a/src/Infrastructure/Queue/ComponentQueue.php b/src/Infrastructure/Queue/ComponentQueue.php index beae37a..63d60b6 100644 --- a/src/Infrastructure/Queue/ComponentQueue.php +++ b/src/Infrastructure/Queue/ComponentQueue.php @@ -13,7 +13,7 @@ namespace CloudCreativity\Modules\Infrastructure\Queue; use CloudCreativity\Modules\Contracts\Application\Messages\Command; -use CloudCreativity\Modules\Contracts\Application\Ports\Driven\Queue\Queue; +use CloudCreativity\Modules\Contracts\Application\Ports\Driven\Queue; use CloudCreativity\Modules\Contracts\Infrastructure\Queue\EnqueuerContainer; use CloudCreativity\Modules\Contracts\Toolkit\Pipeline\PipeContainer; use CloudCreativity\Modules\Toolkit\Pipeline\MiddlewareProcessor; diff --git a/tests/Unit/Application/Bus/CommandDispatcherTest.php b/tests/Unit/Application/Bus/CommandDispatcherTest.php index 8270626..a469dc4 100644 --- a/tests/Unit/Application/Bus/CommandDispatcherTest.php +++ b/tests/Unit/Application/Bus/CommandDispatcherTest.php @@ -16,7 +16,7 @@ use CloudCreativity\Modules\Contracts\Application\Bus\CommandHandler; use CloudCreativity\Modules\Contracts\Application\Bus\CommandHandlerContainer; use CloudCreativity\Modules\Contracts\Application\Messages\Command; -use CloudCreativity\Modules\Contracts\Application\Ports\Driven\Queue\Queue; +use CloudCreativity\Modules\Contracts\Application\Ports\Driven\Queue; use CloudCreativity\Modules\Contracts\Toolkit\Pipeline\PipeContainer; use CloudCreativity\Modules\Toolkit\Result\Result; use PHPUnit\Framework\MockObject\MockObject; diff --git a/tests/Unit/Application/InboundEventBus/EventDispatcherTest.php b/tests/Unit/Application/InboundEventBus/InboundEventDispatcherTest.php similarity index 94% rename from tests/Unit/Application/InboundEventBus/EventDispatcherTest.php rename to tests/Unit/Application/InboundEventBus/InboundEventDispatcherTest.php index 55c0db4..cfcc8db 100644 --- a/tests/Unit/Application/InboundEventBus/EventDispatcherTest.php +++ b/tests/Unit/Application/InboundEventBus/InboundEventDispatcherTest.php @@ -12,7 +12,7 @@ namespace CloudCreativity\Modules\Tests\Unit\Application\InboundEventBus; -use CloudCreativity\Modules\Application\InboundEventBus\EventDispatcher; +use CloudCreativity\Modules\Application\InboundEventBus\InboundEventDispatcher; use CloudCreativity\Modules\Contracts\Application\InboundEventBus\EventHandler; use CloudCreativity\Modules\Contracts\Application\InboundEventBus\EventHandlerContainer; use CloudCreativity\Modules\Contracts\Application\Messages\IntegrationEvent; @@ -20,7 +20,7 @@ use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -class EventDispatcherTest extends TestCase +class InboundEventDispatcherTest extends TestCase { /** * @var EventHandlerContainer&MockObject @@ -33,9 +33,9 @@ class EventDispatcherTest extends TestCase private PipeContainer&MockObject $middleware; /** - * @var EventDispatcher + * @var InboundEventDispatcher */ - private EventDispatcher $dispatcher; + private InboundEventDispatcher $dispatcher; /** * @var array @@ -49,7 +49,7 @@ protected function setUp(): void { parent::setUp(); - $this->dispatcher = new EventDispatcher( + $this->dispatcher = new InboundEventDispatcher( handlers: $this->handlers = $this->createMock(EventHandlerContainer::class), middleware: $this->middleware = $this->createMock(PipeContainer::class), ); diff --git a/tests/Unit/Application/UnitOfWork/UnitOfWorkManagerTest.php b/tests/Unit/Application/UnitOfWork/UnitOfWorkManagerTest.php index 0a785a4..2795f25 100644 --- a/tests/Unit/Application/UnitOfWork/UnitOfWorkManagerTest.php +++ b/tests/Unit/Application/UnitOfWork/UnitOfWorkManagerTest.php @@ -14,8 +14,8 @@ use Closure; use CloudCreativity\Modules\Application\UnitOfWork\UnitOfWorkManager; -use CloudCreativity\Modules\Contracts\Application\Ports\Driven\Exceptions\ExceptionReporter; -use CloudCreativity\Modules\Contracts\Application\Ports\Driven\UnitOfWork\UnitOfWork; +use CloudCreativity\Modules\Contracts\Application\Ports\Driven\ExceptionReporter; +use CloudCreativity\Modules\Contracts\Application\Ports\Driven\UnitOfWork; use LogicException; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; From 29a33e4cb0e609a42cc200956c9e9d5bad9d891d Mon Sep 17 00:00:00 2001 From: Christopher Gammie Date: Sat, 7 Dec 2024 15:42:51 +0000 Subject: [PATCH 8/8] docs: update changelog and bump version --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 038599b..8349b5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ All notable changes to this project will be documented in this file. This projec ## Unreleased +## [2.0.0] - 2024-12-07 + ### Changed - **BREAKING** Removed the sub-namespaces for ports provided by this package, i.e.: @@ -325,3 +327,5 @@ All notable changes to this project will be documented in this file. This projec ## [0.1.0] - 2023-11-18 Initial release. + +[2.0.0]: https://github.com/cloudcreativity/docs.dancecloud.com/compare/v2.0.0-rc.3...v2.0.0 \ No newline at end of file