Ejemplo n.º 1
0
 /**
  * @return Version
  */
 public function loadApplicationVersion()
 {
     if (!$this->store->containsKey(self::APPLICATION_VERSION_KEY)) {
         return Version::fromString('0.0.0');
     }
     return $this->store->get(self::APPLICATION_VERSION_KEY);
 }
Ejemplo n.º 2
0
 /**
  * @param MigrationsGenerateCommand $command
  */
 public function migrationsGenerate(MigrationsGenerateCommand $command)
 {
     $latestAvailableVersion = $this->migrator->status()->latestAvailableVersion();
     if ($latestAvailableVersion == null) {
         $latestAvailableVersion = Version::fromString('0.0.0');
     }
     $nextVersion = $latestAvailableVersion;
     if ($command->isMajor()) {
         $nextVersion->increment(VersionIncrementType::MAJOR());
     } else {
         $nextVersion->increment(VersionIncrementType::MINOR());
     }
     $command->getIo()->writeLine('Generating migrations classes for version <c2>' . $nextVersion->__toString() . '</c2>');
     try {
         $this->migrator->generate($nextVersion);
         $command->getIo()->writeLine('The migration has been <c1>successfully generated</c1>');
     } catch (\Exception $e) {
         $command->getIo()->writeLine('<error>' . $e->getMessage() . '</error>');
     }
 }
Ejemplo n.º 3
0
 /**
  * Test migrate method.
  */
 public function testMigrate()
 {
     $this->migrationsDirectory = __DIR__ . '/../../Fixtures/Migrations';
     require_once __DIR__ . '/../../Fixtures/BlogEventSourced.php';
     // simulate an application and aggregate version state
     $currentApplicationVersion = Version::fromString('0.1.0');
     $aggregateVersion = Version::fromString('0.1.0');
     VersionManager::setCurrentApplicationVersion($currentApplicationVersion);
     VersionManager::persistVersionOfClass(PostEventSourced::class, $aggregateVersion);
     VersionManager::persistVersionOfClass(\BlogEventSourced::class, $aggregateVersion);
     // creating migration store
     $aggregates = [PostEventSourced::class, \BlogEventSourced::class];
     $migratorStore = new InMemoryMigrationStore();
     $migratorStore->persist(new Migration($aggregates, $aggregateVersion, new \DateTime()));
     // creating event store
     $eventStore = new InMemoryEventStore();
     // add the event store flow
     $postId1 = PostId::fromNative(md5(rand()));
     $postEventStream1 = new EventStream($this->streamName(PostEventSourced::class), $postId1, [new PostWasCreated($postId1, 'Best restaurants in barcelona', 'empty'), new PostTitleWasChanged($postId1, 'Best cuban restaurants in barcelona')]);
     $postId2 = PostId::fromNative(md5(rand()));
     $postEventStream2 = new EventStream($this->streamName(PostEventSourced::class), $postId2, [new PostWasCreated($postId2, 'Best things to do with children in barcelona', 'empty'), new PostTitleWasChanged($postId2, 'Things to do with children in barcelona this weekend')]);
     $eventStore->persist($postEventStream1, $aggregateVersion, $currentApplicationVersion);
     $eventStore->persist($postEventStream2, $aggregateVersion, $currentApplicationVersion);
     // fake BlogEventSourced event stream
     $postId3 = PostId::fromNative(md5(rand()));
     $postEventStream2 = new EventStream($this->streamName(\BlogEventSourced::class), $postId3, []);
     $eventStore->persist($postEventStream2, $aggregateVersion, $currentApplicationVersion);
     // creating snapshot store
     $snapshotStore = new InMemorySnapshotStore();
     // creating the migrator
     $migrator = new MigratorWithSnapshot($this->getClassMetadataFactory(), $migratorStore, $eventStore, $snapshotStore, $this->migrationsDirectory);
     $emptyMigrator = new MigratorWithSnapshot($this->getClassMetadataFactory(), $migratorStore, $eventStore, $snapshotStore, __DIR__ . '/../../Fixtures/EmptyMigrations');
     $this->given($result = $emptyMigrator->migrate())->then()->boolean($result)->isFalse();
     $this->given($status = $migrator->status())->and($nextVersion = $status->nextAvailableVersion())->then()->boolean($migratorStore->hasMigration($nextVersion))->isFalse()->variable($snapshotStore->load('post_event_sourced', $postId1, $aggregateVersion, $currentApplicationVersion))->isNull()->and()->when($result = $migrator->migrate())->and(VersionManager::setCurrentApplicationVersion($migratorStore->getLast()->version()))->then()->boolean($migratorStore->hasMigration($nextVersion))->isTrue()->boolean($result)->isTrue()->variable($snapshotStore->load('post_event_sourced', $postId1, $aggregateVersion, $nextVersion))->isNotNull()->variable($snapshotStore->load('post_event_sourced', $postId2, $aggregateVersion, $nextVersion))->isNotNull()->and()->exception(function () use($migrator) {
         // because the V1_0_0\BlogEventSourcedMigration class return an invalid stream
         $migrator->migrate();
     })->isInstanceOf(\RuntimeException::class);
 }
 /**
  * Test Get method.
  */
 public function testGet()
 {
     $this->given($store = new InMemorySnapshotStore())->and($repository = $this->createRepository($store))->and($post = PostEventSourcedFactory::create($this->faker->sentence, $this->faker->paragraph))->and($version = new Version(0, 0, 231))->and($post->setVersion($version))->and($post->changeTitle($this->faker->sentence))->and($snapshot = new Snapshot(NameResolver::resolve(get_class($post)), $post, new \DateTime()))->and($applicationVersion = Version::fromString('0.0.0'))->when($repository->persist($post))->and($store->persist($snapshot, $applicationVersion))->then()->object($repository->get($post->id()))->isEqualTo($post);
 }
