diff --git a/Classes/ContentRepository.php b/Classes/ContentRepository.php index d966002f..8587b3fc 100644 --- a/Classes/ContentRepository.php +++ b/Classes/ContentRepository.php @@ -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(); diff --git a/Classes/Factory/ProjectionsAndCatchUpHooksFactory.php b/Classes/Factory/ProjectionsAndCatchUpHooksFactory.php index cd369a87..f48ed134 100644 --- a/Classes/Factory/ProjectionsAndCatchUpHooksFactory.php +++ b/Classes/Factory/ProjectionsAndCatchUpHooksFactory.php @@ -6,12 +6,12 @@ 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 @@ -19,7 +19,7 @@ final class ProjectionsAndCatchUpHooksFactory { /** - * @var array>, options: array, catchUpHooksFactories: array}> + * @var array>, options: array, catchUpHooksFactories: array>}> */ private array $factories = []; @@ -40,7 +40,7 @@ public function registerFactory(ProjectionFactoryInterface $factory, array $opti /** * @param ProjectionFactoryInterface> $factory - * @param CatchUpHookFactoryInterface $catchUpHookFactory + * @param CatchUpHookFactoryInterface $catchUpHookFactory * @return void * @api */ diff --git a/Classes/Projection/CatchUpHookFactories.php b/Classes/Projection/CatchUpHookFactories.php index deabf534..f12fb3be 100644 --- a/Classes/Projection/CatchUpHookFactories.php +++ b/Classes/Projection/CatchUpHookFactories.php @@ -4,18 +4,22 @@ namespace Neos\ContentRepository\Core\Projection; -use Neos\ContentRepository\Core\ContentRepository; +use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; /** + * @implements CatchUpHookFactoryInterface * @internal */ final class CatchUpHookFactories implements CatchUpHookFactoryInterface { /** - * @var array + * @var array> */ private array $catchUpHookFactories; + /** + * @param CatchUpHookFactoryInterface ...$catchUpHookFactories + */ private function __construct(CatchUpHookFactoryInterface ...$catchUpHookFactories) { $this->catchUpHookFactories = $catchUpHookFactories; @@ -26,6 +30,10 @@ public static function create(): self return new self(); } + /** + * @param CatchUpHookFactoryInterface $catchUpHookFactory + * @return self + */ public function with(CatchUpHookFactoryInterface $catchUpHookFactory): self { if ($this->has($catchUpHookFactory::class)) { @@ -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); } } diff --git a/Classes/Projection/CatchUpHookFactoryInterface.php b/Classes/Projection/CatchUpHookFactoryInterface.php index ec84d096..10d918cd 100644 --- a/Classes/Projection/CatchUpHookFactoryInterface.php +++ b/Classes/Projection/CatchUpHookFactoryInterface.php @@ -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; } diff --git a/Classes/Projection/ContentGraph/ContentGraphReadModelInterface.php b/Classes/Projection/ContentGraph/ContentGraphReadModelInterface.php index e1298bc1..5f157f8d 100644 --- a/Classes/Projection/ContentGraph/ContentGraphReadModelInterface.php +++ b/Classes/Projection/ContentGraph/ContentGraphReadModelInterface.php @@ -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 { diff --git a/Classes/Projection/ProjectionsAndCatchUpHooks.php b/Classes/Projection/ProjectionsAndCatchUpHooks.php index 255e59b7..d7b674ba 100644 --- a/Classes/Projection/ProjectionsAndCatchUpHooks.php +++ b/Classes/Projection/ProjectionsAndCatchUpHooks.php @@ -26,6 +26,7 @@ public function __construct( /** * @param ProjectionInterface $projection + * @return ?CatchUpHookFactoryInterface */ public function getCatchUpHookFactoryForProjection(ProjectionInterface $projection): ?CatchUpHookFactoryInterface {