コード例 #1
0
ファイル: SagaRepository.php プロジェクト: martyn82/apha
 /**
  * @param Identity $sagaIdentity
  * @param string $sagaType
  * @return Saga
  */
 public function load(Identity $sagaIdentity, string $sagaType)
 {
     $sagaData = $this->storage->findById($sagaIdentity->getValue());
     if (empty($sagaData)) {
         return null;
     }
     return $this->serializer->deserialize($sagaData, $sagaType);
 }
コード例 #2
0
ファイル: ReplayRunner.php プロジェクト: martyn82/apha
 /**
  * @param Identity $identity
  * @param EventStorage $eventStorage
  * @param Serializer $serializer
  */
 private function prepareSomeEvents(Identity $identity, EventStorage $eventStorage, Serializer $serializer)
 {
     // This is not the preferred way, but used for simplicity! You should use commands to achieve this.
     $event = new CreatedEvent($identity);
     $event->setVersion(1);
     $eventStorage->append(EventDescriptor::record($identity->getValue(), 'aggregateType', $event->getEventName(), $serializer->serialize($event), $event->getVersion()));
     $event = new DemonstratedEvent($identity);
     $event->setVersion(2);
     $eventStorage->append(EventDescriptor::record($identity->getValue(), 'aggregateType', $event->getEventName(), $serializer->serialize($event), $event->getVersion()));
 }
コード例 #3
0
ファイル: ManagedSagaRunner.php プロジェクト: martyn82/apha
 /**
  * @return void
  */
 public function run()
 {
     $logger = new Logger('default');
     $sagaFactory = new GenericSagaFactory();
     $sagaStorage = new MemorySagaStorage();
     $sagaRepository = new SagaRepository($sagaStorage, new JsonSerializer());
     $resolver = new SimpleAssociationValueResolver();
     $sagaManager = new SimpleSagaManager([ToDoSaga::class], $sagaRepository, $resolver, $sagaFactory);
     $eventBus = new SimpleEventBus([]);
     $eventBus->setLogger(new EventLogger($logger));
     $eventBus->addHandler(Event::class, $sagaManager);
     $eventStore = new EventStore($eventBus, new MemoryEventStorage(), new JsonSerializer(), new EventClassMap([ToDoItemCreated::class, ToDoItemDone::class, DeadlineExpired::class]));
     $factory = new GenericAggregateFactory(ToDoItem::class);
     $repository = new EventSourcingRepository($factory, $eventStore);
     $commandHandler = new ToDoCommandHandler($repository);
     $commandBus = new SimpleCommandBus([CreateToDoItem::class => $commandHandler, MarkItemDone::class => $commandHandler]);
     $loggingCommandInterceptor = new LoggingInterceptor(new CommandLogger($logger));
     $commandGateway = new DefaultCommandGateway($commandBus, [$loggingCommandInterceptor]);
     $toCompleteId = Identity::createNew();
     $commandGateway->send(new CreateToDoItem($toCompleteId, "Item to complete", PHP_INT_MAX));
     $sagaIds = $sagaRepository->find(ToDoSaga::class, new AssociationValue('identity', $toCompleteId->getValue()));
     $logger->debug("Active sagas found:", ['count' => count($sagaIds), 'saga' => !empty($sagaIds) ? $sagaStorage->findById($sagaIds[0]->getValue()) : '']);
     $commandGateway->send(new MarkItemDone($toCompleteId));
     $sagaIds = $sagaRepository->find(ToDoSaga::class, new AssociationValue('identity', $toCompleteId->getValue()));
     $logger->debug("Active sagas found:", ['count' => count($sagaIds), 'saga' => !empty($sagaIds) ? $sagaStorage->findById($sagaIds[0]->getValue())['serialized'] : '']);
 }
