From 27fe1e95f2feeb1a6ccff4af8201e105a741ef6e Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Sun, 12 May 2024 13:08:32 +0200 Subject: [PATCH] FEATURE: Introduce Node access FlowQuery operations see https://github.com/neos/neos-development-collection/issues/5022 --- .../FlowQueryOperations/IdOperation.php | 77 ++++++++++++++++ .../FlowQueryOperations/LabelOperation.php | 77 ++++++++++++++++ .../NodeTypeNameOperation.php | 90 +++++++++++++++++++ .../ExpressionBasedNodeLabelGenerator.php | 4 +- .../Features/Fusion/FlowQuery.feature | 46 ++++++++++ 5 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/IdOperation.php create mode 100644 Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/LabelOperation.php create mode 100644 Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/NodeTypeNameOperation.php diff --git a/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/IdOperation.php b/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/IdOperation.php new file mode 100644 index 00000000000..82d92207987 --- /dev/null +++ b/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/IdOperation.php @@ -0,0 +1,77 @@ + $context $context onto which this operation should be applied (array or array-like object) + * @return boolean + */ + public function canEvaluate($context): bool + { + return (isset($context[0]) && $context[0] instanceof Node); + } + + /** + * {@inheritdoc} + * + * @param FlowQuery $flowQuery the FlowQuery object + * @param array $arguments the arguments for this operation + * @return mixed + * @throws FlowQueryException + */ + public function evaluate(FlowQuery $flowQuery, array $arguments) + { + if ($arguments !== []) { + throw new FlowQueryException(static::$shortName . '() does not require any argument.', 1715510778); + } + $node = $flowQuery->getContext()[0] ?? null; + if (!$node instanceof Node) { + return null; + } + return $node->nodeAggregateId->value; + } +} diff --git a/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/LabelOperation.php b/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/LabelOperation.php new file mode 100644 index 00000000000..3790819e345 --- /dev/null +++ b/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/LabelOperation.php @@ -0,0 +1,77 @@ + $context $context onto which this operation should be applied (array or array-like object) + * @return boolean + */ + public function canEvaluate($context): bool + { + return (isset($context[0]) && $context[0] instanceof Node); + } + + /** + * {@inheritdoc} + * + * @param FlowQuery $flowQuery the FlowQuery object + * @param array $arguments the arguments for this operation + * @return mixed + * @throws FlowQueryException + */ + public function evaluate(FlowQuery $flowQuery, array $arguments) + { + if ($arguments !== []) { + throw new FlowQueryException(static::$shortName . '() does not require any argument.', 1715510778); + } + $node = $flowQuery->getContext()[0] ?? null; + if (!$node instanceof Node) { + return null; + } + return $node->getLabel(); + } +} diff --git a/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/NodeTypeNameOperation.php b/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/NodeTypeNameOperation.php new file mode 100644 index 00000000000..4664a8c5009 --- /dev/null +++ b/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/NodeTypeNameOperation.php @@ -0,0 +1,90 @@ + $context $context onto which this operation should be applied (array or array-like object) + * @return boolean + */ + public function canEvaluate($context): bool + { + return (isset($context[0]) && $context[0] instanceof Node); + } + + /** + * {@inheritdoc} + * + * @param FlowQuery $flowQuery the FlowQuery object + * @param array $arguments the arguments for this operation + * @return mixed + * @throws FlowQueryException + */ + public function evaluate(FlowQuery $flowQuery, array $arguments) + { + if ($arguments !== []) { + throw new FlowQueryException(static::$shortName . '() does not require any argument.', 1715510778); + } + $node = $flowQuery->getContext()[0] ?? null; + if (!$node instanceof Node) { + return null; + } + + $contentRepository = $this->contentRepositoryRegistry->get($node->subgraphIdentity->contentRepositoryId); + + return $contentRepository->getNodeTypeManager()->hasNodeType($node->nodeTypeName) + ? $node->nodeTypeName + : NodeTypeNameFactory::forFallback()->value; + } +} diff --git a/Neos.ContentRepositoryRegistry/Classes/NodeLabel/ExpressionBasedNodeLabelGenerator.php b/Neos.ContentRepositoryRegistry/Classes/NodeLabel/ExpressionBasedNodeLabelGenerator.php index 8ed9333b6a0..0babece2680 100644 --- a/Neos.ContentRepositoryRegistry/Classes/NodeLabel/ExpressionBasedNodeLabelGenerator.php +++ b/Neos.ContentRepositoryRegistry/Classes/NodeLabel/ExpressionBasedNodeLabelGenerator.php @@ -37,7 +37,9 @@ class ExpressionBasedNodeLabelGenerator implements NodeLabelGeneratorInterface /** * @var string */ - protected $expression = '${(node.nodeType.label ? node.nodeType.label : node.nodeType.name) + \' (\' + node.name + \')\'}'; + protected $expression = <<<'EEL' + ${(node.nodeType.label ? node.nodeType.label : node.nodeType.name) + (node.nodeName ? ' (' + node.nodeName.value + ')' : '')} + EEL; /** * @return string diff --git a/Neos.Neos/Tests/Behavior/Features/Fusion/FlowQuery.feature b/Neos.Neos/Tests/Behavior/Features/Fusion/FlowQuery.feature index b7073940274..5681e0390f0 100644 --- a/Neos.Neos/Tests/Behavior/Features/Fusion/FlowQuery.feature +++ b/Neos.Neos/Tests/Behavior/Features/Fusion/FlowQuery.feature @@ -395,3 +395,49 @@ Feature: Tests for the "Neos.ContentRepository" Flow Query methods. removeNode: a nothingToRemove: a1a4,a1a4,a1a4 """ + + Scenario: Node accessors (final Node access operations) + When the Fusion context node is "a1" + When I execute the following Fusion code: + """fusion + test = Neos.Fusion:DataStructure { + property = ${q(node).property('title')} + identifier = ${q(node).id()} + label = ${q(node).label()} + nodeTypeName = ${q(node).nodeTypeName()} + @process.render = ${Json.stringify(value, ['JSON_PRETTY_PRINT'])} + } + """ + Then I expect the following Fusion rendering result: + """ + { + "property": "Node a1", + "identifier": "a1", + "label": "Neos.Neos:Test.DocumentType1", + "nodeTypeName": "Neos.Neos:Test.DocumentType1" + } + """ + # changing the node type config will invoke the Neos.Neos:FallbackNode handling + When I change the node types in content repository "default" to: + """yaml + 'Neos.Neos:FallbackNode': {} + """ + When I execute the following Fusion code: + """fusion + test = Neos.Fusion:DataStructure { + property = ${q(node).property('title')} + identifier = ${q(node).id()} + label = ${q(node).label()} + nodeTypeName = ${q(node).nodeTypeName()} + @process.render = ${Json.stringify(value, ['JSON_PRETTY_PRINT'])} + } + """ + Then I expect the following Fusion rendering result: + """ + { + "property": "Node a1", + "identifier": "a1", + "label": "Neos.Neos:Test.DocumentType1", + "nodeTypeName": "Neos.Neos:FallbackNode" + } + """