Skip to content

Commit

Permalink
projection options
Browse files Browse the repository at this point in the history
- I was not able to pass projection options when defining projections so it couldn't be used when running projection with console command
  • Loading branch information
unixslayer committed Jul 29, 2020
1 parent 70b6e6d commit 0936674
Show file tree
Hide file tree
Showing 15 changed files with 116 additions and 8 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,13 @@
"symfony/dependency-injection": "^3.4 || ^4.4 || ^5.0",
"symfony/http-kernel": "^3.4 || ^4.4 || ^5.0",
"symfony/framework-bundle": "^3.4 || ^4.4 || ^5.0",
"symfony/messenger": "^4.2 || ^4.4 || ^5.0",
"prooph/event-store": "^7.0"
},
"require-dev": {
"prooph/event-sourcing": "^5.0",
"prooph/snapshot-store": "^1.0",
"prooph/pdo-event-store": "^1.0",
"prooph/pdo-event-store": "^1.12",
"phpunit/phpunit": "^7 || ^8",
"symfony/yaml" : "^3.4 || ^4.4 || ^5.0",
"bookdown/bookdown": "1.x-dev as 1.0.0",
Expand Down
14 changes: 11 additions & 3 deletions src/Command/AbstractProjectionCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,21 @@ abstract class AbstractProjectionCommand extends Command
*/
protected $projectionReadModelLocator;

/**
* @var ContainerInterface
*/
protected $projectionOptionsLocator;

public function __construct(
ContainerInterface $projectionManagerForProjectionsLocator,
ContainerInterface $projectionsLocator,
ContainerInterface $projectionReadModelLocator
ContainerInterface $projectionReadModelLocator,
ContainerInterface $projectionOptionsLocator
) {
$this->projectionManagerForProjectionsLocator = $projectionManagerForProjectionsLocator;
$this->projectionsLocator = $projectionsLocator;
$this->projectionReadModelLocator = $projectionReadModelLocator;
$this->projectionOptionsLocator = $projectionOptionsLocator;

parent::__construct();
}
Expand All @@ -97,18 +104,19 @@ protected function initialize(InputInterface $input, OutputInterface $output): v
throw new RuntimeException(\vsprintf('Projection "%s" not found', \is_array($this->projectionName) ? $this->projectionName : [$this->projectionName]));
}
$this->projection = $this->projectionsLocator->get($this->projectionName);
$projectionOptions = $this->projectionOptionsLocator->has($this->projectionName) ? $this->projectionOptionsLocator->get($this->projectionName)->options() : [];

if ($this->projection instanceof ReadModelProjection) {
if (! $this->projectionReadModelLocator->has($this->projectionName)) {
throw new RuntimeException(\vsprintf('ReadModel for "%s" not found', \is_array($this->projectionName) ? $this->projectionName : [$this->projectionName]));
}
$this->readModel = $this->projectionReadModelLocator->get($this->projectionName);

$this->projector = $this->projectionManager->createReadModelProjection($this->projectionName, $this->readModel);
$this->projector = $this->projectionManager->createReadModelProjection($this->projectionName, $this->readModel, $projectionOptions);
}

if ($this->projection instanceof Projection) {
$this->projector = $this->projectionManager->createProjection($this->projectionName);
$this->projector = $this->projectionManager->createProjection($this->projectionName, $projectionOptions);
}

if (null === $this->projector) {
Expand Down
4 changes: 4 additions & 0 deletions src/DependencyInjection/Compiler/RegisterProjectionsPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public function process(ContainerBuilder $container): void
if (! $container->hasDefinition('prooph_event_store.projection_read_models_locator')
|| ! $container->hasDefinition('prooph_event_store.projection_manager_for_projections_locator')
|| ! $container->hasDefinition('prooph_event_store.projections_locator')
|| ! $container->hasDefinition('prooph_event_store.projection_options_locator')
) {
return;
}
Expand All @@ -36,6 +37,7 @@ public function process(ContainerBuilder $container): void
$readModelsLocator = [];
$projectionManagerForProjectionsLocator = [];
$projectionsLocator = [];
$projectionOptionsLocator = [];

foreach ($projectionIds as $id) {
$projectorDefinition = $container->getDefinition($id);
Expand All @@ -62,10 +64,12 @@ public function process(ContainerBuilder $container): void
\sprintf('prooph_event_store.projection_manager.%s', $tag['projection_manager'])
);
$projectionsLocator[$tag['projection_name']] = new Reference($id);
$projectionOptionsLocator[$tag['projection_name']] = new Reference($id);
}
}