コード例 #4
0
ファイル: SagaRunner.php プロジェクト: martyn82/apha
 /**
  * @return void
  */
 public function run()
 {
     $logger = new Logger('default');
     $sagaId = Identity::createNew();
     $toDoSaga = new ToDoSaga($sagaId, new AssociationValues([]));
     $eventBus = new SimpleEventBus([ToDoItemCreated::class => [$toDoSaga], ToDoItemDone::class => [$toDoSaga], DeadlineExpired::class => [$toDoSaga]]);
     $eventBus->setLogger(new EventLogger($logger));
     $scheduler = new SimpleEventScheduler($eventBus);
     $toDoSaga->setEventScheduler($scheduler);
     $eventStore = new EventStore($eventBus, new MemoryEventStorage(), new JsonSerializer(), new EventClassMap([ToDoItemCreated::class, ToDoItemDone::class, DeadlineExpired::class]));
     $factory = new GenericAggregateFactory(ToDoItem::class);
     $repository = new EventSourcingRepository($factory, $eventStore);
     $commandHandler = new ToDoCommandHandler($repository);
     $commandBus = new SimpleCommandBus([CreateToDoItem::class => $commandHandler, MarkItemDone::class => $commandHandler]);
     $loggingCommandInterceptor = new LoggingInterceptor(new CommandLogger($logger));
     $commandGateway = new DefaultCommandGateway($commandBus, [$loggingCommandInterceptor]);
     // Send commands to create two todoitems
     $todoItemExpireSeconds = 3;
     $toCompleteId = Identity::createNew();
     $toExpireId = Identity::createNew();
     $commandGateway->send(new CreateToDoItem($toCompleteId, "Item to complete", $todoItemExpireSeconds));
     $commandGateway->send(new CreateToDoItem($toExpireId, "Item to expire", $todoItemExpireSeconds));
     // Start an idling process for 5 seconds and wait for the ToDoItem to expire
     $this->idle(5, $commandGateway, $toCompleteId);
 }
コード例 #5
0
ファイル: Scenario.php プロジェクト: martyn82/apha
 /**
  * @param array $events
  * @return AggregateRoot
  */
 private function getAggregate(array $events = []) : AggregateRoot
 {
     if ($this->aggregate == null) {
         $this->aggregate = $this->factory->createAggregate(Identity::createNew(), new Events($events));
     }
     return $this->aggregate;
 }
コード例 #6
0
 /**
  * @test
  */
 public function readAllRetrievesAllAnnotatedStartSagas()
 {
     $saga = new StartSagaAnnotationReaderTest_Saga(Identity::createNew(), new AssociationValues([]));
     $reader = new StartSagaAnnotationReader($saga);
     $annotations = $reader->readAll();
     self::assertCount(1, $annotations);
 }
コード例 #7
0
ファイル: AnnotatedSaga.php プロジェクト: martyn82/apha
 /**
  * @param Identity $identity
  */
 public function __construct(Identity $identity = null)
 {
     if ($identity == null) {
         $identity = Identity::createNew();
     }
     $this->setParameterResolver(new DefaultParameterResolver());
     parent::__construct($identity, new AssociationValues([]));
 }
コード例 #8
0
 /**
  * @test
  */
 public function getIdRetrievesValueOfAggregateIdentifier()
 {
     $identity = Identity::createNew();
     /* @var $aggregate AnnotatedAggregateRootTest_Aggregate */
     $aggregate = AnnotatedAggregateRootTest_Aggregate::reconstruct(new Events());
     $aggregate->setIdentity($identity);
     $actualIdentity = $aggregate->getId();
     self::assertEquals($identity, $actualIdentity);
 }
コード例 #9
0
 /**
  * @test
  */
 public function extractAssociationValuesOnIdentity()
 {
     $identity = Identity::createNew();
     $event = new SimpleAssociationValueResolverTest_Event($identity);
     $resolver = new SimpleAssociationValueResolver();
     $associationValues = $resolver->extractAssociationValues($event);
     $associationValuesArray = $associationValues->getArrayCopy();
     self::assertEquals($identity->getValue(), $associationValuesArray[0]->getValue());
 }
コード例 #10
0
ファイル: ScenarioTest.php プロジェクト: martyn82/apha
 /**
  * @test
  */
 public function aStoryOfSubsequentEvents()
 {
     $factory = $this->createFactory();
     $eventStore = $this->createEventStore(new EventClassMap([ScenarioTest_Created::class, ScenarioTest_DoneThis::class, ScenarioTest_DoneThat::class]));
     $repository = $this->createRepository($factory, $eventStore);
     $commandHandler = new ScenarioTest_CommandHandler($repository);
     $identity = Identity::createNew();
     $scenario = new Scenario($factory, $this, $eventStore, $commandHandler);
     $scenario->given([new ScenarioTest_Created($identity)])->when([new ScenarioTest_DoThis($identity), new ScenarioTest_DoThat($identity)])->then([new ScenarioTest_DoneThis($identity), new ScenarioTest_DoneThat($identity)]);
 }