Ejemplo n.º 5
0
 /**
  * Test RemoveAll method.
  */
 public function testRemoveAll()
 {
     $this->given($store = $this->createStore())->and($postId = PostId::fromNative(md5(rand())))->and($aggregateVersion = new Version())->and($applicationVersion = new Version())->then()->exception(function () use($store, $aggregateVersion, $applicationVersion) {
         $store->removeAll('posts', $aggregateVersion, $applicationVersion);
     })->isInstanceOf(\RuntimeException::class);
     $this->given($store = $this->createStore())->and($postId = PostId::fromNative(md5(rand())))->and($postId1 = PostId::fromNative(md5(rand())))->and($eventStream = new EventStream('posts', $postId, [new PostWasCreated($postId, 'foo', 'bar')]))->and($eventStream1 = new EventStream('posts', $postId1, [new PostWasCreated($postId1, 'baz', 'content')]))->and($aggregateVersion = new Version())->and($applicationVersion = new Version())->when($store->persist($eventStream, $aggregateVersion, $applicationVersion))->and($store->persist($eventStream1, $aggregateVersion, $applicationVersion))->then()->array($store->loadAll('posts', $aggregateVersion, $applicationVersion))->hasSize(2)->and()->when($store->removeAll('posts', $aggregateVersion, $applicationVersion))->then()->exception(function () use($store, $aggregateVersion, $applicationVersion) {
         // because there is no stream entry in the current application store
         $store->loadAll('posts', $aggregateVersion, $applicationVersion);
     })->isInstanceOf(\RuntimeException::class)->and()->when($applicationVersion = Version::fromString('2.1.0'))->then()->exception(function () use($store, $aggregateVersion, $applicationVersion) {
         // because there is application entry in the store
         $store->removeAll('posts', $aggregateVersion, $applicationVersion);
     })->isInstanceOf(\RuntimeException::class);
 }
Ejemplo n.º 6
0
 /**
  * @param string  $aggregateType
  * @param Version $aggregateVersion
  *
  * @return string
  */
 protected function getAggregateKey($aggregateType, Version $aggregateVersion)
 {
     return sprintf('%s_%s_%s', $aggregateType, $aggregateVersion->major(), $aggregateVersion->minor());
 }
