Skip to content

Commit

Permalink
TASK: Catchups will only be able to access the state of the projectio…
Browse files Browse the repository at this point in the history
…n they are registered for

A catchup doesn't have access to the full content repository, as it would allow full recursion via handle and accessing other projections
state is not safe as the other projection might not be behind - the order is undefined.

This will make it possible to catchup projections from outside of the cr instance as proposed here: neos/neos-development-collection#5321
  • Loading branch information
mhsdesign committed Nov 2, 2024
1 parent 6f2890e commit 347322e
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 11 deletions.
2 changes: 1 addition & 1 deletion Classes/ContentRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ public function catchUpProjection(string $projectionClassName, CatchUpOptions $o
$projection = $this->projectionsAndCatchUpHooks->projections->get($projectionClassName);

$catchUpHookFactory = $this->projectionsAndCatchUpHooks->getCatchUpHookFactoryForProjection($projection);
$catchUpHook = $catchUpHookFactory?->build($this);
$catchUpHook = $catchUpHookFactory?->build($this->id, $projection->getState());

// TODO allow custom stream name per projection
$streamName = VirtualStreamName::all();
Expand Down
6 changes: 3 additions & 3 deletions Classes/Factory/ProjectionsAndCatchUpHooksFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@

use Neos\ContentRepository\Core\Projection\CatchUpHookFactories;
use Neos\ContentRepository\Core\Projection\CatchUpHookFactoryInterface;
use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphProjectionInterface;
use Neos\ContentRepository\Core\Projection\ProjectionFactoryInterface;
use Neos\ContentRepository\Core\Projection\ProjectionInterface;
use Neos\ContentRepository\Core\Projection\Projections;
use Neos\ContentRepository\Core\Projection\ProjectionsAndCatchUpHooks;
use Neos\ContentRepository\Core\Projection\ProjectionStateInterface;
use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphProjectionInterface;

/**
* @api for custom framework integrations, not for users of the CR
*/
final class ProjectionsAndCatchUpHooksFactory
{
/**
* @var array<string, array{factory: ProjectionFactoryInterface<ProjectionInterface<ProjectionStateInterface>>, options: array<string, mixed>, catchUpHooksFactories: array<CatchUpHookFactoryInterface>}>
* @var array<string, array{factory: ProjectionFactoryInterface<ProjectionInterface<ProjectionStateInterface>>, options: array<string, mixed>, catchUpHooksFactories: array<CatchUpHookFactoryInterface<ProjectionStateInterface>>}>
*/
private array $factories = [];

Expand All @@ -40,7 +40,7 @@ public function registerFactory(ProjectionFactoryInterface $factory, array $opti

/**
* @param ProjectionFactoryInterface<ProjectionInterface<ProjectionStateInterface>> $factory
* @param CatchUpHookFactoryInterface $catchUpHookFactory
* @param CatchUpHookFactoryInterface<ProjectionStateInterface> $catchUpHookFactory
* @return void
* @api
*/
Expand Down
16 changes: 12 additions & 4 deletions Classes/Projection/CatchUpHookFactories.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,22 @@

namespace Neos\ContentRepository\Core\Projection;

use Neos\ContentRepository\Core\ContentRepository;
use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId;

/**
* @implements CatchUpHookFactoryInterface<ProjectionStateInterface>
* @internal
*/
final class CatchUpHookFactories implements CatchUpHookFactoryInterface
{
/**
* @var array<mixed,CatchUpHookFactoryInterface>
* @var array<mixed,CatchUpHookFactoryInterface<ProjectionStateInterface>>
*/
private array $catchUpHookFactories;

/**
* @param CatchUpHookFactoryInterface<ProjectionStateInterface> ...$catchUpHookFactories
*/
private function __construct(CatchUpHookFactoryInterface ...$catchUpHookFactories)
{
$this->catchUpHookFactories = $catchUpHookFactories;
Expand All @@ -26,6 +30,10 @@ public static function create(): self
return new self();
}

/**
* @param CatchUpHookFactoryInterface<ProjectionStateInterface> $catchUpHookFactory
* @return self
*/
public function with(CatchUpHookFactoryInterface $catchUpHookFactory): self
{
if ($this->has($catchUpHookFactory::class)) {
Expand All @@ -44,9 +52,9 @@ private function has(string $catchUpHookFactoryClassName): bool
return array_key_exists($catchUpHookFactoryClassName, $this->catchUpHookFactories);
}

public function build(ContentRepository $contentRepository): CatchUpHookInterface
public function build(ContentRepositoryId $contentRepositoryId, ProjectionStateInterface $projectionState): CatchUpHookInterface
{
$catchUpHooks = array_map(static fn(CatchUpHookFactoryInterface $catchUpHookFactory) => $catchUpHookFactory->build($contentRepository), $this->catchUpHookFactories);
$catchUpHooks = array_map(static fn(CatchUpHookFactoryInterface $catchUpHookFactory) => $catchUpHookFactory->build($contentRepositoryId, $projectionState), $this->catchUpHookFactories);
return new DelegatingCatchUpHook(...$catchUpHooks);
}
}
13 changes: 11 additions & 2 deletions Classes/Projection/CatchUpHookFactoryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,21 @@

namespace Neos\ContentRepository\Core\Projection;

use Neos\ContentRepository\Core\ContentRepository;
use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId;

/**
* @template T of ProjectionStateInterface
* @api
*/
interface CatchUpHookFactoryInterface
{
public function build(ContentRepository $contentRepository): CatchUpHookInterface;
/**
* Note that a catchup doesn't have access to the full content repository, as it would allow full recursion via handle and accessing other projections
* state is not safe as the other projection might not be behind - the order is undefined.
*
* @param ContentRepositoryId $contentRepositoryId the content repository the catchup was registered in
* @param ProjectionStateInterface&T $projectionState the state of the projection the catchup was registered to (Its only safe to access this projections state)
* @return CatchUpHookInterface
*/
public function build(ContentRepositoryId $contentRepositoryId, ProjectionStateInterface $projectionState): CatchUpHookInterface;
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@
use Neos\ContentRepository\Core\SharedModel\Workspace\Workspaces;

/**
* @api for creating a custom content repository graph projection implementation, **not for users of the CR**
* This low level interface gives access to the content graph and workspaces
*
* Generally this is not accessible for users of the CR, except for registering a catchup-hook on the content graph
*
* @api as dependency in catchup hooks and for creating a custom content repository graph projection implementation
*/
interface ContentGraphReadModelInterface extends ProjectionStateInterface
{
Expand Down
1 change: 1 addition & 0 deletions Classes/Projection/ProjectionsAndCatchUpHooks.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public function __construct(

/**
* @param ProjectionInterface<ProjectionStateInterface> $projection
* @return ?CatchUpHookFactoryInterface<ProjectionStateInterface>
*/
public function getCatchUpHookFactoryForProjection(ProjectionInterface $projection): ?CatchUpHookFactoryInterface
{
Expand Down

0 comments on commit 347322e

Please sign in to comment.