From 3ac30804e6c9a913e85aaa5912fc2895feb5e74a Mon Sep 17 00:00:00 2001 From: Bastian Waidelich Date: Thu, 18 Apr 2024 16:31:55 +0200 Subject: [PATCH] WIP: FEATURE: Overhaul NodeTypeManager Resolves: #4228 --- ...yStringNodeBasedNodeTypeManagerFactory.php | 25 +- .../WorkspaceWritingDuringPublication.php | 21 +- .../NodeType/ClosureNodeTypeProvider.php | 157 ++++++++++++ .../Classes/NodeType/NodeTypeManager.php | 241 ++---------------- .../NodeType/NodeTypeProviderInterface.php | 23 ++ .../Classes/NodeType/NodeTypes.php | 115 +++++++++ .../Dto/NodeAggregateIdsByNodePathsTest.php | 45 ++-- .../Unit/NodeType/NodeTypeManagerTest.php | 27 +- .../DefaultNodeTypeManagerFactory.php | 13 +- .../Functional/Fusion/NodeHelperTest.php | 8 +- .../Service/NodeTypeSchemaBuilderTest.php | 7 +- 11 files changed, 388 insertions(+), 294 deletions(-) create mode 100644 Neos.ContentRepository.Core/Classes/NodeType/ClosureNodeTypeProvider.php create mode 100644 Neos.ContentRepository.Core/Classes/NodeType/NodeTypeProviderInterface.php create mode 100644 Neos.ContentRepository.Core/Classes/NodeType/NodeTypes.php diff --git a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/GherkinPyStringNodeBasedNodeTypeManagerFactory.php b/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/GherkinPyStringNodeBasedNodeTypeManagerFactory.php index cc91ca70224..14c43b0458f 100644 --- a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/GherkinPyStringNodeBasedNodeTypeManagerFactory.php +++ b/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/GherkinPyStringNodeBasedNodeTypeManagerFactory.php @@ -15,6 +15,7 @@ namespace Neos\ContentRepository\BehavioralTests\TestSuite\Behavior; use Behat\Gherkin\Node\PyStringNode; +use Neos\ContentRepository\Core\NodeType\ClosureNodeTypeProvider; use Neos\ContentRepository\Core\NodeType\NodeLabelGeneratorFactoryInterface; use Neos\ContentRepository\Core\NodeType\NodeLabelGeneratorInterface; use Neos\ContentRepository\Core\NodeType\NodeType; @@ -45,18 +46,20 @@ public function build(ContentRepositoryId $contentRepositoryId, array $options): public static function initializeWithPyStringNode(PyStringNode $nodeTypesToUse): void { self::$nodeTypesToUse = new NodeTypeManager( - fn (): array => Yaml::parse($nodeTypesToUse->getRaw()) ?? [], - new class implements NodeLabelGeneratorFactoryInterface { - public function create(NodeType $nodeType): NodeLabelGeneratorInterface - { - return new class implements NodeLabelGeneratorInterface { - public function getLabel(Node $node): string - { - return $node->nodeTypeName->value; - } - }; + new ClosureNodeTypeProvider( + fn (): array => Yaml::parse($nodeTypesToUse->getRaw()) ?? [], + new class implements NodeLabelGeneratorFactoryInterface { + public function create(NodeType $nodeType): NodeLabelGeneratorInterface + { + return new class implements NodeLabelGeneratorInterface { + public function getLabel(Node $node): string + { + return $node->nodeTypeName->value; + } + }; + } } - } + ) ); } diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Functional/Feature/WorkspacePublication/WorkspaceWritingDuringPublication.php b/Neos.ContentRepository.BehavioralTests/Tests/Functional/Feature/WorkspacePublication/WorkspaceWritingDuringPublication.php index 4d532e7a805..c33e4fc4be4 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Functional/Feature/WorkspacePublication/WorkspaceWritingDuringPublication.php +++ b/Neos.ContentRepository.BehavioralTests/Tests/Functional/Feature/WorkspacePublication/WorkspaceWritingDuringPublication.php @@ -31,6 +31,7 @@ use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Command\CreateRootWorkspace; use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Command\CreateWorkspace; use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Command\RebaseWorkspace; +use Neos\ContentRepository\Core\NodeType\ClosureNodeTypeProvider; use Neos\ContentRepository\Core\NodeType\DefaultNodeLabelGeneratorFactory; use Neos\ContentRepository\Core\NodeType\NodeTypeManager; use Neos\ContentRepository\Core\NodeType\NodeTypeName; @@ -81,17 +82,19 @@ public function getContentDimensionsOrderedByPriority(): array }; GherkinPyStringNodeBasedNodeTypeManagerFactory::$nodeTypesToUse = new NodeTypeManager( - fn (): array => [ - 'Neos.ContentRepository:Root' => [], - 'Neos.ContentRepository.Testing:Document' => [ - 'properties' => [ - 'title' => [ - 'type' => 'string' + new ClosureNodeTypeProvider( + fn (): array => [ + 'Neos.ContentRepository:Root' => [], + 'Neos.ContentRepository.Testing:Document' => [ + 'properties' => [ + 'title' => [ + 'type' => 'string' + ] ] ] - ] - ], - new DefaultNodeLabelGeneratorFactory() + ], + new DefaultNodeLabelGeneratorFactory() + ) ); $this->contentRepositoryRegistry = $this->objectManager->get(ContentRepositoryRegistry::class); diff --git a/Neos.ContentRepository.Core/Classes/NodeType/ClosureNodeTypeProvider.php b/Neos.ContentRepository.Core/Classes/NodeType/ClosureNodeTypeProvider.php new file mode 100644 index 00000000000..e11b8f50ef9 --- /dev/null +++ b/Neos.ContentRepository.Core/Classes/NodeType/ClosureNodeTypeProvider.php @@ -0,0 +1,157 @@ +cachedNodeTypes = NodeTypes::fromArray([]); + } + + public function getNodeTypes(): NodeTypes + { + if ($this->cachedNodeTypes->isEmpty()) { + $completeNodeTypeConfiguration = ($this->nodeTypeConfigLoader)(); + // the root node type must always exist + $completeNodeTypeConfiguration[NodeTypeName::ROOT_NODE_TYPE_NAME] ??= []; + foreach (array_keys($completeNodeTypeConfiguration) as $nodeTypeName) { + if (!is_string($nodeTypeName)) { + continue; + } + if (!is_array($completeNodeTypeConfiguration[$nodeTypeName])) { + continue; + } + $this->loadNodeType($nodeTypeName, $completeNodeTypeConfiguration); + } + } + return $this->cachedNodeTypes; + } + + /** + * Load one node type, if it is not loaded yet. + * + * @param array $completeNodeTypeConfiguration the full node type configuration for all node types + * @throws NodeConfigurationException + * @throws NodeTypeIsFinalException + * @throws NodeTypeNotFoundException + */ + private function loadNodeType(string $nodeTypeName, array &$completeNodeTypeConfiguration): NodeType + { + $cachedNodeType = $this->cachedNodeTypes->get($nodeTypeName); + if ($cachedNodeType !== null) { + return $cachedNodeType; + } + + if (!isset($completeNodeTypeConfiguration[$nodeTypeName])) { + throw new NodeTypeNotFoundException('Node type "' . $nodeTypeName . '" does not exist', 1316451800); + } + + $nodeTypeConfiguration = $completeNodeTypeConfiguration[$nodeTypeName]; + try { + $superTypes = isset($nodeTypeConfiguration['superTypes']) + ? $this->evaluateSuperTypesConfiguration( + $nodeTypeConfiguration['superTypes'], + $completeNodeTypeConfiguration + ) + : []; + } catch (NodeConfigurationException $exception) { + throw new NodeConfigurationException('Node type "' . $nodeTypeName . '" sets super type with a non-string key to NULL.', 1416578395, $exception); + } catch (NodeTypeIsFinalException $exception) { + throw new NodeTypeIsFinalException('Node type "' . $nodeTypeName . '" has a super type "' . $exception->getMessage() . '" which is final.', 1316452423, $exception); + } + + // Remove unset properties + $nodeTypeConfiguration['properties'] = array_filter($nodeTypeConfiguration['properties'] ?? [], static fn ($propertyConfiguration) => $propertyConfiguration !== null); + if ($nodeTypeConfiguration['properties'] === []) { + unset($nodeTypeConfiguration['properties']); + } + + $nodeType = new NodeType( + NodeTypeName::fromString($nodeTypeName), + $superTypes, + $nodeTypeConfiguration, + $this->nodeLabelGeneratorFactory + ); + + $this->cachedNodeTypes = $this->cachedNodeTypes->with($nodeType); + return $nodeType; + } + + /** + * Evaluates the given superTypes configuation and returns the array of effective superTypes. + * + * @param array $superTypesConfiguration + * @param array $completeNodeTypeConfiguration + * @return array + */ + private function evaluateSuperTypesConfiguration( + array $superTypesConfiguration, + array $completeNodeTypeConfiguration + ): array { + $superTypes = []; + foreach ($superTypesConfiguration as $superTypeName => $enabled) { + if (!is_string($superTypeName)) { + throw new NodeConfigurationException( + 'superTypes must be a dictionary; the array format was deprecated since Neos 2.0', + 1651821391 + ); + } + $superTypes[$superTypeName] = $this->evaluateSuperTypeConfiguration( + $superTypeName, + $enabled, + $completeNodeTypeConfiguration + ); + } + + return $superTypes; + } + + /** + * Evaluates a single superType configuration and returns the NodeType if enabled. + * + * @param array $completeNodeTypeConfiguration + * @throws NodeConfigurationException + * @throws NodeTypeIsFinalException + */ + private function evaluateSuperTypeConfiguration( + string $superTypeName, + ?bool $enabled, + array &$completeNodeTypeConfiguration + ): ?NodeType { + // Skip unset node types + if ($enabled === false || $enabled === null) { + return null; + } + + $superType = $this->loadNodeType($superTypeName, $completeNodeTypeConfiguration); + if ($superType->isFinal() === true) { + throw new NodeTypeIsFinalException($superType->name->value, 1444944148); + } + + return $superType; + } +} diff --git a/Neos.ContentRepository.Core/Classes/NodeType/NodeTypeManager.php b/Neos.ContentRepository.Core/Classes/NodeType/NodeTypeManager.php index 4c98cdf9383..ce2ca3000c0 100644 --- a/Neos.ContentRepository.Core/Classes/NodeType/NodeTypeManager.php +++ b/Neos.ContentRepository.Core/Classes/NodeType/NodeTypeManager.php @@ -24,21 +24,14 @@ /** * Manager for node types - * @api Note: The constructor is not part of the public API + * @api */ final class NodeTypeManager { - /** - * Node types, indexed by name - * - * @var array - */ - private array $cachedNodeTypes = []; - /** * Node types, indexed by supertype (also including abstract node types) * - * @var array> + * @var array */ private array $cachedSubNodeTypes = []; @@ -46,8 +39,7 @@ final class NodeTypeManager * @internal */ public function __construct( - private readonly \Closure $nodeTypeConfigLoader, - private readonly NodeLabelGeneratorFactoryInterface $nodeLabelGeneratorFactory + private readonly NodeTypeProviderInterface $nodeTypeProvider ) { } @@ -59,16 +51,10 @@ public function __construct( */ public function getNodeTypes(bool $includeAbstractNodeTypes = true): array { - if ($this->cachedNodeTypes === []) { - $this->loadNodeTypes(); - } if ($includeAbstractNodeTypes) { - return $this->cachedNodeTypes; + return $this->nodeTypeProvider->getNodeTypes()->toArray(); } - - return array_filter($this->cachedNodeTypes, function ($nodeType) { - return !$nodeType->isAbstract(); - }); + return $this->nodeTypeProvider->getNodeTypes()->withoutAbstractNodeTypes()->toArray(); } /** @@ -80,30 +66,18 @@ public function getNodeTypes(bool $includeAbstractNodeTypes = true): array */ public function getSubNodeTypes(string|NodeTypeName $superTypeName, bool $includeAbstractNodeTypes = true): array { - if ($superTypeName instanceof NodeTypeName) { - $superTypeName = $superTypeName->value; + if (is_string($superTypeName)) { + $superTypeName = NodeTypeName::fromString($superTypeName); } - if ($this->cachedNodeTypes === []) { - $this->loadNodeTypes(); - } - - if (!isset($this->cachedSubNodeTypes[$superTypeName])) { - $filteredNodeTypes = []; - foreach ($this->cachedNodeTypes as $nodeTypeName => $nodeType) { - if ($nodeType->isOfType($superTypeName) && $nodeTypeName !== $superTypeName) { - $filteredNodeTypes[$nodeTypeName] = $nodeType; - } - } - $this->cachedSubNodeTypes[$superTypeName] = $filteredNodeTypes; + if (!array_key_exists($superTypeName->value, $this->cachedSubNodeTypes)) { + $this->cachedSubNodeTypes[$superTypeName->value] = $this->nodeTypeProvider->getNodeTypes()->filter( + fn (NodeType $nodeType) => !$nodeType->name->equals($superTypeName) && $nodeType->isOfType($superTypeName) + ); } - - if ($includeAbstractNodeTypes === false) { - return array_filter($this->cachedSubNodeTypes[$superTypeName], function (NodeType $nodeType) { - return !$nodeType->isAbstract(); - }); + if ($includeAbstractNodeTypes) { + return $this->cachedSubNodeTypes[$superTypeName->value]->toArray(); } - - return $this->cachedSubNodeTypes[$superTypeName]; + return $this->cachedSubNodeTypes[$superTypeName->value]->withoutAbstractNodeTypes()->toArray(); } /** @@ -113,16 +87,7 @@ public function getSubNodeTypes(string|NodeTypeName $superTypeName, bool $includ */ public function getNodeType(string|NodeTypeName $nodeTypeName): ?NodeType { - if ($nodeTypeName instanceof NodeTypeName) { - $nodeTypeName = $nodeTypeName->value; - } - if ($this->cachedNodeTypes === []) { - $this->loadNodeTypes(); - } - if (isset($this->cachedNodeTypes[$nodeTypeName])) { - return $this->cachedNodeTypes[$nodeTypeName]; - } - return null; + return $this->nodeTypeProvider->getNodeTypes()->get($nodeTypeName); } /** @@ -133,62 +98,7 @@ public function getNodeType(string|NodeTypeName $nodeTypeName): ?NodeType */ public function hasNodeType(string|NodeTypeName $nodeTypeName): bool { - if ($nodeTypeName instanceof NodeTypeName) { - $nodeTypeName = $nodeTypeName->value; - } - if ($this->cachedNodeTypes === []) { - $this->loadNodeTypes(); - } - return isset($this->cachedNodeTypes[$nodeTypeName]); - } - - /** - * Loads all node types into memory. - */ - private function loadNodeTypes(): void - { - $completeNodeTypeConfiguration = ($this->nodeTypeConfigLoader)(); - - // the root node type must always exist - $completeNodeTypeConfiguration[NodeTypeName::ROOT_NODE_TYPE_NAME] ??= []; - - foreach (array_keys($completeNodeTypeConfiguration) as $nodeTypeName) { - if (!is_string($nodeTypeName)) { - continue; - } - if (!is_array($completeNodeTypeConfiguration[$nodeTypeName])) { - continue; - } - $this->loadNodeType($nodeTypeName, $completeNodeTypeConfiguration); - } - } - - /** - * This method can be used by Functional of Behavioral Tests to completely - * override the node types known in the system. - * - * In order to reset the node type override, an empty array can be passed in. - * In this case, the system-node-types are used again. - * - * @internal - * @param array $completeNodeTypeConfiguration - */ - public function overrideNodeTypes(array $completeNodeTypeConfiguration): void - { - $this->cachedNodeTypes = []; - - if ($completeNodeTypeConfiguration === []) { - // as cachedNodeTypes is now empty loadNodeTypes will reload the default nodeTypes - return; - } - - // the root node type must always exist - $completeNodeTypeConfiguration[NodeTypeName::ROOT_NODE_TYPE_NAME] ??= []; - - foreach (array_keys($completeNodeTypeConfiguration) as $nodeTypeName) { - /** @var string $nodeTypeName */ - $this->loadNodeType($nodeTypeName, $completeNodeTypeConfiguration); - } + return $this->nodeTypeProvider->getNodeTypes()->has($nodeTypeName); } /** @@ -258,129 +168,10 @@ public function isNodeTypeAllowedAsChildToTetheredNode(NodeType $parentNodeType, // We ignore this because the configuration might just not have any constraints, if the childNode was not configured the exception above would have been thrown. $childNodeConstraintConfiguration = []; } - $constraints = Arrays::arrayMergeRecursiveOverrule($constraints, $childNodeConstraintConfiguration); - return ConstraintCheck::create($constraints)->isNodeTypeAllowed($nodeType); } - /** - * Load one node type, if it is not loaded yet. - * - * @param array $completeNodeTypeConfiguration the full node type configuration for all node types - * @throws NodeConfigurationException - * @throws NodeTypeIsFinalException - * @throws NodeTypeNotFoundException - */ - private function loadNodeType(string $nodeTypeName, array &$completeNodeTypeConfiguration): NodeType - { - if (isset($this->cachedNodeTypes[$nodeTypeName])) { - return $this->cachedNodeTypes[$nodeTypeName]; - } - - if (!isset($completeNodeTypeConfiguration[$nodeTypeName])) { - throw new NodeTypeNotFoundException('Node type "' . $nodeTypeName . '" does not exist', 1316451800); - } - - $nodeTypeConfiguration = $completeNodeTypeConfiguration[$nodeTypeName]; - try { - $superTypes = isset($nodeTypeConfiguration['superTypes']) - ? $this->evaluateSuperTypesConfiguration( - $nodeTypeConfiguration['superTypes'], - $completeNodeTypeConfiguration - ) - : []; - } catch (NodeConfigurationException $exception) { - throw new NodeConfigurationException( - 'Node type "' . $nodeTypeName . '" sets super type with a non-string key to NULL.', - 1416578395 - ); - } catch (NodeTypeIsFinalException $exception) { - throw new NodeTypeIsFinalException( - 'Node type "' . $nodeTypeName . '" has a super type "' . $exception->getMessage() . '" which is final.', - 1316452423 - ); - } - - // Remove unset properties - $properties = []; - if (isset($nodeTypeConfiguration['properties']) && is_array($nodeTypeConfiguration['properties'])) { - $properties = $nodeTypeConfiguration['properties']; - } - - $nodeTypeConfiguration['properties'] = array_filter($properties, function ($propertyConfiguration) { - return $propertyConfiguration !== null; - }); - - if ($nodeTypeConfiguration['properties'] === []) { - unset($nodeTypeConfiguration['properties']); - } - - $nodeType = new NodeType( - NodeTypeName::fromString($nodeTypeName), - $superTypes, - $nodeTypeConfiguration, - $this->nodeLabelGeneratorFactory - ); - - $this->cachedNodeTypes[$nodeTypeName] = $nodeType; - return $nodeType; - } - - /** - * Evaluates the given superTypes configuation and returns the array of effective superTypes. - * - * @param array $superTypesConfiguration - * @param array $completeNodeTypeConfiguration - * @return array - */ - private function evaluateSuperTypesConfiguration( - array $superTypesConfiguration, - array $completeNodeTypeConfiguration - ): array { - $superTypes = []; - foreach ($superTypesConfiguration as $superTypeName => $enabled) { - if (!is_string($superTypeName)) { - throw new NodeConfigurationException( - 'superTypes must be a dictionary; the array format was deprecated since Neos 2.0', - 1651821391 - ); - } - $superTypes[$superTypeName] = $this->evaluateSuperTypeConfiguration( - $superTypeName, - $enabled, - $completeNodeTypeConfiguration - ); - } - - return $superTypes; - } - - /** - * Evaluates a single superType configuration and returns the NodeType if enabled. - * - * @param array $completeNodeTypeConfiguration - * @throws NodeConfigurationException - * @throws NodeTypeIsFinalException - */ - private function evaluateSuperTypeConfiguration( - string $superTypeName, - ?bool $enabled, - array &$completeNodeTypeConfiguration - ): ?NodeType { - // Skip unset node types - if ($enabled === false || $enabled === null) { - return null; - } - - $superType = $this->loadNodeType($superTypeName, $completeNodeTypeConfiguration); - if ($superType->isFinal() === true) { - throw new NodeTypeIsFinalException($superType->name->value, 1444944148); - } - - return $superType; - } - /** * @internal helper to throw if the NodeType doesn't exit */ diff --git a/Neos.ContentRepository.Core/Classes/NodeType/NodeTypeProviderInterface.php b/Neos.ContentRepository.Core/Classes/NodeType/NodeTypeProviderInterface.php new file mode 100644 index 00000000000..e617822c86d --- /dev/null +++ b/Neos.ContentRepository.Core/Classes/NodeType/NodeTypeProviderInterface.php @@ -0,0 +1,23 @@ + + */ +final class NodeTypes implements IteratorAggregate +{ + /** + * @var array + */ + private array $nodeTypesByName; + + private function __construct(NodeType ...$items) + { + $this->nodeTypesByName = $items; + } + + /** + * @param array $nodeTypes + */ + public static function fromArray(array $nodeTypes): self + { + $nodeTypesByName = []; + foreach ($nodeTypes as $index => $nodeType) { + $nodeType instanceof NodeType || throw new InvalidArgumentException(sprintf('expected instance of %s, got: %s at index %s', NodeType::class, get_debug_type($nodeType), $index), 1713436192); + !array_key_exists($nodeType->name->value, $nodeTypesByName) || throw new InvalidArgumentException(sprintf('Node type "%s" is already registered at index %s', $nodeType->name->value, $index), 1713436195); + $nodeTypesByName[$nodeType->name->value] = $nodeType; + } + return new self(...$nodeTypesByName); + } + + public function with(NodeType $nodeType): self + { + if ($this->has($nodeType->name)) { + throw new InvalidArgumentException(sprintf('Node type "%s" is already registered', $nodeType->name->value), 1713448999); + } + return new self(...[...$this->nodeTypesByName, $nodeType->name->value => $nodeType]); + } + + public function has(NodeTypeName|string $nodeTypeName): bool + { + if ($nodeTypeName instanceof NodeTypeName) { + $nodeTypeName = $nodeTypeName->value; + } + return array_key_exists($nodeTypeName, $this->nodeTypesByName); + } + + public function get(NodeTypeName|string $nodeTypeName): ?NodeType + { + if ($nodeTypeName instanceof NodeTypeName) { + $nodeTypeName = $nodeTypeName->value; + } + return $this->nodeTypesByName[$nodeTypeName] ?? null; + } + + public function isEmpty(): bool + { + return $this->nodeTypesByName === []; + } + + public function withoutAbstractNodeTypes(): self + { + return $this->filter(fn (NodeType $nodeType) => !$nodeType->isAbstract()); + } + + /** + * @param Closure(NodeType): bool $callback + */ + public function filter(Closure $callback): self + { + return self::fromArray(array_filter($this->nodeTypesByName, $callback(...))); + } + + /** + * @param Closure(NodeType): mixed $callback + * @return array + */ + public function map(Closure $callback): array + { + return array_map($callback(...), $this->nodeTypesByName); + } + + public function getIterator(): Traversable + { + return yield from $this->nodeTypesByName; + } + + /** + * @return array + */ + public function toArray(): array + { + return $this->nodeTypesByName; + } +} diff --git a/Neos.ContentRepository.Core/Tests/Unit/Feature/NodeCreation/Dto/NodeAggregateIdsByNodePathsTest.php b/Neos.ContentRepository.Core/Tests/Unit/Feature/NodeCreation/Dto/NodeAggregateIdsByNodePathsTest.php index 04d9f727cf6..db0c2ea66e6 100644 --- a/Neos.ContentRepository.Core/Tests/Unit/Feature/NodeCreation/Dto/NodeAggregateIdsByNodePathsTest.php +++ b/Neos.ContentRepository.Core/Tests/Unit/Feature/NodeCreation/Dto/NodeAggregateIdsByNodePathsTest.php @@ -15,6 +15,7 @@ namespace Neos\ContentRepository\Core\Tests\Unit\Feature\NodeCreation\Dto; use Neos\ContentRepository\Core\Feature\NodeCreation\Dto\NodeAggregateIdsByNodePaths; +use Neos\ContentRepository\Core\NodeType\ClosureNodeTypeProvider; use Neos\ContentRepository\Core\NodeType\DefaultNodeLabelGeneratorFactory; use Neos\ContentRepository\Core\NodeType\NodeTypeManager; use Neos\ContentRepository\Core\NodeType\NodeTypeName; @@ -34,30 +35,32 @@ class NodeAggregateIdsByNodePathsTest extends TestCase public function testCompleteForNodeOfType(NodeAggregateIdsByNodePaths $subject, array $expectedNodeAggregateIdsByPath): void { $nodeTypeManager = new NodeTypeManager( - fn (): array => [ - 'Neos.ContentRepository.Testing:Content' => [], - 'Neos.ContentRepository.Testing:LeafDocument' => [ - 'childNodes' => [ - 'grandchild1' => [ - 'type' => 'Neos.ContentRepository.Testing:Content' - ], - 'grandchild2' => [ - 'type' => 'Neos.ContentRepository.Testing:Content' + new ClosureNodeTypeProvider( + fn (): array => [ + 'Neos.ContentRepository.Testing:Content' => [], + 'Neos.ContentRepository.Testing:LeafDocument' => [ + 'childNodes' => [ + 'grandchild1' => [ + 'type' => 'Neos.ContentRepository.Testing:Content' + ], + 'grandchild2' => [ + 'type' => 'Neos.ContentRepository.Testing:Content' + ] ] - ] - ], - 'Neos.ContentRepository.Testing:Document' => [ - 'childNodes' => [ - 'child1' => [ - 'type' => 'Neos.ContentRepository.Testing:LeafDocument' - ], - 'child2' => [ - 'type' => 'Neos.ContentRepository.Testing:LeafDocument' + ], + 'Neos.ContentRepository.Testing:Document' => [ + 'childNodes' => [ + 'child1' => [ + 'type' => 'Neos.ContentRepository.Testing:LeafDocument' + ], + 'child2' => [ + 'type' => 'Neos.ContentRepository.Testing:LeafDocument' + ] ] ] - ] - ], - new DefaultNodeLabelGeneratorFactory() + ], + new DefaultNodeLabelGeneratorFactory() + ) ); $completeSubject = $subject->completeForNodeOfType( diff --git a/Neos.ContentRepository.Core/Tests/Unit/NodeType/NodeTypeManagerTest.php b/Neos.ContentRepository.Core/Tests/Unit/NodeType/NodeTypeManagerTest.php index fc5de248c5b..7cf20912742 100644 --- a/Neos.ContentRepository.Core/Tests/Unit/NodeType/NodeTypeManagerTest.php +++ b/Neos.ContentRepository.Core/Tests/Unit/NodeType/NodeTypeManagerTest.php @@ -11,6 +11,7 @@ * source code. */ +use Neos\ContentRepository\Core\NodeType\ClosureNodeTypeProvider; use Neos\ContentRepository\Core\NodeType\DefaultNodeLabelGeneratorFactory; use Neos\ContentRepository\Core\NodeType\NodeType; use Neos\ContentRepository\Core\NodeType\NodeTypeManager; @@ -43,8 +44,10 @@ public function setUp(): void protected function prepareNodeTypeManager(array $nodeTypesFixtureData) { $this->nodeTypeManager = new NodeTypeManager( - fn() => $nodeTypesFixtureData, - new DefaultNodeLabelGeneratorFactory() + new ClosureNodeTypeProvider( + fn() => $nodeTypesFixtureData, + new DefaultNodeLabelGeneratorFactory() + ) ); } @@ -447,24 +450,12 @@ public function getAutoCreatedChildNodesReturnsLowercaseNames() public function rootNodeTypeIsAlwaysPresent() { $nodeTypeManager = new NodeTypeManager( - fn() => [], - new DefaultNodeLabelGeneratorFactory() + new ClosureNodeTypeProvider( + fn() => [], + new DefaultNodeLabelGeneratorFactory() + ) ); self::assertTrue($nodeTypeManager->hasNodeType(NodeTypeName::ROOT_NODE_TYPE_NAME)); self::assertInstanceOf(NodeType::class, $nodeTypeManager->getNodeType(NodeTypeName::ROOT_NODE_TYPE_NAME)); } - - /** - * @test - */ - public function rootNodeTypeIsPresentAfterOverride() - { - $nodeTypeManager = new NodeTypeManager( - fn() => [], - new DefaultNodeLabelGeneratorFactory() - ); - $nodeTypeManager->overrideNodeTypes(['Some:NewNodeType' => []]); - self::assertTrue($nodeTypeManager->hasNodeType(NodeTypeName::fromString('Some:NewNodeType'))); - self::assertTrue($nodeTypeManager->hasNodeType(NodeTypeName::ROOT_NODE_TYPE_NAME)); - } } diff --git a/Neos.ContentRepositoryRegistry/Classes/Factory/NodeTypeManager/DefaultNodeTypeManagerFactory.php b/Neos.ContentRepositoryRegistry/Classes/Factory/NodeTypeManager/DefaultNodeTypeManagerFactory.php index cc888aa6e13..f7184236ed9 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Factory/NodeTypeManager/DefaultNodeTypeManagerFactory.php +++ b/Neos.ContentRepositoryRegistry/Classes/Factory/NodeTypeManager/DefaultNodeTypeManagerFactory.php @@ -2,6 +2,7 @@ declare(strict_types=1); namespace Neos\ContentRepositoryRegistry\Factory\NodeTypeManager; +use Neos\ContentRepository\Core\NodeType\ClosureNodeTypeProvider; use Neos\ContentRepository\Core\NodeType\NodeTypeManager; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; use Neos\ContentRepositoryRegistry\Configuration\NodeTypeEnrichmentService; @@ -20,11 +21,13 @@ public function __construct( public function build(ContentRepositoryId $contentRepositoryId, array $options): NodeTypeManager { return new NodeTypeManager( - function () { - $configuration = $this->configurationManager->getConfiguration('NodeTypes'); - return $this->nodeTypeEnrichmentService->enrichNodeTypeLabelsConfiguration($configuration); - }, - $this->nodeLabelGeneratorFactory + new ClosureNodeTypeProvider( + function () { + $configuration = $this->configurationManager->getConfiguration('NodeTypes'); + return $this->nodeTypeEnrichmentService->enrichNodeTypeLabelsConfiguration($configuration); + }, + $this->nodeLabelGeneratorFactory + ) ); } } diff --git a/Neos.Neos/Tests/Functional/Fusion/NodeHelperTest.php b/Neos.Neos/Tests/Functional/Fusion/NodeHelperTest.php index 9952d6a776b..c91158ac1b0 100644 --- a/Neos.Neos/Tests/Functional/Fusion/NodeHelperTest.php +++ b/Neos.Neos/Tests/Functional/Fusion/NodeHelperTest.php @@ -15,6 +15,7 @@ use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValue; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValues; +use Neos\ContentRepository\Core\NodeType\ClosureNodeTypeProvider; use Neos\ContentRepository\Core\NodeType\DefaultNodeLabelGeneratorFactory; use Neos\ContentRepository\Core\NodeType\NodeType; use Neos\ContentRepository\Core\NodeType\NodeTypeManager; @@ -135,10 +136,11 @@ protected function setUp(): void ] ], new NodeTypeManager( - fn () => [], - new DefaultNodeLabelGeneratorFactory() + new ClosureNodeTypeProvider( + fn () => [], + new DefaultNodeLabelGeneratorFactory() + ) ), - new DefaultNodeLabelGeneratorFactory() ); $textNodeProperties = new PropertyCollection( diff --git a/Neos.Neos/Tests/Functional/Service/NodeTypeSchemaBuilderTest.php b/Neos.Neos/Tests/Functional/Service/NodeTypeSchemaBuilderTest.php index f5c64ffef50..327af569105 100644 --- a/Neos.Neos/Tests/Functional/Service/NodeTypeSchemaBuilderTest.php +++ b/Neos.Neos/Tests/Functional/Service/NodeTypeSchemaBuilderTest.php @@ -11,6 +11,7 @@ * source code. */ +use Neos\ContentRepository\Core\NodeType\ClosureNodeTypeProvider; use Neos\ContentRepository\Core\NodeType\NodeLabelGeneratorFactoryInterface; use Neos\ContentRepository\Core\NodeType\NodeTypeManager; use Neos\Flow\Configuration\ConfigurationManager; @@ -41,8 +42,10 @@ public function setUp(): void $nodeLabelGeneratorFactory = $this->objectManager->get(NodeLabelGeneratorFactoryInterface::class); $this->nodeTypeSchemaBuilder = NodeTypeSchemaBuilder::create( new NodeTypeManager( - fn() => $configurationManager->getConfiguration('NodeTypes'), - $nodeLabelGeneratorFactory + new ClosureNodeTypeProvider( + fn() => $configurationManager->getConfiguration('NodeTypes'), + $nodeLabelGeneratorFactory + ) ) ); $this->schema = $this->nodeTypeSchemaBuilder->generateNodeTypeSchema();