Ejemplo n.º 7
0
 /**
  * Test Remove method.
  */
 public function testRemove()
 {
     $this->given($store = $this->createStore())->and($post = PostEventSourcedFactory::create($this->faker->sentence, $this->faker->paragraph))->and($snapshot = new Snapshot('posts', $post, new \DateTime()))->and($applicationVersion = Version::fromString('0.1.0'))->when($store->persist($snapshot, $applicationVersion))->and($store->remove('blogs', $post->id(), $post->version(), $applicationVersion))->then()->object($store->load('posts', $post->id(), $post->version(), $applicationVersion))->isEqualTo($snapshot)->and()->when($store->remove('posts', $post->id(), $post->version(), $applicationVersion))->then()->variable($store->load('posts', $post->id(), $post->version(), $applicationVersion))->isNull();
     $this->given($store = $this->createStore())->and($post = PostEventSourcedFactory::create($this->faker->sentence, $this->faker->paragraph))->and($snapshot = new Snapshot('posts', $post, new \DateTime()))->and($applicationVersion = Version::fromString('0.1.0'))->when($store->persist($snapshot, $applicationVersion))->then()->object($store->load('posts', $post->id(), $post->version(), $applicationVersion))->isEqualTo($snapshot)->and()->when($applicationVersion2 = Version::fromString('2.0.0'))->and($store->remove('posts', $post->id(), $post->version(), $applicationVersion2))->then()->object($store->load('posts', $post->id(), $post->version(), $applicationVersion))->isEqualTo($snapshot)->and()->when($store->remove('posts', $post->id(), $post->version(), $applicationVersion))->then()->variable($store->load('posts', $post->id(), $post->version(), $applicationVersion))->isNull();
 }
Ejemplo n.º 8
0
 /**
  * Test createdAt method.
  */
 public function testCreatedAt()
 {
     $this->given($migration = new Migration([], Version::fromString('2.4.0')))->then()->object($migration->createdAt())->isNotNull();
     $this->given($createdAt = new \DateTime())->given($migration = new Migration([], Version::fromString('2.4.0'), $createdAt))->then()->object($migration->createdAt())->isEqualTo($createdAt);
 }
Ejemplo n.º 9
0
 /**
  * @param $directory
  *
  * @return Version
  */
 private function directoryToVersion($directory)
 {
     $versionNumber = str_replace(array('V', '_'), array('', '.'), $directory);
     return Version::fromString($versionNumber);
 }
Ejemplo n.º 10
0
 /**
  * @param Version $version
  *
  * @return bool
  */
 public function hasMigration(Version $version)
 {
     return $this->store->containsKey($version->__toString());
 }
Ejemplo n.º 11
0
 /**
  * Test GetLast method.
  */
 public function testGetLast()
 {
     $this->given($store = $this->createStore())->and($aggregates = [PostEventSourced::class])->and($migration1 = new Migration($aggregates, Version::fromString('0.1.0'), new \DateTime()))->and($migration2 = new Migration($aggregates, Version::fromString('0.2.0'), new \DateTime()))->then()->variable($store->getLast())->isNull()->and()->when($store->persist($migration2))->and($store->persist($migration1))->then()->object($store->getLast())->isEqualTo($migration2);
 }
Ejemplo n.º 12
0
 /**
  * Test compareTo method.
  */
 public function testCompareTo()
 {
     $this->given($version1 = Version::fromString('0.1.0'))->and($version2 = Version::fromString('0.1.8'))->and($version3 = Version::fromString('1.0.0'))->and($version4 = Version::fromString('1.0.4'))->and($version5 = Version::fromString('1.3.0'))->and($version6 = Version::fromString('1.3.9'))->then()->integer($version1->compareTo($version1))->isEqualTo(0)->integer($version1->compareTo($version2))->isEqualTo(-1)->integer($version3->compareTo($version2))->isEqualTo(1)->integer($version3->compareTo($version4))->isEqualTo(-1)->integer($version6->compareTo($version5))->isEqualTo(1)->exception(function () use($version1) {
         $version1->compareTo($this);
     })->isInstanceOf(\InvalidArgumentException::class);
 }
Ejemplo n.º 13
0
 /**
  * @param Version $version
  *
  * @return string
  */
 protected function versionToDirectory(Version $version)
 {
     return sprintf('V%s', str_replace('.', '_', $version->__toString()));
 }
Ejemplo n.º 14
0
 /**
  * Test setCurrentApplicationVersion method.
  */
 public function testSetCurrentApplicationVersion()
 {
     $this->given($applicationVersion = Version::fromString('3.2.0'))->and(VersionManager::setCurrentApplicationVersion($applicationVersion))->then()->object(VersionManager::currentApplicationVersion())->isEqualTo($applicationVersion);
 }
