From 49404243129e4943b94baf5a9417ed0d34f326fa Mon Sep 17 00:00:00 2001 From: Martin Ficzel Date: Fri, 3 Nov 2023 16:54:43 +0100 Subject: [PATCH] TASK: Fix `NextUntil` and `PrevUntil` and optimize `Next`, `NextAll`, `Prev`, `PrevAll` --- .../Classes/Projection/ContentGraph/Nodes.php | 14 ++++++-- .../FlowQueryOperations/NextAllOperation.php | 25 ++++--------- .../FlowQueryOperations/NextOperation.php | 24 ++++--------- .../NextUntilOperation.php | 35 +++++------------- .../FlowQueryOperations/PrevAllOperation.php | 25 +++++-------- .../FlowQueryOperations/PrevOperation.php | 29 +++++---------- .../PrevUntilOperation.php | 36 ++++++------------- 7 files changed, 61 insertions(+), 127 deletions(-) diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php index adb5887378b..e8fcee3cf7f 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php @@ -97,8 +97,18 @@ public function count(): int public function first(): ?Node { if (count($this->nodes) > 0) { - $array = $this->nodes; - return reset($array); + $key = array_key_first($this->nodes); + return $this->nodes[$key]; + } + + return null; + } + + public function last(): ?Node + { + if (count($this->nodes) > 0) { + $key = array_key_last($this->nodes); + return $this->nodes[$key]; } return null; diff --git a/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/NextAllOperation.php b/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/NextAllOperation.php index d644f2d7a69..98c6d8afbdd 100644 --- a/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/NextAllOperation.php +++ b/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/NextAllOperation.php @@ -12,6 +12,7 @@ */ use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindChildNodesFilter; +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindSucceedingSiblingNodesFilter; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Annotations as Flow; use Neos\Eel\FlowQuery\FlowQuery; @@ -69,7 +70,12 @@ public function evaluate(FlowQuery $flowQuery, array $arguments) $output = []; $outputNodePaths = []; foreach ($flowQuery->getContext() as $contextNode) { - foreach ($this->getNextForNode($contextNode) as $nextNode) { + $nextNodes = $this->contentRepositoryRegistry->subgraphForNode($contextNode) + ->findSucceedingSiblingNodes( + $contextNode->nodeAggregateId, + FindSucceedingSiblingNodesFilter::create() + ); + foreach ($nextNodes as $nextNode) { if ($nextNode !== null && !isset($outputNodePaths[$nextNode->nodeAggregateId->value])) { $outputNodePaths[$nextNode->nodeAggregateId->value] = true; $output[] = $nextNode; @@ -82,21 +88,4 @@ public function evaluate(FlowQuery $flowQuery, array $arguments) $flowQuery->pushOperation('filter', $arguments); } } - - /** - * @param Node $contextNode The node for which the next node should be found - * @return Nodes The next nodes of $contextNode - */ - protected function getNextForNode(Node $contextNode): Nodes - { - $subgraph = $this->contentRepositoryRegistry->subgraphForNode($contextNode); - - $parentNode = $subgraph->findParentNode($contextNode->nodeAggregateId); - if ($parentNode === null) { - return Nodes::createEmpty(); - } - - return $subgraph->findChildNodes($parentNode->nodeAggregateId, FindChildNodesFilter::create()) - ->nextAll($contextNode); - } } diff --git a/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/NextOperation.php b/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/NextOperation.php index 797142689be..ba247b9179e 100644 --- a/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/NextOperation.php +++ b/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/NextOperation.php @@ -12,6 +12,7 @@ */ use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindChildNodesFilter; +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindSucceedingSiblingNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Eel\FlowQuery\FlowQuery; @@ -69,7 +70,11 @@ public function evaluate(FlowQuery $flowQuery, array $arguments) $output = []; $outputNodePaths = []; foreach ($flowQuery->getContext() as $contextNode) { - $nextNode = $this->getNextForNode($contextNode); + $nextNode = $this->contentRepositoryRegistry->subgraphForNode($contextNode) + ->findSucceedingSiblingNodes( + $contextNode->nodeAggregateId, + FindSucceedingSiblingNodesFilter::create() + )->first(); if ($nextNode !== null && !isset($outputNodePaths[$nextNode->nodeAggregateId->value])) { $outputNodePaths[$nextNode->nodeAggregateId->value] = true; $output[] = $nextNode; @@ -81,21 +86,4 @@ public function evaluate(FlowQuery $flowQuery, array $arguments) $flowQuery->pushOperation('filter', $arguments); } } - - /** - * @param Node $contextNode The node for which the preceding node should be found - * @return Node|null The following node of $contextNode or NULL - */ - protected function getNextForNode(Node $contextNode): ?Node - { - $subgraph = $this->contentRepositoryRegistry->subgraphForNode($contextNode); - - $parentNode = $subgraph->findParentNode($contextNode->nodeAggregateId); - if ($parentNode === null) { - return null; - } - - return $subgraph->findChildNodes($parentNode->nodeAggregateId, FindChildNodesFilter::create()) - ->next($contextNode); - } } diff --git a/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/NextUntilOperation.php b/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/NextUntilOperation.php index 5006fdb6222..f017780a129 100644 --- a/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/NextUntilOperation.php +++ b/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/NextUntilOperation.php @@ -12,6 +12,7 @@ */ use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindChildNodesFilter; +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindSucceedingSiblingNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Projection\ContentGraph\Nodes; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; @@ -70,22 +71,21 @@ public function evaluate(FlowQuery $flowQuery, array $arguments) { $output = []; $outputNodeIdentifiers = []; - $until = []; foreach ($flowQuery->getContext() as $contextNode) { - $nextNodes = $this->getNextForNode($contextNode); + $nextNodes = $this->contentRepositoryRegistry->subgraphForNode($contextNode) + ->findSucceedingSiblingNodes( + $contextNode->nodeAggregateId, + FindSucceedingSiblingNodesFilter::create() + ); if (isset($arguments[0]) && !empty($arguments[0])) { $untilQuery = new FlowQuery($nextNodes); $untilQuery->pushOperation('filter', [$arguments[0]]); - - $until = $untilQuery->getContext(); + $untilNodes = Nodes::fromArray(iterator_to_array($untilQuery)); } - /** @var array $until */ - - if (isset($until[0]) && !empty($until[0])) { - $nextNodes = $nextNodes->until($until[0]); + if (isset($untilNodes) && !$untilNodes->isEmpty()) { + $nextNodes = $nextNodes->previousAll($untilNodes->first()); } - foreach ($nextNodes as $nextNode) { if ($nextNode !== null && !isset($outputNodeIdentifiers[$nextNode->nodeAggregateId->value])) { @@ -101,21 +101,4 @@ public function evaluate(FlowQuery $flowQuery, array $arguments) $flowQuery->pushOperation('filter', [$arguments[1]]); } } - - /** - * @param Node $contextNode The node for which the next nodes should be found - * @return Nodes The following nodes of $contextNode - */ - protected function getNextForNode(Node $contextNode): Nodes - { - $subgraph = $this->contentRepositoryRegistry->subgraphForNode($contextNode); - - $parentNode = $subgraph->findParentNode($contextNode->nodeAggregateId); - if ($parentNode === null) { - return Nodes::createEmpty(); - } - - return $subgraph->findChildNodes($parentNode->nodeAggregateId, FindChildNodesFilter::create()) - ->nextAll($contextNode); - } } diff --git a/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/PrevAllOperation.php b/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/PrevAllOperation.php index 81a1a8afb22..8f735404b31 100644 --- a/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/PrevAllOperation.php +++ b/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/PrevAllOperation.php @@ -12,6 +12,8 @@ */ use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindChildNodesFilter; +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindPrecedingSiblingNodesFilter; +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindSucceedingSiblingNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Projection\ContentGraph\Nodes; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; @@ -69,7 +71,12 @@ public function evaluate(FlowQuery $flowQuery, array $arguments) $output = []; $outputNodeAggregateIds = []; foreach ($flowQuery->getContext() as $contextNode) { - foreach ($this->getPrevForNode($contextNode) as $prevNode) { + $prevNodes = $this->contentRepositoryRegistry->subgraphForNode($contextNode) + ->findPrecedingSiblingNodes( + $contextNode->nodeAggregateId, + FindPrecedingSiblingNodesFilter::create() + )->reverse(); + foreach ($prevNodes as $prevNode) { if ($prevNode !== null && !isset($outputNodeAggregateIds[$prevNode->nodeAggregateId->value]) ) { @@ -84,20 +91,4 @@ public function evaluate(FlowQuery $flowQuery, array $arguments) $flowQuery->pushOperation('filter', $arguments); } } - - /** - * @param Node $contextNode The node for which the preceding node should be found - * @return Nodes The preceding nodes of $contextNode - */ - protected function getPrevForNode(Node $contextNode): Nodes - { - $subgraph = $this->contentRepositoryRegistry->subgraphForNode($contextNode); - $parentNode = $subgraph->findParentNode($contextNode->nodeAggregateId); - if ($parentNode === null) { - return Nodes::createEmpty(); - } - - return $subgraph->findChildNodes($parentNode->nodeAggregateId, FindChildNodesFilter::create()) - ->previousAll($contextNode); - } } diff --git a/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/PrevOperation.php b/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/PrevOperation.php index c8e885f8393..4de65e99311 100644 --- a/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/PrevOperation.php +++ b/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/PrevOperation.php @@ -12,6 +12,7 @@ */ use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindChildNodesFilter; +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindPrecedingSiblingNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Eel\FlowQuery\FlowQuery; @@ -68,10 +69,14 @@ public function evaluate(FlowQuery $flowQuery, array $arguments): void $output = []; $outputNodePaths = []; foreach ($flowQuery->getContext() as $contextNode) { - $nextNode = $this->getPrevForNode($contextNode); - if ($nextNode !== null && !isset($outputNodePaths[$nextNode->nodeAggregateId->value])) { - $outputNodePaths[$nextNode->nodeAggregateId->value] = true; - $output[] = $nextNode; + $previousNode = $this->contentRepositoryRegistry->subgraphForNode($contextNode) + ->findPrecedingSiblingNodes( + $contextNode->nodeAggregateId, + FindPrecedingSiblingNodesFilter::create() + )->first(); + if ($previousNode !== null && !isset($outputNodePaths[$previousNode->nodeAggregateId->value])) { + $outputNodePaths[$previousNode->nodeAggregateId->value] = true; + $output[] = $previousNode; } } $flowQuery->setContext($output); @@ -80,20 +85,4 @@ public function evaluate(FlowQuery $flowQuery, array $arguments): void $flowQuery->pushOperation('filter', $arguments); } } - - /** - * @param Node $contextNode The node for which the preceding node should be found - * @return Node|null The preceeding node of $contextNode or NULL - */ - protected function getPrevForNode(Node $contextNode): ?Node - { - $subgraph = $this->contentRepositoryRegistry->subgraphForNode($contextNode); - $parentNode = $subgraph->findParentNode($contextNode->nodeAggregateId); - if ($parentNode === null) { - return null; - } - - return $subgraph->findChildNodes($parentNode->nodeAggregateId, FindChildNodesFilter::create()) - ->previous($contextNode); - } } diff --git a/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/PrevUntilOperation.php b/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/PrevUntilOperation.php index fe1dea0f61c..d7d483d7061 100644 --- a/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/PrevUntilOperation.php +++ b/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/PrevUntilOperation.php @@ -13,6 +13,7 @@ */ use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindChildNodesFilter; +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindPrecedingSiblingNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Projection\ContentGraph\Nodes; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; @@ -33,7 +34,7 @@ class PrevUntilOperation extends AbstractOperation * * @var string */ - protected static $shortName = 'nextUntil'; + protected static $shortName = 'prevUntil'; /** * {@inheritdoc} @@ -70,22 +71,21 @@ public function evaluate(FlowQuery $flowQuery, array $arguments): void { $output = []; $outputNodeIdentifiers = []; - $until = []; foreach ($flowQuery->getContext() as $contextNode) { - $prevNodes = $this->getPrevForNode($contextNode); + $prevNodes = $this->contentRepositoryRegistry->subgraphForNode($contextNode) + ->findPrecedingSiblingNodes( + $contextNode->nodeAggregateId, + FindPrecedingSiblingNodesFilter::create() + ); if (isset($arguments[0]) && !empty($arguments[0])) { $untilQuery = new FlowQuery($prevNodes); $untilQuery->pushOperation('filter', [$arguments[0]]); - - $until = $untilQuery->getContext(); + $untilNodes = Nodes::fromArray(iterator_to_array($untilQuery)); } - /** @var array $until */ - - if (isset($until[0]) && !empty($until[0])) { - $prevNodes = $prevNodes->until($until[0]); + if (isset($untilNodes) && !$untilNodes->isEmpty()) { + $prevNodes = $prevNodes->previousAll($untilNodes->first())->reverse(); } - foreach ($prevNodes as $prevNode) { if ($prevNode !== null && !isset($outputNodeIdentifiers[$prevNode->nodeAggregateId->value])) { @@ -101,20 +101,4 @@ public function evaluate(FlowQuery $flowQuery, array $arguments): void $flowQuery->pushOperation('filter', [$arguments[1]]); } } - - /** - * @param Node $contextNode The node for which the next nodes should be found - * @return Nodes The following nodes of $contextNode - */ - protected function getPrevForNode(Node $contextNode): Nodes - { - $subgraph = $this->contentRepositoryRegistry->subgraphForNode($contextNode); - $parentNode = $subgraph->findParentNode($contextNode->nodeAggregateId); - if ($parentNode === null) { - return Nodes::createEmpty(); - } - - return $subgraph->findChildNodes($parentNode->nodeAggregateId, FindChildNodesFilter::create()) - ->previousAll($contextNode); - } }