コード例 #11
0
ファイル: SagaSerializerTest.php プロジェクト: martyn82/apha
 /**
  * @test
  */
 public function deserializeWillHydrateDeserializedSaga()
 {
     $serializer = new JsonSerializer();
     $factory = $this->createFactory();
     $saga = new SagaSerializerTest_Saga(Identity::createNew(), new AssociationValues([]));
     $sagaType = get_class($saga);
     $serializedSaga = $serializer->serialize($saga);
     $factory->expects(self::once())->method('hydrate')->with($saga);
     $sagaSerializer = new SagaSerializer($serializer, $factory);
     $sagaSerializer->deserialize($serializedSaga, $sagaType);
 }
コード例 #12
0
 /**
  * @test
  */
 public function findByIdRetrievesAggregateByIdentity()
 {
     $aggregate = new EventSourcingRepositoryTest_AggregateRoot();
     $aggregateType = get_class($aggregate);
     $factory = $this->createAggregateFactory($aggregateType);
     $identity = Identity::createNew();
     $events = new Events([new EventSourcingRepositoryTest_Event()]);
     $eventStore = $this->createEventStore();
     $eventStore->expects(self::once())->method('getEventsForAggregate')->with($identity)->willReturn($events);
     $repository = new EventSourcingRepository($factory, $eventStore);
     $repository->findById($identity);
 }
コード例 #13
0
 /**
  * @test
  */
 public function createNewSagaIfNoneFound()
 {
     $identity = Identity::createNew();
     $event = $this->getMockBuilder(Event::class)->getMock();
     $event->expects(self::any())->method('getIdentity')->willreturn($identity);
     $sagaTypes = [SimpleSagaManagerTest_Saga::class];
     $repository = $this->createRepository();
     $factory = $this->createFactory();
     $resolver = $this->createAssociationValueResolver();
     $resolver->expects(self::once())->method('extractAssociationValues')->willReturn(new AssociationValues([new AssociationValue('identity', $identity->getValue())]));
     $repository->expects(self::once())->method('find')->willReturn([]);
     $manager = new SimpleSagaManager($sagaTypes, $repository, $resolver, $factory);
     $manager->on($event);
 }
コード例 #14
0
 /**
  * @return void
  */
 public function run()
 {
     $logger = new Logger('default');
     $serializer = new JsonSerializer();
     $stateStorage = new MemoryStateStorage();
     $toDoItemProjections = new ToDoItemProjections($stateStorage);
     $eventStore = new EventStore(new SimpleEventBus([ToDoItemCreated::class => [$toDoItemProjections], ToDoItemDone::class => [$toDoItemProjections], DeadlineExpired::class => [$toDoItemProjections]]), new MemoryEventStorage(), $serializer, new EventClassMap([ToDoItemCreated::class, ToDoItemDone::class, DeadlineExpired::class]));
     $repository = new EventSourcingRepository(new GenericAggregateFactory(ToDoItem::class), $eventStore);
     $toDoItemCommandHandler = new ToDoCommandHandler($repository);
     $commandGateWay = new DefaultCommandGateway(new SimpleCommandBus([CreateToDoItem::class => $toDoItemCommandHandler, MarkItemDone::class => $toDoItemCommandHandler]), [new LoggingInterceptor(new CommandLogger($logger))]);
     $toDoId = Identity::createNew();
     $commandGateWay->send(new CreateToDoItem($toDoId, "Wash the dishes", 5));
     $logger->debug("Current state of ToDoItem", ['item' => $serializer->serialize($stateStorage->find($toDoId->getValue()))]);
     $commandGateWay->send(new MarkItemDone($toDoId));
     $logger->debug("Current state of ToDoItem", ['item' => $serializer->serialize($stateStorage->find($toDoId->getValue()))]);
 }