Ejemplo n.º 15
0
 /**
  * Test LoadApplicationVersion method.
  */
 public function testLoadApplicationVersion()
 {
     $this->given($store = $this->createStore())->then()->object($store->loadApplicationVersion())->isEqualTo(Version::fromString('0.0.0'));
 }
Ejemplo n.º 16
0
 /**
  * @param string  $streamName
  * @param Version $aggregateVersion
  *
  * @return string
  */
 protected function getStreamKey($streamName, Version $aggregateVersion)
 {
     return sprintf('%s_%s_%s', $streamName, $aggregateVersion->major(), $aggregateVersion->minor());
 }
Ejemplo n.º 17
0
 /**
  * Test MigrationsStatus method.
  */
 public function testMigrationsStatus()
 {
     $this->migrationsDirectory = __DIR__ . '/../EmptyMigrations';
     $this->given($service = $this->createService())->and($command = new MigrationsStatusCommand())->and($command->setIo($this->getIO()))->when($service->migrationsStatus($command))->then()->string($this->output->fetch())->contains(' Current Version      <c2>0</c2>')->contains(' Latest Version       <c2>none</c2>')->contains(' Next Version         <c2>none</c2>')->contains(' Executed Migrations  <c2>0</c2>')->contains(' Available Migrations <c2>0</c2>')->contains(' New Migrations       <c2>0</c2>');
     $this->migrationsDirectory = __DIR__ . '/../../../Fixtures/Event';
     $this->given($service = $this->createService())->and($command = new MigrationsStatusCommand())->and($command->setIo($this->getIO()))->when($service->migrationsStatus($command))->then()->string($this->output->fetch())->contains('Invalid migration directory');
     $this->migrationsDirectory = __DIR__ . '/../../../Fixtures/Migrations';
     $this->given($service = $this->createService())->and($command = new MigrationsStatusCommand())->and($command->setIo($this->getIO()))->when($service->migrationsStatus($command))->then()->string($this->output->fetch())->contains(' Current Version      <c2>0</c2>')->contains(' Latest Version       <c2>1.1.0</c2>')->contains(' Next Version         <c2>0.1.0</c2>')->contains(' Executed Migrations  <c2>0</c2>')->contains(' Available Migrations <c2>4</c2>')->contains(' New Migrations       <c2>4</c2>');
     require_once __DIR__ . '/../../../Fixtures/BlogEventSourced.php';
     $aggregates = [PostEventSourced::class, \BlogEventSourced::class];
     $migratorStore = new InMemoryMigrationStore();
     $migratorStore->persist(new Migration($aggregates, Version::fromString('0.1.0'), \DateTime::createFromFormat('Y-m-d H:i:s', '2016-08-26 14:12:00')));
     $migratorStore->persist(new Migration($aggregates, Version::fromString('0.2.0'), \DateTime::createFromFormat('Y-m-d H:i:s', '2016-09-01 18:30:00')));
     $migrator = new Migrator($this->getClassMetadataFactory(), $migratorStore, new InMemoryEventStore(), $this->migrationsDirectory);
     $service = new MigrationsService($migrator);
     $this->given($command = new MigrationsStatusCommand())->and($command->setIo($this->getIO()))->when($service->migrationsStatus($command))->then()->string($this->output->fetch())->contains(' Current Version      <c2>0.2.0 (2016-09-01 18:30:00)</c2>')->contains(' Latest Version       <c2>1.1.0</c2>')->contains(' Next Version         <c2>1.0.0</c2>')->contains(' Executed Migrations  <c2>2</c2>')->contains(' Available Migrations <c2>4</c2>')->contains(' New Migrations       <c2>2</c2>');
 }
Ejemplo n.º 18
0
 /**
  * Test RegisterMigration method.
  */
 public function testRegisterMigration()
 {
     $this->given($manager = $this->createManager())->then()->exception(function () use($manager) {
         $manager->registerMigration([], Version::fromString('0.2.0'));
     })->isInstanceOf(\RuntimeException::class);
 }
