diff --git a/Neos.ContentRepository.Core/Classes/Factory/ContentRepositoryFactory.php b/Neos.ContentRepository.Core/Classes/Factory/ContentRepositoryFactory.php index f914f0436e..ea4593a6a7 100644 --- a/Neos.ContentRepository.Core/Classes/Factory/ContentRepositoryFactory.php +++ b/Neos.ContentRepository.Core/Classes/Factory/ContentRepositoryFactory.php @@ -65,7 +65,7 @@ final class ContentRepositoryFactory private ?ContentRepository $contentRepositoryRuntimeCache = null; /** - * @param CatchUpHookFactoryInterface $contentGraphCatchUpHookFactory + * @param CatchUpHookFactoryInterface|null $contentGraphCatchUpHookFactory */ public function __construct( private readonly ContentRepositoryId $contentRepositoryId, @@ -77,7 +77,7 @@ public function __construct( private readonly ClockInterface $clock, SubscriptionStoreInterface $subscriptionStore, ContentGraphProjectionFactoryInterface $contentGraphProjectionFactory, - private readonly CatchUpHookFactoryInterface $contentGraphCatchUpHookFactory, + private readonly CatchUpHookFactoryInterface|null $contentGraphCatchUpHookFactory, private readonly CommandHooksFactory $commandHooksFactory, private readonly ContentRepositorySubscriberFactories $additionalSubscriberFactories, LoggerInterface|null $logger = null, @@ -115,7 +115,7 @@ private function buildContentGraphSubscriber(): ProjectionSubscriber return new ProjectionSubscriber( SubscriptionId::fromString('contentGraph'), $this->contentGraphProjection, - $this->contentGraphCatchUpHookFactory->build(CatchUpHookFactoryDependencies::create( + $this->contentGraphCatchUpHookFactory?->build(CatchUpHookFactoryDependencies::create( $this->contentRepositoryId, $this->contentGraphProjection->getState(), $this->subscriberFactoryDependencies->nodeTypeManager, diff --git a/Neos.ContentRepository.Core/Classes/Factory/ProjectionSubscriberFactory.php b/Neos.ContentRepository.Core/Classes/Factory/ProjectionSubscriberFactory.php index f763dfb932..1970b08556 100644 --- a/Neos.ContentRepository.Core/Classes/Factory/ProjectionSubscriberFactory.php +++ b/Neos.ContentRepository.Core/Classes/Factory/ProjectionSubscriberFactory.php @@ -14,6 +14,8 @@ namespace Neos\ContentRepository\Core\Factory; +use Neos\ContentRepository\Core\Projection\CatchUpHook\CatchUpHookFactoryDependencies; +use Neos\ContentRepository\Core\Projection\CatchUpHook\CatchUpHookFactoryInterface; use Neos\ContentRepository\Core\Projection\ProjectionFactoryInterface; use Neos\ContentRepository\Core\Projection\ProjectionInterface; use Neos\ContentRepository\Core\Projection\ProjectionStateInterface; @@ -27,21 +29,32 @@ { /** * @param ProjectionFactoryInterface> $projectionFactory + * @param CatchUpHookFactoryInterface|null $catchUpHookFactory * @param array $projectionFactoryOptions */ public function __construct( private SubscriptionId $subscriptionId, private ProjectionFactoryInterface $projectionFactory, + private ?CatchUpHookFactoryInterface $catchUpHookFactory, private array $projectionFactoryOptions, ) { } public function build(SubscriberFactoryDependencies $dependencies): ProjectionSubscriber { + $projection = $this->projectionFactory->build($dependencies, $this->projectionFactoryOptions); + $catchUpHook = $this->catchUpHookFactory?->build(CatchUpHookFactoryDependencies::create( + $dependencies->contentRepositoryId, + $projection->getState(), + $dependencies->nodeTypeManager, + $dependencies->contentDimensionSource, + $dependencies->interDimensionalVariationGraph, + )); + return new ProjectionSubscriber( $this->subscriptionId, - $this->projectionFactory->build($dependencies, $this->projectionFactoryOptions), - null + $projection, + $catchUpHook, ); } } diff --git a/Neos.ContentRepository.Core/Classes/Projection/CatchUpHook/CatchUpHookFactories.php b/Neos.ContentRepository.Core/Classes/Projection/CatchUpHook/CatchUpHookFactories.php index e383b32299..22f2621e2a 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/CatchUpHook/CatchUpHookFactories.php +++ b/Neos.ContentRepository.Core/Classes/Projection/CatchUpHook/CatchUpHookFactories.php @@ -51,6 +51,11 @@ private function has(string $catchUpHookFactoryClassName): bool return array_key_exists($catchUpHookFactoryClassName, $this->catchUpHookFactories); } + public function isEmpty(): bool + { + return $this->catchUpHookFactories === []; + } + public function build(CatchUpHookFactoryDependencies $dependencies): CatchUpHookInterface { $catchUpHooks = array_map(static fn(CatchUpHookFactoryInterface $catchUpHookFactory) => $catchUpHookFactory->build($dependencies), $this->catchUpHookFactories); diff --git a/Neos.ContentRepositoryRegistry/Classes/ContentRepositoryRegistry.php b/Neos.ContentRepositoryRegistry/Classes/ContentRepositoryRegistry.php index 1f073833b2..4fdec55cd7 100644 --- a/Neos.ContentRepositoryRegistry/Classes/ContentRepositoryRegistry.php +++ b/Neos.ContentRepositoryRegistry/Classes/ContentRepositoryRegistry.php @@ -21,6 +21,7 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\ContentSubgraphInterface; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Projection\ProjectionFactoryInterface; +use Neos\ContentRepository\Core\Projection\ProjectionStateInterface; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryIds; use Neos\ContentRepository\Core\Subscription\Store\SubscriptionStoreInterface; @@ -57,6 +58,9 @@ final class ContentRepositoryRegistry */ private array $factoryInstances = []; + /** + * @var array + */ private array $settings; #[Flow\Inject(name: 'Neos.ContentRepositoryRegistry:Logger', lazy: false)] @@ -183,6 +187,8 @@ private function buildFactory(ContentRepositoryId $contentRepositoryId): Content unset($contentRepositorySettings['preset']); } try { + /** @var CatchUpHookFactoryInterface|null $contentGraphCatchUpHookFactory */ + $contentGraphCatchUpHookFactory = $this->buildCatchUpHookFactory($contentRepositoryId, 'contentGraph', $contentRepositorySettings['contentGraphProjection']); $clock = $this->buildClock($contentRepositoryId, $contentRepositorySettings); return new ContentRepositoryFactory( $contentRepositoryId, @@ -194,7 +200,7 @@ private function buildFactory(ContentRepositoryId $contentRepositoryId): Content $clock, $this->buildSubscriptionStore($contentRepositoryId, $clock, $contentRepositorySettings), $this->buildContentGraphProjectionFactory($contentRepositoryId, $contentRepositorySettings), - $this->buildContentGraphCatchUpHookFactory($contentRepositoryId, $contentRepositorySettings), + $contentGraphCatchUpHookFactory, $this->buildCommandHooksFactory($contentRepositoryId, $contentRepositorySettings), $this->buildAdditionalSubscribersFactories($contentRepositoryId, $contentRepositorySettings), $this->logger, @@ -275,27 +281,29 @@ private function buildContentGraphProjectionFactory(ContentRepositoryId $content } /** - * @param array $contentRepositorySettings - * @return CatchUpHookFactoryInterface + * @param array $projectionOptions + * @return CatchUpHookFactoryInterface|null */ - private function buildContentGraphCatchUpHookFactory(ContentRepositoryId $contentRepositoryId, array $contentRepositorySettings): CatchUpHookFactoryInterface + private function buildCatchUpHookFactory(ContentRepositoryId $contentRepositoryId, string $projectionName, array $projectionOptions): ?CatchUpHookFactoryInterface { - if (!isset($contentRepositorySettings['contentGraphProjection']['catchUpHooks'])) { - throw InvalidConfigurationException::fromMessage('Content repository "%s" does not have the contentGraphProjection.catchUpHooks configured.', $contentRepositoryId->value); + if (!isset($projectionOptions['catchUpHooks'])) { + return null; } $catchUpHookFactories = CatchUpHookFactories::create(); - foreach ($contentRepositorySettings['contentGraphProjection']['catchUpHooks'] as $catchUpHookName => $catchUpHookOptions) { + foreach ($projectionOptions['catchUpHooks'] as $catchUpHookName => $catchUpHookOptions) { if ($catchUpHookOptions === null) { // Allow catch up hooks to be disabled by setting their configuration to `null` continue; } $catchUpHookFactory = $this->objectManager->get($catchUpHookOptions['factoryObjectName']); if (!$catchUpHookFactory instanceof CatchUpHookFactoryInterface) { - throw InvalidConfigurationException::fromMessage('CatchUpHook factory object name for content graph CatchUpHook "%s" (content repository "%s") is not an instance of %s but %s', $catchUpHookName, $contentRepositoryId->value, CatchUpHookFactoryInterface::class, get_debug_type($catchUpHookFactory)); + throw InvalidConfigurationException::fromMessage('CatchUpHook factory object name for hook "%s" in projection "%s" (content repository "%s") is not an instance of %s but %s', $catchUpHookName, $projectionName, $contentRepositoryId->value, CatchUpHookFactoryInterface::class, get_debug_type($catchUpHookFactory)); } $catchUpHookFactories = $catchUpHookFactories->with($catchUpHookFactory); } - /** @var CatchUpHookFactoryInterface $catchUpHookFactories */ + if ($catchUpHookFactories->isEmpty()) { + return null; + } return $catchUpHookFactories; } @@ -344,6 +352,7 @@ private function buildAdditionalSubscribersFactories(ContentRepositoryId $conten $projectionSubscriberFactories[$projectionName] = new ProjectionSubscriberFactory( SubscriptionId::fromString($projectionName), $projectionFactory, + $this->buildCatchUpHookFactory($contentRepositoryId, $projectionName, $projectionOptions), $projectionOptions['options'] ?? [], ); }