Skip to content

Commit

Permalink
Merge pull request #76 from Orkin/allow-add-custom-event-store
Browse files Browse the repository at this point in the history
Allow to add a custom event store to AggregateRepository
  • Loading branch information
prolic authored Apr 30, 2018
2 parents 67fa365 + 09826ff commit 624810e
Show file tree
Hide file tree
Showing 4 changed files with 204 additions and 2 deletions.
18 changes: 18 additions & 0 deletions docs/interop_factories.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,24 @@ You can also configure a custom stream name (default is `event_stream`):
]
```

You can add your custom event store too (default is `EventStore::class`):
```php
[
'prooph' => [
'event_sourcing' => [
'aggregate_repository' => [
'user_repository' => [
'repository_class' => MyUserRepository::class,
'event_store' => MyCustomEventStore::class, // <-- Custom event store service id
'aggregate_type' => MyUser::class,
'aggregate_translator' => 'user_translator',
],
],
],
],
]
```

Last but not least you can enable the so called "One-Stream-Per-Aggregate-Mode":
```php
[
Expand Down
17 changes: 15 additions & 2 deletions src/Container/Aggregate/AggregateRepositoryFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
namespace Prooph\EventSourcing\Container\Aggregate;

use Interop\Config\ConfigurationTrait;
use Interop\Config\ProvidesDefaultOptions;
use Interop\Config\RequiresConfigId;
use Interop\Config\RequiresMandatoryOptions;
use InvalidArgumentException;
Expand All @@ -23,7 +24,7 @@
use Prooph\EventStore\StreamName;
use Psr\Container\ContainerInterface;

final class AggregateRepositoryFactory implements RequiresConfigId, RequiresMandatoryOptions
final class AggregateRepositoryFactory implements RequiresConfigId, RequiresMandatoryOptions, ProvidesDefaultOptions
{
use ConfigurationTrait;

Expand Down Expand Up @@ -81,7 +82,7 @@ public function __invoke(ContainerInterface $container): AggregateRepository
throw ConfigurationException::configurationError(sprintf('Repository class %s must be a sub class of %s', $repositoryClass, AggregateRepository::class));
}

$eventStore = $container->get(EventStore::class);
$eventStore = $container->get($config['event_store']);

if (is_array($config['aggregate_type'])) {
$aggregateType = AggregateType::fromMapping($config['aggregate_type']);
Expand Down Expand Up @@ -120,4 +121,16 @@ public function mandatoryOptions(): iterable
'aggregate_translator',
];
}

/**
* Returns a list of default options, which are merged in \Interop\Config\RequiresConfig::options()
*
* @return iterable List with default options and values, can be nested
*/
public function defaultOptions(): iterable
{
return [
'event_store' => EventStore::class,
];
}
}
65 changes: 65 additions & 0 deletions tests/Container/Aggregate/AggregateRepositoryFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Prooph\EventSourcing\Container\Aggregate\AggregateRepositoryFactory;
use Prooph\EventStore\EventStore;
use Prooph\EventStore\Exception\ConfigurationException;
use ProophTest\EventSourcing\Mock\EventStoreMock;
use ProophTest\EventSourcing\Mock\RepositoryMock;
use ProophTest\EventStore\ActionEventEmitterEventStoreTestCase;
use ProophTest\EventStore\Mock\User;
Expand Down Expand Up @@ -54,6 +55,37 @@ public function it_creates_an_aggregate_from_static_call(): void
self::assertInstanceOf(RepositoryMock::class, $factory($container->reveal()));
}

