From 85230100dc75d3a28dac8b2f938739d764d80204 Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Tue, 19 Nov 2024 10:18:43 +0100 Subject: [PATCH] TASK: Introduce internal `calculateCopyNodesRecursively` to support usecases like https://github.com/Flowpack/Flowpack.NodeTemplates/issues/60 were we need to return a list of commands and cant handle them ourselves, it would be practical to expose a way to get the commands that would be handled --- .../Domain/Service/NodeDuplicationService.php | 47 ++++++++++++++----- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/Neos.Neos/Classes/Domain/Service/NodeDuplicationService.php b/Neos.Neos/Classes/Domain/Service/NodeDuplicationService.php index 4872941577..dbd7d21460 100644 --- a/Neos.Neos/Classes/Domain/Service/NodeDuplicationService.php +++ b/Neos.Neos/Classes/Domain/Service/NodeDuplicationService.php @@ -99,26 +99,53 @@ public function copyNodesRecursively( throw new NodeAggregateCurrentlyDoesNotExist(sprintf('The source node aggregate "%s" does not exist', $sourceNodeAggregateId->value), 1732006772); } - $transientNodeCopy = TransientNodeCopy::forEntry( + $commands = $this->calculateCopyNodesRecursively( $subtree, + $subgraph, $workspaceName, $targetDimensionSpacePoint, + $targetParentNodeAggregateId, + $targetSucceedingSiblingNodeAggregateId, + $nodeAggregateIdMapping + ); + + foreach ($commands as $command) { + $contentRepository->handle($command); + } + } + + /** + * @internal implementation detail of {@see NodeDuplicationService::copyNodesRecursively}, exposed for EXPERIMENTAL use cases, the API can change any time! + */ + public function calculateCopyNodesRecursively( + Subtree $subtreeToCopy, + ContentSubgraphInterface $subgraph, + WorkspaceName $targetWorkspaceName, + OriginDimensionSpacePoint $targetDimensionSpacePoint, + NodeAggregateId $targetParentNodeAggregateId, + ?NodeAggregateId $targetSucceedingSiblingNodeAggregateId, + ?NodeAggregateIdMapping $nodeAggregateIdMapping = null + ): Commands { + $transientNodeCopy = TransientNodeCopy::forEntry( + $subtreeToCopy, + $targetWorkspaceName, + $targetDimensionSpacePoint, $nodeAggregateIdMapping ?? NodeAggregateIdMapping::createEmpty() ); $createCopyOfNodeCommand = CreateNodeAggregateWithNode::create( $transientNodeCopy->workspaceName, $transientNodeCopy->aggregateId, - $subtree->node->nodeTypeName, + $subtreeToCopy->node->nodeTypeName, $targetDimensionSpacePoint, $targetParentNodeAggregateId, succeedingSiblingNodeAggregateId: $targetSucceedingSiblingNodeAggregateId, // todo skip properties not in schema initialPropertyValues: PropertyValuesToWrite::fromArray( - iterator_to_array($subtree->node->properties) + iterator_to_array($subtreeToCopy->node->properties) ), references: $this->serializeProjectedReferences( - $subgraph->findReferences($subtree->node->aggregateId, FindReferencesFilter::create()) + $subgraph->findReferences($subtreeToCopy->node->aggregateId, FindReferencesFilter::create()) ) ); @@ -128,7 +155,7 @@ public function copyNodesRecursively( $commands = Commands::create($createCopyOfNodeCommand); - foreach ($subtree->node->tags->withoutInherited() as $explicitTag) { + foreach ($subtreeToCopy->node->tags->withoutInherited() as $explicitTag) { $commands = $commands->append( TagSubtree::create( $transientNodeCopy->workspaceName, @@ -140,18 +167,16 @@ public function copyNodesRecursively( ); } - foreach ($subtree->children as $childSubtree) { - if ($subtree->node->classification->isTethered() && $childSubtree->node->classification->isTethered()) { + foreach ($subtreeToCopy->children as $childSubtree) { + if ($subtreeToCopy->node->classification->isTethered() && $childSubtree->node->classification->isTethered()) { // TODO we assume here that the child node is tethered because the grandparent specifies that. // this is not always fully correct and we could loosen the constraint by checking the node type schema - throw new TetheredNodesCannotBePartiallyCopied(sprintf('Cannot copy tethered node %s because child node %s is also tethered. Only standalone tethered nodes can be copied.', $subtree->node->aggregateId->value, $childSubtree->node->aggregateId->value), 1731264887); + throw new TetheredNodesCannotBePartiallyCopied(sprintf('Cannot copy tethered node %s because child node %s is also tethered. Only standalone tethered nodes can be copied.', $subtreeToCopy->node->aggregateId->value, $childSubtree->node->aggregateId->value), 1731264887); } $commands = $this->commandsForSubtreeRecursively($transientNodeCopy, $childSubtree, $subgraph, $commands); } - foreach ($commands as $command) { - $contentRepository->handle($command); - } + return $commands; } private function commandsForSubtreeRecursively(TransientNodeCopy $transientParentNode, Subtree $subtree, ContentSubgraphInterface $subgraph, Commands $commands): Commands