From 627721881c9147b14a55158c084dca193b3386a9 Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Sun, 12 Nov 2023 09:21:52 +0100 Subject: [PATCH 1/2] BUGFIX: #3624 Node::getProperty does not always return list for references EEL can only operate on an array of nodes if the `[0]` item is a node (simple duck typing) Instead of fixing eel like proposed here https://github.com/neos/neos-development-collection/pull/3946 with this fix we avoid returning non 0 indexed arrays here: ``` ${q(node).property("someReference")} ``` Currently, this might indeed return an array with holes like `[1 => NODE, 2 => NODE, 5 => NODE]` if the identifiers in fields 0, 3 and 4 are not resolvable. Thats because of the "unsafe" `array_filter` method in `resolvePropertyReferences` https://github.com/neos/neos-development-collection/blob/378a029d0cc7ea6acb853751e7592873584a4aac/Neos.ContentRepository/Classes/Domain/Model/Node.php#L961 which will leave holes in the array. Using `array_filter` was introduced with Neos 2.2 so this is technically a regression of https://github.com/neos/neos-development-collection/commit/87804e12082e7d6d06bd22f50739e20eeaa45539 ^^ --- .../Classes/Domain/Model/Node.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Neos.ContentRepository/Classes/Domain/Model/Node.php b/Neos.ContentRepository/Classes/Domain/Model/Node.php index a19a9170483..c7cdf56b2b7 100644 --- a/Neos.ContentRepository/Classes/Domain/Model/Node.php +++ b/Neos.ContentRepository/Classes/Domain/Model/Node.php @@ -960,11 +960,15 @@ public function getProperty($propertyName, bool $returnNodesAsIdentifiers = fals */ protected function resolvePropertyReferences(array $value = []): array { - $nodes = array_map(function ($nodeIdentifier) { - return $this->context->getNodeByIdentifier($nodeIdentifier); - }, $value); - - return array_filter($nodes); + $nodes = []; + foreach ($value as $nodeIdentifier) { + $node = $this->context->getNodeByIdentifier($nodeIdentifier); + // $node can be NULL if the node is not visible (or removed) according to the current content context: + if ($node !== null) { + $nodes[] = $node; + } + } + return $nodes; } /** From 858a50063a8e7a23c462bb60c573a9e546f270d8 Mon Sep 17 00:00:00 2001 From: Bastian Waidelich Date: Sun, 14 Jan 2024 12:51:57 +0100 Subject: [PATCH 2/2] Add unit test --- .../Tests/Functional/Domain/NodesTest.php | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Neos.ContentRepository/Tests/Functional/Domain/NodesTest.php b/Neos.ContentRepository/Tests/Functional/Domain/NodesTest.php index d34d6f52fe8..78ec4d61988 100644 --- a/Neos.ContentRepository/Tests/Functional/Domain/NodesTest.php +++ b/Neos.ContentRepository/Tests/Functional/Domain/NodesTest.php @@ -1412,6 +1412,34 @@ public function getPropertyReturnsReferencedNodesInCorrectWorkspace() self::assertSame($testReferencedNodeProperty->getWorkspace(), $testReferencedNode->getWorkspace()); } + /** + * @see https://github.com/neos/neos-development-collection/issues/3624 + * @test + */ + public function getPropertyReturnsReferencedNodesWithoutHolesInArrayKeys(): void + { + $nodeTypeManager = $this->objectManager->get(NodeTypeManager::class); + $nodeType = $nodeTypeManager->getNodeType('Neos.ContentRepository.Testing:NodeTypeWithReferences'); + + $rootNode = $this->context->getNode('/'); + $nodeA = $rootNode->createNode('node-a', $nodeType, '30e893c1-caef-0ca5-b53d-e5699bb8e506'); + $nodeB = $rootNode->createNode('node-b', $nodeType, '81c848ed-abb5-7608-a5db-7eea0331ccfa'); + $nodeC = $rootNode->createNode('node-c', $nodeType, 'e3b99700-f632-4a4c-2f93-0ad07eaf733f'); + + $expectedNodes = [0 => $nodeB, 1 => $nodeC]; + + $nodeA->setProperty('property2', '81c848ed-abb5-7608-a5db-7eea0331ccfa'); + $nodeA->setProperty('property3', [ + '00000000-0000-0000-0000-000000000001', + '81c848ed-abb5-7608-a5db-7eea0331ccfa', + '00000000-0000-0000-0000-000000000002', + 'e3b99700-f632-4a4c-2f93-0ad07eaf733f' + ]); + + $actualProperties = $nodeA->getProperties(); + self::assertSame($expectedNodes, $actualProperties['property3']); + } + /** * @test */