diff --git a/Classes/ContentRepository/Service/NodeService.php b/Classes/ContentRepository/Service/NeosUiNodeService.php similarity index 53% rename from Classes/ContentRepository/Service/NodeService.php rename to Classes/ContentRepository/Service/NeosUiNodeService.php index cad0b5c744..9ca28403bd 100644 --- a/Classes/ContentRepository/Service/NodeService.php +++ b/Classes/ContentRepository/Service/NeosUiNodeService.php @@ -21,54 +21,20 @@ use Neos\Neos\Utility\NodeTypeWithFallbackProvider; /** + * @internal * @Flow\Scope("singleton") */ -class NodeService +class NeosUiNodeService { use NodeTypeWithFallbackProvider; #[Flow\Inject] protected ContentRepositoryRegistry $contentRepositoryRegistry; - /** - * Helper method to retrieve the closest document for a node - */ - public function getClosestDocument(Node $node): ?Node - { - if ($this->getNodeType($node)->isOfType('Neos.Neos:Document')) { - return $node; - } - - $subgraph = $this->contentRepositoryRegistry->subgraphForNode($node); - - while ($node instanceof Node) { - if ($this->getNodeType($node)->isOfType('Neos.Neos:Document')) { - return $node; - } - $node = $subgraph->findParentNode($node->nodeAggregateId); - } - - return null; - } - - /** - * Helper method to check if a given node is a document node. - * - * @param Node $node The node to check - * @return boolean A boolean which indicates if the given node is a document node. - */ - public function isDocument(Node $node): bool - { - return ($this->getClosestDocument($node) === $node); - } - - /** - * Converts a given context path to a node object - */ - public function getNodeFromContextPath(string $contextPath, ContentRepositoryId $contentRepositoryId): ?Node + public function findNodeBySerializedNodeAddress(string $serializedNodeAddress, ContentRepositoryId $contentRepositoryId): ?Node { $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); - $nodeAddress = NodeAddressFactory::create($contentRepository)->createFromUriString($contextPath); + $nodeAddress = NodeAddressFactory::create($contentRepository)->createFromUriString($serializedNodeAddress); $subgraph = $contentRepository->getContentGraph()->getSubgraph( $nodeAddress->contentStreamId, diff --git a/Classes/ContentRepository/Service/WorkspaceService.php b/Classes/ContentRepository/Service/WorkspaceService.php index 9ae80ff464..8e05538eae 100644 --- a/Classes/ContentRepository/Service/WorkspaceService.php +++ b/Classes/ContentRepository/Service/WorkspaceService.php @@ -14,8 +14,10 @@ use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\Factory\ContentRepositoryId; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Command\DiscardIndividualNodesFromWorkspace; +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Projection\Workspace\Workspace; +use Neos\Neos\Domain\Service\NodeTypeNameFactory; use Neos\Neos\FrontendRouting\NodeAddress; use Neos\Neos\FrontendRouting\NodeAddressFactory; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; @@ -97,7 +99,7 @@ public function getPublishableNodeInfo(WorkspaceName $workspaceName, ContentRepo $node = $subgraph->findNodeById($change->nodeAggregateId); if ($node instanceof Node) { - $documentNode = $this->getClosestDocumentNode($node); + $documentNode = $subgraph->findClosestNode($node->nodeAggregateId, FindClosestNodeFilter::create(nodeTypeConstraints: NodeTypeNameFactory::NAME_DOCUMENT)); if ($documentNode instanceof Node) { $contentRepository = $this->contentRepositoryRegistry->get($documentNode->subgraphIdentity->contentRepositoryId); $nodeAddressFactory = NodeAddressFactory::create($contentRepository); @@ -161,7 +163,7 @@ public function predictRemoveNodeFeedbackFromDiscardIndividualNodesFromWorkspace ): array { $workspace = $contentRepository->getWorkspaceFinder()->findOneByName($command->workspaceName); if (is_null($workspace)) { - return Nodes::createEmpty(); + return []; } $changeFinder = $contentRepository->projectionState(ChangeFinder::class); @@ -201,18 +203,4 @@ public function predictRemoveNodeFeedbackFromDiscardIndividualNodesFromWorkspace return $result; } - - private function getClosestDocumentNode(Node $node): ?Node - { - $subgraph = $this->contentRepositoryRegistry->subgraphForNode($node); - - while ($node instanceof Node) { - if ($this->getNodeType($node)->isOfType('Neos.Neos:Document')) { - return $node; - } - $node = $subgraph->findParentNode($node->nodeAggregateId); - } - - return null; - } } diff --git a/Classes/Controller/BackendServiceController.php b/Classes/Controller/BackendServiceController.php index 7c923fbcec..1f941184eb 100644 --- a/Classes/Controller/BackendServiceController.php +++ b/Classes/Controller/BackendServiceController.php @@ -37,7 +37,7 @@ use Neos\Neos\FrontendRouting\NodeAddressFactory; use Neos\Neos\FrontendRouting\SiteDetection\SiteDetectionResult; use Neos\Neos\Service\UserService; -use Neos\Neos\Ui\ContentRepository\Service\NodeService; +use Neos\Neos\Ui\ContentRepository\Service\NeosUiNodeService; use Neos\Neos\Ui\ContentRepository\Service\WorkspaceService; use Neos\Neos\Ui\Domain\Model\ChangeCollection; use Neos\Neos\Ui\Domain\Model\Feedback\Messages\Error; @@ -88,7 +88,7 @@ class BackendServiceController extends ActionController /** * @Flow\Inject - * @var NodeService + * @var NeosUiNodeService */ protected $nodeService; @@ -590,7 +590,7 @@ public function flowQueryAction(array $chain): string /** @var array $payload */ $payload = $createContext['payload'] ?? []; $flowQuery = new FlowQuery(array_map( - fn ($envelope) => $this->nodeService->getNodeFromContextPath($envelope['$node'], $contentRepositoryId), + fn ($envelope) => $this->nodeService->findNodeBySerializedNodeAddress($envelope['$node'], $contentRepositoryId), $payload )); diff --git a/Classes/Domain/Model/AbstractChange.php b/Classes/Domain/Model/AbstractChange.php index 9edfac63f3..62c877da2d 100644 --- a/Classes/Domain/Model/AbstractChange.php +++ b/Classes/Domain/Model/AbstractChange.php @@ -11,10 +11,12 @@ * source code. */ +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Annotations as Flow; use Neos\Flow\Persistence\PersistenceManagerInterface; +use Neos\Neos\Domain\Service\NodeTypeNameFactory; use Neos\Neos\Service\UserService; use Neos\Neos\Ui\Domain\Model\Feedback\Operations\NodeCreated; use Neos\Neos\Ui\Domain\Model\Feedback\Operations\ReloadDocument; @@ -64,7 +66,8 @@ public function getSubject(): ?Node protected function updateWorkspaceInfo(): void { if (!is_null($this->subject)) { - $documentNode = $this->findClosestDocumentNode($this->subject); + $subgraph = $this->contentRepositoryRegistry->subgraphForNode($this->subject); + $documentNode = $subgraph->findClosestNode($this->subject->nodeAggregateId, FindClosestNodeFilter::create(nodeTypeConstraints: NodeTypeNameFactory::NAME_DOCUMENT)); if (!is_null($documentNode)) { $contentRepository = $this->contentRepositoryRegistry->get($this->subject->subgraphIdentity->contentRepositoryId); $workspace = $contentRepository->getWorkspaceFinder()->findOneByCurrentContentStreamId( @@ -78,18 +81,6 @@ protected function updateWorkspaceInfo(): void } } - final protected function findClosestDocumentNode(Node $node): ?Node - { - while ($node instanceof Node) { - if ($this->getNodeType($node)->isOfType('Neos.Neos:Document')) { - return $node; - } - $node = $this->findParentNode($node); - } - - return null; - } - protected function findParentNode(Node $node): ?Node { return $this->contentRepositoryRegistry->subgraphForNode($node) diff --git a/Classes/Domain/Model/Changes/AbstractStructuralChange.php b/Classes/Domain/Model/Changes/AbstractStructuralChange.php index f4eb59d5a1..de725b5fe4 100644 --- a/Classes/Domain/Model/Changes/AbstractStructuralChange.php +++ b/Classes/Domain/Model/Changes/AbstractStructuralChange.php @@ -20,7 +20,7 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Nodes; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Annotations as Flow; -use Neos\Neos\Ui\ContentRepository\Service\NodeService; +use Neos\Neos\Ui\ContentRepository\Service\NeosUiNodeService; use Neos\Neos\Ui\Domain\Model\AbstractChange; use Neos\Neos\Ui\Domain\Model\Feedback\Operations\ReloadDocument; use Neos\Neos\Ui\Domain\Model\Feedback\Operations\RenderContentOutOfBand; @@ -50,7 +50,7 @@ abstract class AbstractStructuralChange extends AbstractChange /** * @Flow\Inject - * @var NodeService + * @var NeosUiNodeService */ protected $nodeService; @@ -111,7 +111,7 @@ public function getSiblingNode(): ?Node } if ($this->cachedSiblingNode === null) { - $this->cachedSiblingNode = $this->nodeService->getNodeFromContextPath( + $this->cachedSiblingNode = $this->nodeService->findNodeBySerializedNodeAddress( $this->siblingDomAddress->getContextPath(), $this->getSubject()->subgraphIdentity->contentRepositoryId ); diff --git a/Classes/Domain/Model/Changes/CopyInto.php b/Classes/Domain/Model/Changes/CopyInto.php index 5b2c3463f6..56c4e55d5d 100644 --- a/Classes/Domain/Model/Changes/CopyInto.php +++ b/Classes/Domain/Model/Changes/CopyInto.php @@ -32,7 +32,7 @@ public function getParentNode(): ?Node { if (!isset($this->cachedParentNode)) { $this->cachedParentNode = $this->parentContextPath - ? $this->nodeService->getNodeFromContextPath($this->parentContextPath, $this->getSubject()->subgraphIdentity->contentRepositoryId) + ? $this->nodeService->findNodeBySerializedNodeAddress($this->parentContextPath, $this->getSubject()->subgraphIdentity->contentRepositoryId) : null; } diff --git a/Classes/Domain/Model/Changes/MoveInto.php b/Classes/Domain/Model/Changes/MoveInto.php index ebccb70c9e..2018a8f1c1 100644 --- a/Classes/Domain/Model/Changes/MoveInto.php +++ b/Classes/Domain/Model/Changes/MoveInto.php @@ -33,7 +33,7 @@ public function getParentNode(): ?Node return null; } - return $this->nodeService->getNodeFromContextPath( + return $this->nodeService->findNodeBySerializedNodeAddress( $this->parentContextPath, $this->getSubject()->subgraphIdentity->contentRepositoryId ); diff --git a/Classes/Domain/Model/Changes/Remove.php b/Classes/Domain/Model/Changes/Remove.php index f204d69af3..ccf87a5c04 100644 --- a/Classes/Domain/Model/Changes/Remove.php +++ b/Classes/Domain/Model/Changes/Remove.php @@ -13,11 +13,13 @@ */ use Neos\ContentRepository\Core\DimensionSpace\Exception\DimensionSpacePointNotFound; +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter; use Neos\ContentRepository\Core\SharedModel\Exception\ContentStreamDoesNotExistYet; use Neos\ContentRepository\Core\SharedModel\Node\NodeVariantSelectionStrategy; use Neos\ContentRepository\Core\Feature\NodeRemoval\Command\RemoveNodeAggregate; use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregatesTypeIsAmbiguous; use Neos\Flow\Annotations as Flow; +use Neos\Neos\Domain\Service\NodeTypeNameFactory; use Neos\Neos\Fusion\Cache\ContentCacheFlusher; use Neos\Neos\Ui\Domain\Model\AbstractChange; use Neos\Neos\Ui\Domain\Model\Feedback\Operations\RemoveNode; @@ -68,7 +70,8 @@ public function apply(): void // otherwise we cannot find the parent nodes anymore. $this->updateWorkspaceInfo(); - $closestDocumentParentNode = $this->findClosestDocumentNode($subject); + $subgraph = $this->contentRepositoryRegistry->subgraphForNode($this->subject); + $closestDocumentParentNode = $subgraph->findClosestNode($this->subject->nodeAggregateId, FindClosestNodeFilter::create(nodeTypeConstraints: NodeTypeNameFactory::NAME_DOCUMENT)); $command = RemoveNodeAggregate::create( $subject->subgraphIdentity->contentStreamId, $subject->nodeAggregateId, diff --git a/Classes/Domain/Model/Feedback/Operations/ReloadDocument.php b/Classes/Domain/Model/Feedback/Operations/ReloadDocument.php index 3b0d24cced..039881587c 100644 --- a/Classes/Domain/Model/Feedback/Operations/ReloadDocument.php +++ b/Classes/Domain/Model/Feedback/Operations/ReloadDocument.php @@ -11,10 +11,12 @@ * source code. */ +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; +use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Annotations as Flow; use Neos\Flow\Mvc\Controller\ControllerContext; -use Neos\Neos\Ui\ContentRepository\Service\NodeService; +use Neos\Neos\Domain\Service\NodeTypeNameFactory; use Neos\Neos\Ui\Domain\Model\AbstractFeedback; use Neos\Neos\Ui\Domain\Model\FeedbackInterface; use Neos\Neos\Ui\Fusion\Helper\NodeInfoHelper; @@ -23,11 +25,8 @@ class ReloadDocument extends AbstractFeedback { protected ?Node $node; - /** - * @Flow\Inject - * @var NodeService - */ - protected $nodeService; + #[Flow\Inject] + protected ContentRepositoryRegistry $contentRepositoryRegistry; public function getType(): string { @@ -73,7 +72,10 @@ public function serializePayload(ControllerContext $controllerContext): array } $nodeInfoHelper = new NodeInfoHelper(); - if ($documentNode = $this->nodeService->getClosestDocument($this->node)) { + $documentNode = $this->contentRepositoryRegistry->subgraphForNode($this->node) + ->findClosestNode($this->node->nodeAggregateId, FindClosestNodeFilter::create(nodeTypeConstraints: NodeTypeNameFactory::NAME_DOCUMENT)); + + if ($documentNode) { return [ 'uri' => $nodeInfoHelper->previewUri($documentNode, $controllerContext) ]; diff --git a/Classes/Domain/Service/NodeTreeBuilder.php b/Classes/Domain/Service/NodeTreeBuilder.php index acab3f73e5..3fb6cc5dc5 100644 --- a/Classes/Domain/Service/NodeTreeBuilder.php +++ b/Classes/Domain/Service/NodeTreeBuilder.php @@ -17,7 +17,7 @@ use Neos\Flow\Annotations as Flow; use Neos\Flow\Mvc\Controller\ControllerContext; use Neos\Neos\Service\LinkingService; -use Neos\Neos\Ui\ContentRepository\Service\NodeService; +use Neos\Neos\Ui\ContentRepository\Service\NeosUiNodeService; class NodeTreeBuilder { @@ -58,7 +58,7 @@ class NodeTreeBuilder /** * @Flow\Inject - * @var NodeService + * @var NeosUiNodeService */ protected $nodeService; diff --git a/Classes/TypeConverter/ChangeCollectionConverter.php b/Classes/TypeConverter/ChangeCollectionConverter.php index 51e5fd43af..f6ac74214b 100644 --- a/Classes/TypeConverter/ChangeCollectionConverter.php +++ b/Classes/TypeConverter/ChangeCollectionConverter.php @@ -20,7 +20,7 @@ use Neos\Flow\Property\PropertyMappingConfigurationInterface; use Neos\Flow\Property\TypeConverter\AbstractTypeConverter; use Neos\Flow\Reflection\ReflectionService; -use Neos\Neos\Ui\ContentRepository\Service\NodeService; +use Neos\Neos\Ui\ContentRepository\Service\NeosUiNodeService; use Neos\Neos\Ui\Domain\Model\ChangeCollection; use Neos\Neos\Ui\Domain\Model\ChangeInterface; use Neos\Neos\Ui\Domain\Model\Changes\Property; @@ -76,7 +76,7 @@ class ChangeCollectionConverter /** * @Flow\Inject - * @var NodeService + * @var NeosUiNodeService */ protected $nodeService; @@ -141,7 +141,7 @@ protected function convertChangeData(array $changeData, ContentRepositoryId $con $subjectContextPath = $changeData['subject']; - $subject = $this->nodeService->getNodeFromContextPath($subjectContextPath, $contentRepositoryId); + $subject = $this->nodeService->findNodeBySerializedNodeAddress($subjectContextPath, $contentRepositoryId); if (is_null($subject)) { throw new \RuntimeException('Could not find node for subject "' . $subjectContextPath . '"', 1645657340); } @@ -150,7 +150,7 @@ protected function convertChangeData(array $changeData, ContentRepositoryId $con if (isset($changeData['reference']) && method_exists($changeClassInstance, 'setReference')) { $referenceContextPath = $changeData['reference']; - $reference = $this->nodeService->getNodeFromContextPath($referenceContextPath, $contentRepositoryId); + $reference = $this->nodeService->findNodeBySerializedNodeAddress($referenceContextPath, $contentRepositoryId); $changeClassInstance->setReference($reference); }