コード例 #15
0
 /**
  * @return void
  */
 public function run()
 {
     $logger = new Logger('default');
     // The storage device to store event data
     $eventStorage = new MemoryEventStorage();
     // A new event bus with a mapping to specify what handlers to call for what event.
     $eventBus = new SimpleEventBus([UserCreated::class => [new UserCreatedHandler($eventStorage, $logger)]]);
     $eventBus->setLogger(new EventLogger($logger));
     // An event store to store events
     $eventStore = new EventStore($eventBus, $eventStorage, new JsonSerializer(), new EventClassMap([UserCreated::class]));
     // A basic aggregate factory to be able to reconstruct the aggregate
     $factory = new GenericAggregateFactory(User::class);
     // A repository for objects of type Aggregate
     $repository = new EventSourcingRepository($factory, $eventStore);
     // A new command bus with a mapping to specify what handler to call for what command.
     $commandBus = new SimpleCommandBus([CreateUser::class => new CreateUserHandler($repository, $logger)]);
     $loggingCommandInterceptor = new LoggingInterceptor(new CommandLogger($logger));
     $commandGateway = new DefaultCommandGateway($commandBus, [$loggingCommandInterceptor]);
     // Send the command
     $commandGateway->send(new CreateUser(Identity::createNew()));
 }
コード例 #16
0
ファイル: AnnotatedSagaRunner.php プロジェクト: martyn82/apha
 /**
  * @return void
  */
 public function run()
 {
     $logger = new Logger('default');
     $eventBus = new SimpleEventBus();
     $eventBus->setLogger(new EventLogger($logger));
     $scheduler = new SimpleEventScheduler($eventBus);
     $parameterResolver = new DefaultParameterResolver();
     $factory = new ToDoSagaFactory($scheduler, $parameterResolver, $logger);
     $serializer = new JsonSerializer();
     $sagaManager = new SimpleSagaManager([ToDoSaga::class], new SagaRepository(new MemorySagaStorage(), new SagaSerializer($serializer, $factory)), new SimpleAssociationValueResolver(), $factory);
     $eventBus->addHandler(Event::class, $sagaManager);
     $eventStore = new EventStore($eventBus, new MemoryEventStorage(), $serializer, new EventClassMap([ToDoItemCreated::class, ToDoItemDone::class, DeadlineExpired::class]));
     $commandHandler = new ToDoCommandHandler(new EventSourcingRepository(new GenericAggregateFactory(ToDoItem::class), $eventStore));
     $commandBus = new SimpleCommandBus([CreateToDoItem::class => $commandHandler, MarkItemDone::class => $commandHandler]);
     $commandGateway = new DefaultCommandGateway($commandBus, [new LoggingInterceptor(new CommandLogger($logger))]);
     // Send commands to create two todoitems
     $todoItemExpireSeconds = 3;
     $toCompleteId = Identity::createNew();
     $commandGateway->send(new CreateToDoItem($toCompleteId, "Item to complete", $todoItemExpireSeconds));
     $commandGateway->send(new CreateToDoItem(Identity::createNew(), "Item to expire", $todoItemExpireSeconds));
     // Start an idling process for 5 seconds and wait for the ToDoItem to expire
     $this->idle(5, $commandGateway, $toCompleteId);
 }
コード例 #17
0
ファイル: SagaManager.php プロジェクト: martyn82/apha
 /**
  * @param Event $event
  */
 public function on(Event $event)
 {
     $handled = false;
     /* @var $sagaType string */
     foreach ($this->sagaTypes as $sagaType) {
         $associationValues = $this->extractAssociationValues($sagaType, $event);
         /* @var $associationValue AssociationValue */
         foreach ($associationValues->getIterator() as $associationValue) {
             $sagaIdentities = $this->repository->find($sagaType, $associationValue);
             /* @var $identity Identity */
             foreach ($sagaIdentities as $identity) {
                 $saga = $this->repository->load($identity, $sagaType);
                 $saga->on($event);
                 $this->commit($saga);
                 $handled = true;
             }
         }
         if ($this->getSagaCreationPolicy($sagaType, $event) == SagaCreationPolicy::ALWAYS || !$handled && $this->getSagaCreationPolicy($sagaType, $event) == SagaCreationPolicy::IF_NONE_FOUND) {
             $saga = $this->factory->createSaga($sagaType, Identity::createNew(), $associationValues);
             $saga->on($event);
             $this->commit($saga);
         }
     }
 }
コード例 #18
0
ファイル: EventStoreTest.php プロジェクト: martyn82/apha
 /**
  * @test
  * @expectedException \Apha\EventStore\AggregateNotFoundException
  */
 public function getEventsForAggregateThrowsExceptionIfAggregateNotFound()
 {
     $eventBus = $this->getEventBus();
     $storage = $this->getEventStorage();
     $serializer = $this->getSerializer();
     $eventMap = $this->getEventMap();
     $aggregateId = Identity::createNew();
     $eventStore = new EventStore($eventBus, $storage, $serializer, $eventMap);
     $eventStore->getEventsForAggregate($aggregateId);
 }
