Skip to content

Commit

Permalink
Merge pull request #64 from stefangr/fix-55
Browse files Browse the repository at this point in the history
Make ProjectionManagerFactory handle decorated EventStores
  • Loading branch information
codeliner committed Oct 5, 2019
2 parents bf93ffa + 6a181f7 commit edb117c
Show file tree
Hide file tree
Showing 2 changed files with 169 additions and 5 deletions.
32 changes: 27 additions & 5 deletions src/ProjectionManagerFactory.php
Expand Up @@ -14,6 +14,7 @@
use PDO;
use Prooph\Bundle\EventStore\Exception\RuntimeException;
use Prooph\EventStore\EventStore;
use Prooph\EventStore\EventStoreDecorator;
use Prooph\EventStore\InMemoryEventStore;
use Prooph\EventStore\Pdo\MariaDbEventStore;
use Prooph\EventStore\Pdo\MySqlEventStore;
Expand All @@ -40,22 +41,43 @@ public function createProjectionManager(
return $connection;
};

if ($eventStore instanceof InMemoryEventStore) {
$realEventStore = $this->getTheRealEventStore($eventStore);

if ($realEventStore instanceof InMemoryEventStore) {
return new InMemoryProjectionManager($eventStore);
}

if ($eventStore instanceof PostgresEventStore) {
if ($realEventStore instanceof PostgresEventStore) {
return new PostgresProjectionManager($eventStore, $checkConnection(), $eventStreamsTable, $projectionsTable);
}

if ($eventStore instanceof MySqlEventStore) {
if ($realEventStore instanceof MySqlEventStore) {
return new MySqlProjectionManager($eventStore, $checkConnection(), $eventStreamsTable, $projectionsTable);
}

if ($eventStore instanceof MariaDbEventStore) {
if ($realEventStore instanceof MariaDbEventStore) {
return new MariaDbProjectionManager($eventStore, $checkConnection(), $eventStreamsTable, $projectionsTable);
}

throw new RuntimeException(\sprintf('ProjectionManager for %s not implemented.', \get_class($eventStore)));
throw new RuntimeException(\sprintf('ProjectionManager for %s not implemented.', \get_class($realEventStore)));
}

/**
* Gets the "real" event store in case we were provided with an EventStoreDecorator.
* That's the one that will really perfom the actions.
*
* @param EventStore $eventStore
*
* @return EventStore
*/
private function getTheRealEventStore(EventStore $eventStore): EventStore
{
$realEventStore = $eventStore;

while ($realEventStore instanceof EventStoreDecorator) {
$realEventStore = $realEventStore->getInnerEventStore();
}

return $realEventStore;
}
}
142 changes: 142 additions & 0 deletions test/ProjectionManagerFactoryTest.php
@@ -0,0 +1,142 @@
<?php

declare(strict_types=1);

namespace ProophTest\Bundle\EventStore;

use PDO;
use PHPUnit\Framework\TestCase;
use Prooph\Bundle\EventStore\Exception\RuntimeException;
use Prooph\Bundle\EventStore\ProjectionManagerFactory;
use Prooph\Common\Messaging\MessageFactory;
use Prooph\EventStore\EventStore;
use Prooph\EventStore\EventStoreDecorator;
use Prooph\EventStore\InMemoryEventStore;
use Prooph\EventStore\Pdo\MariaDbEventStore;
use Prooph\EventStore\Pdo\MySqlEventStore;
use Prooph\EventStore\Pdo\PersistenceStrategy;
use Prooph\EventStore\Pdo\PostgresEventStore;
use Prooph\EventStore\Pdo\Projection\MariaDbProjectionManager;
use Prooph\EventStore\Pdo\Projection\MySqlProjectionManager;
use Prooph\EventStore\Pdo\Projection\PostgresProjectionManager;
use Prooph\EventStore\Projection\InMemoryProjectionManager;

class ProjectionManagerFactoryTest extends TestCase
{
/**
* @var ProjectionManagerFactory
*/
private $sut;

protected function setUp()
{
$this->sut = new ProjectionManagerFactory();
}

/**
* @test
*/
public function it_should_not_accept_an_unknown_event_store()
{
$unknownEventStore = $this->getMockForAbstractClass(EventStore::class);

$this->expectException(RuntimeException::class);
$this->expectExceptionMessage(\sprintf(
'ProjectionManager for %s not implemented.',
\get_class($unknownEventStore)
));

$this->sut->createProjectionManager($unknownEventStore);
}

/**
* @test
* @dataProvider provideEventStores
*/
public function it_should_create_a_projection_manager(
string $expectedProjectionManagerType,
EventStore $eventStore
) {
$connection = $this->createAPdoObject();
$projectionManager = $this->sut->createProjectionManager($eventStore, $connection);

$this->assertInstanceOf($expectedProjectionManagerType, $projectionManager);
}

public function provideEventStores(): array
{
$postgresEventStore = $this->createAnEventStore(PostgresEventStore::class);
$singleLevelEventStoreDecorator = $this->createAnEventStoreDecorator($postgresEventStore);
$multiLevelEventStoreDecorator = $this->createAnEventStoreDecorator($singleLevelEventStoreDecorator);

$eventStores = [
'InMemoryEventStore' => [
InMemoryProjectionManager::class,
$this->createAnEventStore(InMemoryEventStore::class),
],
'PostgresEventStore' => [
PostgresProjectionManager::class,
$postgresEventStore,
],
'MySqlEventStore' => [
MySqlProjectionManager::class,
$this->createAnEventStore(MySqlEventStore::class),
],
'Single level EventStoreDecorator' => [
PostgresProjectionManager::class,
$singleLevelEventStoreDecorator,
],
'Multi level InMemoryEventStore' => [
PostgresProjectionManager::class,
$multiLevelEventStoreDecorator,
],
];

if (\class_exists(MariaDbEventStore::class)) {
$eventStores['MariaDbEventStore'] = [
MariaDbProjectionManager::class,
$this->createAnEventStore(MariaDbEventStore::class),
];
}

return $eventStores;
}

private function createAnEventStore(string $type): EventStore
{
if (InMemoryEventStore::class === $type) {
return new InMemoryEventStore();
}

return new $type(
$this->createAMessageFactory(),
$this->createAPdoObject(),
$this->createAPersistenceStrategy()
);
}

private function createAMessageFactory(): MessageFactory
{
return $this->getMockForAbstractClass(MessageFactory::class);
}

private function createAPdoObject(): PDO
{
return $this->createMock(PDO::class);
}

private function createAPersistenceStrategy(): PersistenceStrategy
{
return $this->getMockForAbstractClass(PersistenceStrategy::class);
}

private function createAnEventStoreDecorator(EventStore $decoratedEventStore): EventStoreDecorator
{
$eventStoreDecorator = $this->getMockForAbstractClass(EventStoreDecorator::class);
$eventStoreDecorator->expects($this->any())
->method('getInnerEventStore')
->willReturn($decoratedEventStore);

return $eventStoreDecorator;
}
}

0 comments on commit edb117c

Please sign in to comment.