self::addServicesToLocator($container, 'prooph_event_store.projections_locator', $projectionsLocator);
self::addServicesToLocator($container, 'prooph_event_store.projection_options_locator', $projectionOptionsLocator);
self::addServicesToLocator($container, 'prooph_event_store.projection_read_models_locator', $readModelsLocator);
self::addServicesToLocator(
$container,
Expand Down
7 changes: 7 additions & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ public function addProjectionManagerSection(ArrayNodeDefinition $node): void
->then($removeFirstCharacter)
->end()
->end()
->arrayNode('options')
->canBeUnset()
->addDefaultsIfNotSet()
->treatFalseLike([])
->treatNullLike([])
->ignoreExtraKeys(false)
->end()
->end();

$node
Expand Down
35 changes: 31 additions & 4 deletions src/DependencyInjection/ProophEventStoreExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,20 @@ private static function loadProjectionManagers(array $config, ContainerBuilder $
$projectionManagerForProjectionsLocator = [];
$projectionsLocator = [];
$readModelsLocator = [];
$projectionOptionsLocator = [];

foreach ($config['projection_managers'] as $projectionManagerName => $projectionManagerConfig) {
$projectionManagerId = "prooph_event_store.projection_manager.$projectionManagerName";
self::defineProjectionManager($container, $projectionManagerId, $projectionManagerConfig);

[$projectionManagerForProjectionsLocator, $projectionsLocator, $readModelsLocator] = self::collectProjectionsForLocators(
[$projectionManagerForProjectionsLocator, $projectionsLocator, $readModelsLocator, $projectionOptionsLocator] = self::collectProjectionsForLocators(
$container,
$projectionManagerConfig['projections'],
$projectionManagerId,
$projectionManagerForProjectionsLocator,
$projectionsLocator,
$readModelsLocator
$readModelsLocator,
$projectionOptionsLocator
);

$projectionManagers[$projectionManagerName] = "prooph_event_store.$projectionManagerName";
Expand All @@ -83,6 +86,7 @@ private static function loadProjectionManagers(array $config, ContainerBuilder $
self::defineServiceLocator($container, 'prooph_event_store.projection_manager_for_projections_locator', $projectionManagerForProjectionsLocator);
self::defineServiceLocator($container, 'prooph_event_store.projection_read_models_locator', $readModelsLocator);
self::defineServiceLocator($container, 'prooph_event_store.projections_locator', $projectionsLocator);
self::defineServiceLocator($container, 'prooph_event_store.projection_options_locator', $projectionOptionsLocator);
}

private static function defineProjectionManager(ContainerBuilder $container, string $serviceId, array $config): void
Expand All @@ -108,11 +112,13 @@ private static function defineServiceLocator(ContainerBuilder $container, string
}

private static function collectProjectionsForLocators(
ContainerBuilder $container,
array $projections,
string $projectionManagerId,
array $projectionManagerForProjectionsLocator,
array $projectionsLocator,
array $readModelsLocator
array $readModelsLocator,
array $projectionOptionsLocator
): array {
foreach ($projections as $projectionName => $projectionConfig) {
if (isset($projectionConfig['read_model'])) {
Expand All @@ -121,9 +127,30 @@ private static function collectProjectionsForLocators(

$projectionsLocator[$projectionName] = new Reference($projectionConfig['projection']);
$projectionManagerForProjectionsLocator[$projectionName] = new Reference($projectionManagerId);

$projectionOptionsId = \sprintf('prooph_event_store.projection_options.%s', $projectionName);
self::defineProjectionOptions($container, $projectionOptionsId, $projectionConfig['options']);
$projectionOptionsLocator[$projectionName] = new Reference($projectionOptionsId);
}

return [$projectionManagerForProjectionsLocator, $projectionsLocator, $readModelsLocator];
return [$projectionManagerForProjectionsLocator, $projectionsLocator, $readModelsLocator, $projectionOptionsLocator];
}

private static function defineProjectionOptions(ContainerBuilder $container, string $serviceId, array $projectionOptions): void
{
$projectionOptions = \array_map(function ($value) use ($container) {
if ($container->has($value)) {
$value = new Reference($value);
}

return $value;
}, $projectionOptions);

$definition = new ChildDefinition('prooph_event_store.projection_options');
$definition->setFactory([new Reference('prooph_event_store.projection_options_factory'), 'createProjectionOptions']);
$definition->setArguments([$projectionOptions]);

$container->setDefinition($serviceId, $definition);
}

/**
Expand Down
23 changes: 23 additions & 0 deletions src/Projection/ProjectionOptions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Prooph\Bundle\EventStore\Projection;

final class ProjectionOptions
{
/**
* @var array
*/
private $options;

public function __construct(array $options)
{
$this->options = $options;
}

public function options(): array
{
return $this->options;
}
}
13 changes: 13 additions & 0 deletions src/Projection/ProjectionOptionsFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Prooph\Bundle\EventStore\Projection;

final class ProjectionOptionsFactory
{
public static function createProjectionOptions(array $options): ProjectionOptions
{
return new ProjectionOptions($options);
}
}
4 changes: 4 additions & 0 deletions src/Resources/config/event_store.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
<factory service="prooph_event_store.projection_factory" method="createProjectionManager" />
</service>
<service id="prooph_event_store.projection_factory" class="Prooph\Bundle\EventStore\ProjectionManagerFactory"/>
<service id="prooph_event_store.projection_options" class="Prooph\Bundle\EventStore\Projection\ProjectionOptions" abstract="true" public="true" />
<service id="prooph_event_store.projection_options_factory" class="Prooph\Bundle\EventStore\Projection\ProjectionOptionsFactory"/>
<service id="prooph_event_store.repository_definition" class="Prooph\EventSourcing\Aggregate\AggregateRepository" abstract="true" public="true">
<factory service="prooph_event_store.repository_factory" method="create" />
</service>
Expand All @@ -34,6 +36,7 @@
<argument type="service" id="prooph_event_store.projection_manager_for_projections_locator" />
<argument type="service" id="prooph_event_store.projections_locator" />
<argument type="service" id="prooph_event_store.projection_read_models_locator" />
<argument type="service" id="prooph_event_store.projection_options_locator" />
</service>

<service id="Prooph\Bundle\EventStore\Command\ProjectionDeleteCommand"
Expand Down Expand Up @@ -71,5 +74,6 @@
parent="Prooph\Bundle\EventStore\Command\AbstractProjectionCommand">
<tag name="console.command" command="event-store:projection:positions" />
</service>
<service id="Prooph\EventStore\Pdo\Projection\GapDetection" />
</services>
</container>
4 changes: 4 additions & 0 deletions test/Command/Fixture/config/projections.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ prooph_event_store:
projections:
black_hole_projection:
projection: ProophTest\Bundle\EventStore\Command\Fixture\Projection\BlackHoleProjection
options:
gap_detection: Prooph\EventStore\Pdo\Projection\GapDetection
black_hole_read_model_projection:
projection: ProophTest\Bundle\EventStore\Command\Fixture\Projection\BlackHoleReadModelProjection
read_model: ProophTest\Bundle\EventStore\Command\Fixture\Projection\BlackHoleReadModel
options:
gap_detection: Prooph\EventStore\Pdo\Projection\GapDetection

services:
Prooph\EventStore\InMemoryEventStore:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ public function it_can_register_projections_centrally(): void
$managerLocator = $container->get('test.prooph_event_store.projection_manager_for_projections_locator');
$projectionsLocator = $container->get('test.prooph_event_store.projections_locator');
$readModelLocator = $container->get('test.prooph_event_store.projection_read_models_locator');
$projectionOptionsLocator = $container->get('test.prooph_event_store.projection_options_locator');

self::assertTrue(
$managerLocator->has('todo_projection'),
Expand All @@ -186,6 +187,10 @@ public function it_can_register_projections_centrally(): void
$readModelLocator->has('todo_projection'),
'The read model for the todo_projection is not available through the dedicated service locator'
);
self::assertTrue(
$projectionOptionsLocator->has('todo_projection'),
'The projection options for the todo_projection is not available through the dedicated service locator'
);
}

/** @test */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ protected function setUp(): void
$this->registerEmptyServiceLocator('prooph_event_store.projection_manager_for_projections_locator');
$this->registerEmptyServiceLocator('prooph_event_store.projection_read_models_locator');
$this->registerEmptyServiceLocator('prooph_event_store.projections_locator');
$this->registerEmptyServiceLocator('prooph_event_store.projection_options_locator');
}

/** @test */
Expand Down
1 change: 1 addition & 0 deletions test/DependencyInjection/ConfigurationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public function it_allows_to_prefix_services_with_an_at(string $configFile): voi
'todo_projection' => [
'read_model' => TodoReadModel::class,
'projection' => TodoProjection::class,
'options' => [],
],
],
'event_streams_table' => 'event_streams',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

<srv:service id="test.prooph_event_store.projection_manager_for_projections_locator" alias="prooph_event_store.projection_manager_for_projections_locator" public="true" />
<srv:service id="test.prooph_event_store.projections_locator" alias="prooph_event_store.projections_locator" public="true" />
<srv:service id="test.prooph_event_store.projection_options_locator" alias="prooph_event_store.projection_options_locator" public="true" />
<srv:service id="test.prooph_event_store.projection_read_models_locator" alias="prooph_event_store.projection_read_models_locator" public="true" />
</srv:services>
</srv:container>
7 changes: 7 additions & 0 deletions test/DependencyInjection/Fixture/config/yml/projections.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ prooph_event_store:
todo_projection:
read_model: 'ProophTest\Bundle\EventStore\DependencyInjection\Fixture\Projection\TodoReadModel'
projection: 'ProophTest\Bundle\EventStore\DependencyInjection\Fixture\Projection\TodoProjection'
options:
gap_detection: 'Prooph\EventStore\Pdo\Projection\GapDetection'

services:
Prooph\EventStore\InMemoryEventStore:
Expand All @@ -17,6 +19,7 @@ services:

ProophTest\Bundle\EventStore\DependencyInjection\Fixture\Projection\TodoReadModel: ~
ProophTest\Bundle\EventStore\DependencyInjection\Fixture\Projection\TodoProjection: ~
Prooph\EventStore\Pdo\Projection\GapDetection: ~

test.prooph_event_store.projection_manager_for_projections_locator:
alias: prooph_event_store.projection_manager_for_projections_locator
Expand All @@ -26,6 +29,10 @@ services:
alias: prooph_event_store.projections_locator
public: true

test.prooph_event_store.projection_options_locator:
alias: prooph_event_store.projection_options_locator
public: true

test.prooph_event_store.projection_read_models_locator:
alias: prooph_event_store.projection_read_models_locator
public: true
2 changes: 2 additions & 0 deletions test/Resources/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ services:
'ProophTest\Bundle\EventStore\DependencyInjection\Fixture\Model\BlackHoleAggregateTranslator':
class: ProophTest\Bundle\EventStore\DependencyInjection\Fixture\Model\BlackHoleAggregateTranslator
public: true

Prooph\EventStore\Pdo\Projection\GapDetection: ~

0 comments on commit 0936674

Please sign in to comment.