コード例 #19
0
ファイル: AggregateRootTest.php プロジェクト: martyn82/apha
 public function getId() : Identity
 {
     return Identity::createNew();
 }
コード例 #20
0
ファイル: EventStore.php プロジェクト: martyn82/apha
 /**
  * @return Identity[]
  */
 public function getAggregateIds() : array
 {
     return array_map(function (string $identity) : Identity {
         return Identity::fromString($identity);
     }, $this->storage->findIdentities());
 }
コード例 #21
0
 /**
  * @test
  */
 public function playToVersionPublishesEventsUpToAVersion()
 {
     $serializer = $this->getSerializer();
     $eventClassMap = $this->getEventClassMap();
     $eventStorage = $this->getEventStorage();
     $eventBus = $this->getEventBus();
     $eventStore = $this->getEventStore($eventBus, $eventStorage, $serializer, $eventClassMap);
     $aggregateId = Identity::createNew();
     $eventVersion1 = new AggregateEventPlayerTest_Event();
     $eventVersion1->setVersion(1);
     $eventVersion2 = new AggregateEventPlayerTest_Event();
     $eventVersion2->setVersion(2);
     $events = new Events([$eventVersion1, $eventVersion2]);
     $eventStore->expects(self::any())->method('getEventsForAggregate')->with($aggregateId)->willReturn($events);
     $eventBus->expects(self::once())->method('publish');
     $eventPlayer = new AggregateEventPlayer($eventBus, $eventStore);
     $eventPlayer->playToVersion($aggregateId, 1);
 }
コード例 #22
0
 /**
  * @param Identity $aggregateId
  */
 public function __construct(Identity $aggregateId)
 {
     parent::__construct(sprintf(static::$messageTemplate, $aggregateId->getValue()));
 }
コード例 #23
0
ファイル: SagaRepositoryTest.php プロジェクト: martyn82/apha
 /**
  * @test
  */
 public function loadReturnsNullIfSagaNotFound()
 {
     $storage = $this->createStorage();
     $serializer = $this->createSerializer();
     $sagaIdentity = Identity::createNew();
     $storage->expects(self::once())->method('findById')->with($sagaIdentity->getValue())->willReturn('');
     $repository = new SagaRepository($storage, $serializer);
     $actual = $repository->load($sagaIdentity, '');
     self::assertNull($actual);
 }
コード例 #24
0
 /**
  * @test
  * @expectedException \InvalidArgumentException
  */
 public function createSagaThrowsExceptionIfSagaUnsupported()
 {
     $parameterResolver = new DefaultParameterResolver();
     $factory = new AnnotatedSagaFactory($parameterResolver);
     $factory->createSaga(\stdClass::class, Identity::createNew(), new AssociationValues([]));
 }
コード例 #25
0
ファイル: AnnotatedSagaTest.php プロジェクト: martyn82/apha
 /**
  * @test
  * @expectedException \Apha\Saga\Annotation\NoStartSagaHandlerException
  */
 public function onThrowsExceptionIfSagaCannotBeStarted()
 {
     $saga = new AnnotatedSagaTest_SagaWithoutStart(Identity::createNew());
     $saga->on(new AnnotatedSagaTest_StartSaga());
 }
コード例 #26
0
ファイル: SagaStorageTest.php プロジェクト: martyn82/apha
 /**
  * @test
  */
 public function deleteIsIdempotent()
 {
     $sagaIdentity = Identity::createNew();
     $storage = $this->createSagaStorage();
     $storage->delete($sagaIdentity->getValue());
 }
コード例 #27
0
 /**
  * @param int $count
  * @param MemoryStateStorage $storage
  * @return Document[]
  */
 public function documentsProvider(int $count, MemoryStateStorage $storage) : array
 {
     $documents = [];
     for ($i = 0; $i < $count; $i++) {
         $documents[$i] = $this->getMockBuilder(Document::class)->setMethods(['getFoo', 'getBar'])->getMockForAbstractClass();
         $storage->upsert(Identity::createNew()->getValue(), $documents[$i]);
     }
     return $documents;
 }