/**
* @test
*/
public function it_creates_an_aggregate_from_static_call_with_custom_event_store(): void
{
$container = $this->prophesize(ContainerInterface::class);
$container->has('config')->willReturn(true);
$container->get('config')->willReturn([
'prooph' => [
'event_sourcing' => [
'aggregate_repository' => [
'repository_mock' => [
'repository_class' => RepositoryMock::class,
'event_store' => EventStoreMock::class,
'aggregate_type' => User::class,
'aggregate_translator' => 'user_translator',
],
],
],
],
]);
$container->get(EventStoreMock::class)->willReturn($this->eventStore);

$userTranslator = $this->prophesize(AggregateTranslator::class);

$container->get('user_translator')->willReturn($userTranslator->reveal());

$factory = [AggregateRepositoryFactory::class, 'repository_mock'];
self::assertInstanceOf(RepositoryMock::class, $factory($container->reveal()));
}

/**
* @test
*/
Expand Down Expand Up @@ -119,6 +151,39 @@ public function it_throws_exception_when_invalid_repository_class_given(): void
$factory->__invoke($container->reveal());
}

/**
* @test
*/
public function it_throws_exception_when_invalid_event_store_class_given(): void
{
$this->expectException(\TypeError::class);

$container = $this->prophesize(ContainerInterface::class);
$container->has('config')->willReturn(true);
$container->get('config')->willReturn([
'prooph' => [
'event_sourcing' => [
'aggregate_repository' => [
'repository_mock' => [
'repository_class' => RepositoryMock::class,
'event_store' => 'stdClass',
'aggregate_type' => User::class,
'aggregate_translator' => 'user_translator',
],
],
],
],
]);
$container->get('stdClass')->willReturn('stdClass');

$userTranslator = $this->prophesize(AggregateTranslator::class);

$container->get('user_translator')->willReturn($userTranslator->reveal());

$factory = [AggregateRepositoryFactory::class, 'repository_mock'];
self::assertInstanceOf(RepositoryMock::class, $factory($container->reveal()));
}

/**
* @test
*/
Expand Down
106 changes: 106 additions & 0 deletions tests/Mock/EventStoreMock.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php
/**
* This file is part of the prooph/event-sourcing.
* (c) 2014-2018 prooph software GmbH <contact@prooph.de>
* (c) 2015-2018 Sascha-Oliver Prolic <saschaprolic@googlemail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ProophTest\EventSourcing\Mock;

use Iterator;
use Prooph\EventStore\EventStore;
use Prooph\EventStore\Metadata\MetadataMatcher;
use Prooph\EventStore\Stream;
use Prooph\EventStore\StreamName;

final class EventStoreMock implements EventStore
{
public function updateStreamMetadata(StreamName $streamName, array $newMetadata): void
{
}

public function create(Stream $stream): void
{
}

public function appendTo(StreamName $streamName, Iterator $streamEvents): void
{
}

public function delete(StreamName $streamName): void
{
}

public function fetchStreamMetadata(StreamName $streamName): array
{
return [];
}

public function hasStream(StreamName $streamName): bool
{
return true;
}

public function load(
StreamName $streamName,
int $fromNumber = 1,
int $count = null,
MetadataMatcher $metadataMatcher = null
): Iterator {
return new \ArrayIterator();
}

public function loadReverse(
StreamName $streamName,
int $fromNumber = null,
int $count = null,
MetadataMatcher $metadataMatcher = null
): Iterator {
return new \ArrayIterator();
}

/**
* @return StreamName[]
*/
public function fetchStreamNames(
?string $filter,
?MetadataMatcher $metadataMatcher,
int $limit = 20,
int $offset = 0
): array {
return [];
}

/**
* @return StreamName[]
*/
public function fetchStreamNamesRegex(
string $filter,
?MetadataMatcher $metadataMatcher,
int $limit = 20,
int $offset = 0
): array {
return [];
}

/**
* @return string[]
*/
public function fetchCategoryNames(?string $filter, int $limit = 20, int $offset = 0): array
{
return [];
}

/**
* @return string[]
*/
public function fetchCategoryNamesRegex(string $filter, int $limit = 20, int $offset = 0): array
{
return [];
}
}

0 comments on commit 624810e

Please sign in to comment.