From 522da05f30a8d9692d0be8b4a82e1bc33359d0b3 Mon Sep 17 00:00:00 2001 From: Matthias Noback Date: Wed, 15 May 2019 16:14:04 +0200 Subject: [PATCH] Allow passing in extra state from the custom repository class This may be needed in case the tables for aggregate root and child entities don't containa ll the information you may need inside the entity. This might be considered an issue with the database schema, but you may not be able to fix the problem. So instead, you need a work-around, which is provided by this change. --- src/TalisOrm/AggregateRepository.php | 3 +- .../AbstractAggregateRepositoryTest.php | 78 +++++++++++++++---- .../TalisOrm/AggregateRepositoryTest/Line.php | 15 +++- .../AggregateRepositoryTest/Order.php | 17 +++- .../OrderTalisOrmRepository.php | 4 +- 5 files changed, 98 insertions(+), 19 deletions(-) diff --git a/src/TalisOrm/AggregateRepository.php b/src/TalisOrm/AggregateRepository.php index 71727cd..752f0c5 100644 --- a/src/TalisOrm/AggregateRepository.php +++ b/src/TalisOrm/AggregateRepository.php @@ -63,7 +63,7 @@ public function save(Aggregate $aggregate): void $this->eventDispatcher->dispatch($aggregate->releaseEvents()); } - public function getById(string $aggregateClass, AggregateId $aggregateId): Aggregate + public function getById(string $aggregateClass, AggregateId $aggregateId, array $extraState = []): Aggregate { if (!is_a($aggregateClass, Aggregate::class, true)) { throw new InvalidArgumentException(sprintf( @@ -74,6 +74,7 @@ public function getById(string $aggregateClass, AggregateId $aggregateId): Aggre } $aggregateState = $this->getAggregateState($aggregateClass, $aggregateId); + $aggregateState = array_merge($aggregateState, $extraState); $childEntitiesByType = $this->getChildEntitiesByType($aggregateClass, $aggregateId, $aggregateState); diff --git a/test/TalisOrm/AbstractAggregateRepositoryTest.php b/test/TalisOrm/AbstractAggregateRepositoryTest.php index ad8e1f7..19df21b 100644 --- a/test/TalisOrm/AbstractAggregateRepositoryTest.php +++ b/test/TalisOrm/AbstractAggregateRepositoryTest.php @@ -71,7 +71,8 @@ public function it_saves_an_aggregate() { $aggregate = Order::create( new OrderId('91338a57-5c9a-40e8-b5e8-803e8175c7d7', 5), - DateTimeUtil::createDateTimeImmutable('2018-10-03') + DateTimeUtil::createDateTimeImmutable('2018-10-03'), + $this->quantityPrecision() ); $this->repository->save($aggregate); @@ -81,6 +82,37 @@ public function it_saves_an_aggregate() self::assertEquals([new OrderCreated()], $this->eventDispatcher->dispatchedEvents()); } + /** + * @test + */ + public function when_loading_an_aggregate_it_can_inject_some_extra_state(): void + { + $aggregate = Order::create( + new OrderId('91338a57-5c9a-40e8-b5e8-803e8175c7d7', 5), + DateTimeUtil::createDateTimeImmutable('2019-05-15'), + $this->quantityPrecision() + ); + $aggregate->addLine( + new LineNumber(1), + new ProductId('73d46c97-a71b-4e3c-9633-bb7a8603b301', 5), + new Quantity(10) + ); + $this->repository->save($aggregate); + + $fromDatabase = $this->repository->getById($aggregate->orderId()); + + /* + * The quantity precision doesn't come from the database, but from the array of extra state, provided by the + * `OrderTalisOrmRepository`. + */ + self::assertSame(2, $fromDatabase->quantityPrecision()); + + /* + * It's also available to the `fromState()` method of the `Line` child entity. + */ + self::assertSame(2, $fromDatabase->lines()[0]->quantityPrecision()); + } + /** * @test */ @@ -88,7 +120,8 @@ public function it_updates_an_aggregate() { $aggregate = Order::create( new OrderId('91338a57-5c9a-40e8-b5e8-803e8175c7d7', 5), - DateTimeUtil::createDateTimeImmutable('2018-10-03') + DateTimeUtil::createDateTimeImmutable('2018-10-03'), + $this->quantityPrecision() ); $this->repository->save($aggregate); @@ -114,13 +147,15 @@ public function it_triggers_a_unique_constraint_exception_if_an_id_is_reused_for { $aggregate = Order::create( new OrderId('91338a57-5c9a-40e8-b5e8-803e8175c7d7', 5), - DateTimeUtil::createDateTimeImmutable('2018-10-03') + DateTimeUtil::createDateTimeImmutable('2018-10-03'), + $this->quantityPrecision() ); $this->repository->save($aggregate); $aggregateWithSameId = Order::create( new OrderId('91338a57-5c9a-40e8-b5e8-803e8175c7d7', 5), - DateTimeUtil::createDateTimeImmutable('2018-10-04') + DateTimeUtil::createDateTimeImmutable('2018-10-04'), + $this->quantityPrecision() ); $this->expectException(UniqueConstraintViolationException::class); @@ -135,7 +170,8 @@ public function it_guards_against_concurrent_updates() { $aggregate = Order::create( new OrderId('91338a57-5c9a-40e8-b5e8-803e8175c7d7', 5), - DateTimeUtil::createDateTimeImmutable('2018-10-03') + DateTimeUtil::createDateTimeImmutable('2018-10-03'), + $this->quantityPrecision() ); $this->repository->save($aggregate); @@ -166,7 +202,8 @@ public function it_guards_against_concurrent_updates_if_the_aggregate_has_a_lowe { $aggregate = Order::create( new OrderId('91338a57-5c9a-40e8-b5e8-803e8175c7d7', 5), - DateTimeUtil::createDateTimeImmutable('2018-10-03') + DateTimeUtil::createDateTimeImmutable('2018-10-03'), + $this->quantityPrecision() ); $this->repository->save($aggregate); @@ -194,7 +231,8 @@ public function it_saves_an_aggregate_with_its_child_entities() { $aggregate = Order::create( new OrderId('91338a57-5c9a-40e8-b5e8-803e8175c7d7', 5), - DateTimeUtil::createDateTimeImmutable('2018-10-03') + DateTimeUtil::createDateTimeImmutable('2018-10-03'), + $this->quantityPrecision() ); $aggregate->addLine( new LineNumber(1), @@ -222,7 +260,8 @@ public function entities_will_only_be_marked_as_persisted_if_all_queries_within_ { $aggregate = Order::create( new OrderId('91338a57-5c9a-40e8-b5e8-803e8175c7d7', 5), - DateTimeUtil::createDateTimeImmutable('2018-10-03') + DateTimeUtil::createDateTimeImmutable('2018-10-03'), + $this->quantityPrecision() ); $aggregate->addLine( new LineNumber(1), @@ -255,7 +294,8 @@ public function it_creates_multiple_child_entities_in_the_database() { $aggregate = Order::create( new OrderId('91338a57-5c9a-40e8-b5e8-803e8175c7d7', 5), - DateTimeUtil::createDateTimeImmutable('2018-10-03') + DateTimeUtil::createDateTimeImmutable('2018-10-03'), + $this->quantityPrecision() ); $aggregate->addLine( new LineNumber(1), @@ -289,7 +329,8 @@ public function it_updates_multiple_child_entities_in_the_database() { $aggregate = Order::create( new OrderId('91338a57-5c9a-40e8-b5e8-803e8175c7d7', 5), - DateTimeUtil::createDateTimeImmutable('2018-10-03') + DateTimeUtil::createDateTimeImmutable('2018-10-03'), + $this->quantityPrecision() ); $aggregate->addLine( new LineNumber(1), @@ -331,7 +372,8 @@ public function it_deletes_child_entities_that_have_been_removed_from_the_aggreg { $aggregate = Order::create( new OrderId('91338a57-5c9a-40e8-b5e8-803e8175c7d7', 5), - DateTimeUtil::createDateTimeImmutable('2018-10-03') + DateTimeUtil::createDateTimeImmutable('2018-10-03'), + $this->quantityPrecision() ); $aggregate->addLine( new LineNumber(1), @@ -369,7 +411,8 @@ public function it_deletes_an_aggregate_with_its_child_entities() { $aggregate = Order::create( new OrderId('91338a57-5c9a-40e8-b5e8-803e8175c7d7', 5), - DateTimeUtil::createDateTimeImmutable('2018-10-03') + DateTimeUtil::createDateTimeImmutable('2018-10-03'), + $this->quantityPrecision() ); $aggregate->addLine( new LineNumber(1), @@ -391,12 +434,14 @@ public function it_does_not_delete_all_aggregates_of_the_same_type() { $aggregate1 = Order::create( new OrderId('91338a57-5c9a-40e8-b5e8-803e8175c7d7', 5), - DateTimeUtil::createDateTimeImmutable('2018-10-03') + DateTimeUtil::createDateTimeImmutable('2018-10-03'), + $this->quantityPrecision() ); $this->repository->save($aggregate1); $aggregate2 = Order::create( new OrderId('c8ee1ee6-7757-4661-81fb-5b327badbff8', 5), - DateTimeUtil::createDateTimeImmutable('2018-10-04') + DateTimeUtil::createDateTimeImmutable('2018-10-04'), + $this->quantityPrecision() ); $this->repository->save($aggregate2); @@ -409,4 +454,9 @@ public function it_does_not_delete_all_aggregates_of_the_same_type() $this->expectException(AggregateNotFoundException::class); $this->repository->getById($aggregate1->orderId()); } + + private function quantityPrecision(): int + { + return 2; + } } diff --git a/test/TalisOrm/AggregateRepositoryTest/Line.php b/test/TalisOrm/AggregateRepositoryTest/Line.php index 00af267..10337ab 100644 --- a/test/TalisOrm/AggregateRepositoryTest/Line.php +++ b/test/TalisOrm/AggregateRepositoryTest/Line.php @@ -32,6 +32,11 @@ final class Line implements ChildEntity, SpecifiesSchema */ private $quantity; + /** + * @var int + */ + private $quantityPrecision; + private function __construct() { } @@ -40,7 +45,8 @@ public static function create( OrderId $orderId, LineNumber $lineNumber, ProductId $productId, - Quantity $quantity + Quantity $quantity, + int $quantityPrecision ): Line { $line = new self(); @@ -48,6 +54,7 @@ public static function create( $line->lineNumber = $lineNumber; $line->productId = $productId; $line->quantity = $quantity; + $line->quantityPrecision = $quantityPrecision; return $line; } @@ -78,6 +85,11 @@ public function quantity(): Quantity return $this->quantity; } + public function quantityPrecision(): int + { + return $this->quantityPrecision; + } + public function state(): array { return [ @@ -97,6 +109,7 @@ public static function fromState(array $state, array $aggregateState): Line $line->lineNumber = new LineNumber((int)$state['line_number']); $line->productId = new ProductId($state['product_id'], (int)$state['company_id']); $line->quantity = new Quantity((int)$state['quantity']); + $line->quantityPrecision = $aggregateState['quantityPrecision']; return $line; } diff --git a/test/TalisOrm/AggregateRepositoryTest/Order.php b/test/TalisOrm/AggregateRepositoryTest/Order.php index 0437b6a..9423fe8 100644 --- a/test/TalisOrm/AggregateRepositoryTest/Order.php +++ b/test/TalisOrm/AggregateRepositoryTest/Order.php @@ -32,6 +32,11 @@ final class Order implements Aggregate, SpecifiesSchema */ private $lines = []; + /** + * @var int + */ + private $quantityPrecision; + private function __construct() { } @@ -41,12 +46,13 @@ private function __construct() * @param DateTimeImmutable $orderDate * @return Order */ - public static function create(OrderId $orderId, DateTimeImmutable $orderDate) + public static function create(OrderId $orderId, DateTimeImmutable $orderDate, int $quantityPrecision) { $order = new self(); $order->orderId = $orderId; $order->orderDate = $orderDate; + $order->quantityPrecision = $quantityPrecision; $order->recordThat(new OrderCreated()); @@ -72,7 +78,7 @@ public function update(DateTimeImmutable $orderDate) */ public function addLine(LineNumber $lineId, ProductId $productId, Quantity $quantity) { - $this->lines[] = Line::create($this->orderId, $lineId, $productId, $quantity); + $this->lines[] = Line::create($this->orderId, $lineId, $productId, $quantity, $this->quantityPrecision); $this->recordThat(new LineAdded()); } @@ -160,6 +166,8 @@ public static function fromState(array $aggregateState, array $childEntitiesByTy $order->aggregateVersion = (int)$aggregateState[Aggregate::VERSION_COLUMN]; + $order->quantityPrecision = $aggregateState['quantityPrecision']; + return $order; } @@ -216,4 +224,9 @@ public function lines(): array { return $this->lines; } + + public function quantityPrecision(): int + { + return $this->quantityPrecision; + } } diff --git a/test/TalisOrm/AggregateRepositoryTest/OrderTalisOrmRepository.php b/test/TalisOrm/AggregateRepositoryTest/OrderTalisOrmRepository.php index 0e439cc..15e4c2f 100644 --- a/test/TalisOrm/AggregateRepositoryTest/OrderTalisOrmRepository.php +++ b/test/TalisOrm/AggregateRepositoryTest/OrderTalisOrmRepository.php @@ -29,7 +29,9 @@ public function save(Order $order) public function getById(OrderId $orderId) { - return $this->aggregateRepository->getById(Order::class, $orderId); + return $this->aggregateRepository->getById(Order::class, $orderId, [ + 'quantityPrecision' => 2 + ]); } public function delete(Order $order)