Ejemplo n.º 19
0
 /**
  * @return bool
  */
 public function migrate()
 {
     $nextMigration = $this->migrationManager()->nextMigrationToExecute();
     $currentApplicationVersion = VersionManager::currentApplicationVersion();
     if ($nextMigration !== null) {
         foreach ($nextMigration->aggregates() as $aggregateMigrationClass) {
             // -- start current application context --
             /** @var MigrationInterface $migrationClass */
             $migrationClass = new $aggregateMigrationClass();
             $aggregateClassName = $migrationClass->aggregateClassName();
             $currentAggregateVersion = VersionManager::versionOfClass($aggregateClassName, $currentApplicationVersion);
             // get all event streams for this aggregate class name
             $eventStreams = $this->eventStore->loadAll($this->streamName($aggregateClassName), $currentAggregateVersion, $currentApplicationVersion);
             // -- end current application context --
             // -- start new version context --
             $nextApplicationVersion = $nextMigration->version();
             // iterate for every aggregateRoot event stream
             foreach ($eventStreams as $aggregateRootEventStream) {
                 // migrate the current aggregate event stream
                 $newAggregateRootEventStream = $migrationClass->migrate($aggregateRootEventStream);
                 if ($newAggregateRootEventStream === null || $newAggregateRootEventStream !== null && !$newAggregateRootEventStream instanceof EventStream) {
                     throw new \RuntimeException(sprintf('Invalid migration class %s. The migration method should return the new EventStream', $aggregateMigrationClass));
                 }
                 // calculate the new version for every event
                 $pathVersion = 0;
                 foreach ($newAggregateRootEventStream->events() as $event) {
                     $event->setVersion(++$pathVersion);
                 }
                 // and the new version for this aggregateRoot
                 $newAggregateRootVersion = Version::fromString($nextMigration->version()->__toString());
                 $newAggregateRootVersion->setPatch($pathVersion);
                 // persist the new event stream for this aggregateRoot.
                 $this->migrateAggregateRoot($aggregateClassName, $newAggregateRootEventStream, $newAggregateRootVersion, $nextApplicationVersion);
             }
             // persist the new version of this aggregate class in the VersionManager
             VersionManager::persistVersionOfClass($aggregateClassName, $nextMigration->version(), $nextApplicationVersion);
             // -- end new version context --
         }
         // persist the new migration in the store
         $this->migrationManager->persistMigration($nextMigration);
         return true;
     }
     return false;
 }
Ejemplo n.º 20
0
 /**
  * Test numNewMigrations method.
  */
 public function testNumNewMigrations()
 {
     $this->given($status = new Status())->then()->integer($status->numNewMigrations())->isEqualTo(0);
     $this->given($migration = new Migration([], Version::fromString('2.4.0')))->and($status = new Status(Version::fromString('1.8.0'), Version::fromString('2.1.0'), $migration, 0, 0, 3))->then()->integer($status->numNewMigrations())->isEqualTo(3);
 }
 /**
  * Test ShouldCreateSnapshot method.
  */
 public function testShouldCreateSnapshot()
 {
     $this->given($snapshotStore = new InMemorySnapshotStore())->and($policy = new TimeBasedSnapshottingPolicy($snapshotStore, PostEventSourced::class, '1 hour'))->and($post = PostEventSourcedFactory::create($this->faker->sentence, $this->faker->paragraph))->and($createdAt = date_create()->modify('-2 hours'))->and($snapshot = new Snapshot(NameResolver::resolve(get_class($post)), $post, $createdAt))->and($applicationVersion = Version::fromString('0.0.0'))->and($snapshotStore->persist($snapshot, $applicationVersion))->then()->boolean($policy->shouldCreateSnapshot($post))->isTrue()->and()->when($post->clearEvents())->then()->boolean($policy->shouldCreateSnapshot($post))->isFalse();
     $this->given($snapshotStore = new InMemorySnapshotStore())->and($policy = new TimeBasedSnapshottingPolicy($snapshotStore, PostEventSourced::class, '1 hour'))->and($post = PostEventSourcedFactory::create($this->faker->sentence, $this->faker->paragraph))->and($createdAt = new \DateTime())->and($snapshot = new Snapshot(NameResolver::resolve(get_class($post)), $post, $createdAt))->and($applicationVersion = Version::fromString('0.1.0'))->and($snapshotStore->persist($snapshot, $applicationVersion))->then()->boolean($policy->shouldCreateSnapshot($post))->isFalse();
 }