diff --git a/Classes/Domain/Model/AbstractChange.php b/Classes/Domain/Model/AbstractChange.php index 8b32cd8074..9320d79c34 100644 --- a/Classes/Domain/Model/AbstractChange.php +++ b/Classes/Domain/Model/AbstractChange.php @@ -11,6 +11,7 @@ * source code. */ +use Neos\ContentRepository\Core\NodeType\NodeType; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; @@ -21,15 +22,12 @@ use Neos\Neos\Ui\Domain\Model\Feedback\Operations\NodeCreated; use Neos\Neos\Ui\Domain\Model\Feedback\Operations\ReloadDocument; use Neos\Neos\Ui\Domain\Model\Feedback\Operations\UpdateWorkspaceInfo; -use Neos\Neos\Utility\NodeTypeWithFallbackProvider; /** * @internal */ abstract class AbstractChange implements ChangeInterface { - use NodeTypeWithFallbackProvider; - protected ?Node $subject = null; #[Flow\Inject] @@ -53,12 +51,12 @@ abstract class AbstractChange implements ChangeInterface */ protected $persistenceManager; - public function setSubject(Node $subject): void + final public function setSubject(Node $subject): void { $this->subject = $subject; } - public function getSubject(): ?Node + final public function getSubject(): ?Node { return $this->subject; } @@ -66,7 +64,7 @@ public function getSubject(): ?Node /** * Helper method to inform the client, that new workspace information is available */ - protected function updateWorkspaceInfo(): void + final protected function updateWorkspaceInfo(): void { if (!is_null($this->subject)) { $subgraph = $this->contentRepositoryRegistry->subgraphForNode($this->subject); @@ -78,12 +76,18 @@ protected function updateWorkspaceInfo(): void } } - protected function findParentNode(Node $node): ?Node + final protected function findParentNode(Node $node): ?Node { return $this->contentRepositoryRegistry->subgraphForNode($node) ->findParentNode($node->aggregateId); } + final protected function getNodeType(Node $node): ?NodeType + { + $contentRepository = $this->contentRepositoryRegistry->get($node->contentRepositoryId); + return $contentRepository->getNodeTypeManager()->getNodeType($node->nodeTypeName); + } + /** * Inform the client to reload the currently-displayed document, because the rendering has changed. * @@ -102,7 +106,7 @@ protected function reloadDocument(Node $node = null): void /** * Inform the client that a node has been created, the client decides if and which tree should react to this change. */ - protected function addNodeCreatedFeedback(Node $subject = null): void + final protected function addNodeCreatedFeedback(Node $subject = null): void { $node = $subject ?: $this->getSubject(); if ($node) { diff --git a/Classes/Domain/Model/Changes/AbstractCreate.php b/Classes/Domain/Model/Changes/AbstractCreate.php index 9e53d245e9..118de197fd 100644 --- a/Classes/Domain/Model/Changes/AbstractCreate.php +++ b/Classes/Domain/Model/Changes/AbstractCreate.php @@ -14,11 +14,10 @@ use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; -use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceFactoryInterface; use Neos\ContentRepository\Core\Feature\NodeCreation\Command\CreateNodeAggregateWithNode; +use Neos\ContentRepository\Core\NodeType\NodeType; use Neos\ContentRepository\Core\NodeType\NodeTypeName; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; -use Neos\ContentRepository\Core\SharedModel\Exception\NodeNameIsAlreadyOccupied; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\Flow\Annotations as Flow; @@ -134,13 +133,19 @@ protected function createNode( if (is_null($nodeTypeName)) { throw new \RuntimeException('Cannot run createNode without a set node type.', 1645577794); } + + $contentRepository = $this->contentRepositoryRegistry->get($parentNode->contentRepositoryId); + $nodeType = $contentRepository->getNodeTypeManager()->getNodeType($nodeTypeName); + if (is_null($nodeType)) { + throw new \RuntimeException(sprintf('Cannot run create node because the node type %s is missing.', $nodeTypeName->value), 1716019747); + } + $nodeName = $this->getName() ? NodeName::fromString($this->getName()) : null; $nodeAggregateId = $this->getNodeAggregateId() ?? NodeAggregateId::create(); // generate a new NodeAggregateId - $contentRepository = $this->contentRepositoryRegistry->get($parentNode->contentRepositoryId); $command = CreateNodeAggregateWithNode::create( $parentNode->workspaceName, @@ -158,10 +163,10 @@ protected function createNode( $contentRepository->getNodeTypeManager() ), $this->nodePropertyConversionService->convertNodeCreationElements( - $contentRepository->getNodeTypeManager()->getNodeType($nodeTypeName), + $nodeType, $this->getData() ?: [] ), - $nodeTypeName, + $nodeType, $contentRepository ); @@ -189,10 +194,9 @@ protected function createNode( protected function applyNodeCreationHandlers( NodeCreationCommands $commands, NodeCreationElements $elements, - NodeTypeName $nodeTypeName, + NodeType $nodeType, ContentRepository $contentRepository ): NodeCreationCommands { - $nodeType = $contentRepository->getNodeTypeManager()->getNodeType($nodeTypeName); if (!isset($nodeType->getOptions()['nodeCreationHandlers']) || !is_array($nodeType->getOptions()['nodeCreationHandlers'])) { return $commands; diff --git a/Classes/Domain/Model/Changes/AbstractStructuralChange.php b/Classes/Domain/Model/Changes/AbstractStructuralChange.php index 0831eb1fe3..111ffc96b1 100644 --- a/Classes/Domain/Model/Changes/AbstractStructuralChange.php +++ b/Classes/Domain/Model/Changes/AbstractStructuralChange.php @@ -17,7 +17,6 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Projection\ContentGraph\Nodes; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateClassification; -use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Annotations as Flow; use Neos\Neos\FrontendRouting\NodeAddressFactory; use Neos\Neos\Ui\ContentRepository\Service\NeosUiNodeService; @@ -26,7 +25,6 @@ use Neos\Neos\Ui\Domain\Model\Feedback\Operations\RenderContentOutOfBand; use Neos\Neos\Ui\Domain\Model\Feedback\Operations\UpdateNodeInfo; use Neos\Neos\Ui\Domain\Model\RenderedNodeDomAddress; -use Neos\Neos\Utility\NodeTypeWithFallbackProvider; /** * A change that performs structural actions like moving or creating nodes @@ -36,11 +34,6 @@ */ abstract class AbstractStructuralChange extends AbstractChange { - use NodeTypeWithFallbackProvider; - - #[Flow\Inject] - protected ContentRepositoryRegistry $contentRepositoryRegistry; - /** * The node dom address for the parent node of the created node */ @@ -149,14 +142,14 @@ protected function finish(Node $node) $this->updateWorkspaceInfo(); - if ($this->getNodeType($node)->isOfType('Neos.Neos:Content') + if ($this->getNodeType($node)?->isOfType('Neos.Neos:Content') && ($this->getParentDomAddress() || $this->getSiblingDomAddress())) { // we can ONLY render out of band if: // 1) the parent of our new (or copied or moved) node is a ContentCollection; // so we can directly update an element of this content collection $contentRepository = $this->contentRepositoryRegistry->get($node->contentRepositoryId); - if ($parentNode && $this->getNodeType($parentNode)->isOfType('Neos.Neos:ContentCollection') && + if ($parentNode && $this->getNodeType($parentNode)?->isOfType('Neos.Neos:ContentCollection') && // 2) the parent DOM address (i.e. the closest RENDERED node in DOM is actually the ContentCollection; // and no other node in between $this->getParentDomAddress() && diff --git a/Classes/Domain/Model/Changes/Property.php b/Classes/Domain/Model/Changes/Property.php index 58be3ccc5b..cf445895e2 100644 --- a/Classes/Domain/Model/Changes/Property.php +++ b/Classes/Domain/Model/Changes/Property.php @@ -23,6 +23,7 @@ use Neos\ContentRepository\Core\Feature\NodeTypeChange\Command\ChangeNodeAggregateType; use Neos\ContentRepository\Core\Feature\NodeTypeChange\Dto\NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy; use Neos\ContentRepository\Core\Feature\NodeVariation\Command\CreateNodeVariant; +use Neos\ContentRepository\Core\NodeType\NodeType; use Neos\ContentRepository\Core\NodeType\NodeTypeName; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\SharedModel\Exception\ContentStreamDoesNotExistYet; @@ -30,14 +31,12 @@ use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateIds; use Neos\ContentRepository\Core\SharedModel\Node\NodeVariantSelectionStrategy; use Neos\ContentRepository\Core\SharedModel\Node\ReferenceName; -use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Annotations as Flow; use Neos\Neos\Ui\Domain\Model\AbstractChange; use Neos\Neos\Ui\Domain\Model\Feedback\Operations\ReloadContentOutOfBand; use Neos\Neos\Ui\Domain\Model\Feedback\Operations\UpdateNodeInfo; use Neos\Neos\Ui\Domain\Model\RenderedNodeDomAddress; use Neos\Neos\Ui\Domain\Service\NodePropertyConversionService; -use Neos\Neos\Utility\NodeTypeWithFallbackProvider; /** * Changes a property on a node @@ -47,11 +46,6 @@ */ class Property extends AbstractChange { - use NodeTypeWithFallbackProvider; - - #[Flow\Inject] - protected ContentRepositoryRegistry $contentRepositoryRegistry; - /** * @Flow\Inject * @var NodePropertyConversionService @@ -131,12 +125,14 @@ public function getIsInline(): bool */ public function canApply(): bool { - if (is_null($this->subject) || is_null($this->subject->nodeType)) { + $propertyName = $this->getPropertyName(); + if (!$this->subject || !$propertyName) { + return false; + } + $nodeType = $this->getNodeType($this->subject); + if (!$nodeType) { return false; } - $nodeType = $this->subject->nodeType; - $propertyName = $this->getPropertyName(); - return $nodeType->hasProperty($propertyName) || $nodeType->hasReference($propertyName); } @@ -151,18 +147,19 @@ public function canApply(): bool public function apply(): void { $subject = $this->subject; + $nodeType = $subject ? $this->getNodeType($subject) : null; $propertyName = $this->getPropertyName(); - if (is_null($subject) || is_null($propertyName) || $this->canApply() === false) { + if (is_null($subject) || is_null($nodeType) || is_null($propertyName) || $this->canApply() === false) { return; } match (true) { - $this->getNodeType($subject)->hasReference($propertyName) => $this->handleNodeReferenceChange($subject, $propertyName), + $nodeType->hasReference($propertyName) => $this->handleNodeReferenceChange($subject, $propertyName), // todo create custom 'changes' for these special cases // we continue to use the underscore logic in the Neos Ui code base as the JS-client code works this way - $propertyName === '_nodeType' => $this->handleNodeTypeChange($subject, $propertyName), - $propertyName === '_hidden' => $this->handleHiddenPropertyChange($subject, $propertyName), - default => $this->handlePropertyChange($subject, $propertyName) + $propertyName === '_nodeType' => $this->handleNodeTypeChange($subject), + $propertyName === '_hidden' => $this->handleHiddenPropertyChange($subject), + default => $this->handlePropertyChange($subject, $nodeType, $propertyName) }; $this->createFeedback($subject); @@ -197,13 +194,13 @@ private function createFeedback(Node $subject): void $reloadIfChangedConfigurationPathForReference = sprintf('references.%s.ui.reloadIfChanged', $propertyName); if (!$this->getIsInline() && ( - $this->getNodeType($node)->getConfiguration($reloadIfChangedConfigurationPathForProperty) - || $this->getNodeType($node)->getConfiguration($reloadIfChangedConfigurationPathForReference) + $this->getNodeType($node)?->getConfiguration($reloadIfChangedConfigurationPathForProperty) + || $this->getNodeType($node)?->getConfiguration($reloadIfChangedConfigurationPathForReference) ) ) { if ($this->getNodeDomAddress() && $this->getNodeDomAddress()->getFusionPath() && $parentNode - && $this->getNodeType($parentNode)->isOfType('Neos.Neos:ContentCollection')) { + && $this->getNodeType($parentNode)?->isOfType('Neos.Neos:ContentCollection')) { $reloadContentOutOfBand = new ReloadContentOutOfBand(); $reloadContentOutOfBand->setNode($node); $reloadContentOutOfBand->setNodeDomAddress($this->getNodeDomAddress()); @@ -217,8 +214,8 @@ private function createFeedback(Node $subject): void $reloadPageIfChangedConfigurationPathForReference = sprintf('references.%s.ui.reloadPageIfChanged', $propertyName); if (!$this->getIsInline() && ( - $this->getNodeType($node)->getConfiguration($reloadPageIfChangedConfigurationPathForProperty) - || $this->getNodeType($node)->getConfiguration($reloadPageIfChangedConfigurationPathForReference) + $this->getNodeType($node)?->getConfiguration($reloadPageIfChangedConfigurationPathForProperty) + || $this->getNodeType($node)?->getConfiguration($reloadPageIfChangedConfigurationPathForReference) ) ) { $this->reloadDocument($node); @@ -248,41 +245,37 @@ private function handleNodeReferenceChange(Node $subject, string $propertyName): ); } - private function handleHiddenPropertyChange(Node $subject, string $propertyName): void + private function handleHiddenPropertyChange(Node $subject): void { - $value = $this->nodePropertyConversionService->convert( - $this->getNodeType($subject)->getPropertyType($propertyName), - $this->getValue() - ); + // todo simplify conversion + $value = (bool)$this->nodePropertyConversionService->convert('boolean', $this->getValue()); $contentRepository = $this->contentRepositoryRegistry->get($subject->contentRepositoryId); - $command = EnableNodeAggregate::create( - $subject->workspaceName, - $subject->aggregateId, - $subject->originDimensionSpacePoint->toDimensionSpacePoint(), - NodeVariantSelectionStrategy::STRATEGY_ALL_SPECIALIZATIONS - ); - - if ($value === true) { - $command = DisableNodeAggregate::create( + $command = match ($value) { + false => EnableNodeAggregate::create( $subject->workspaceName, $subject->aggregateId, $subject->originDimensionSpacePoint->toDimensionSpacePoint(), NodeVariantSelectionStrategy::STRATEGY_ALL_SPECIALIZATIONS - ); - } + ), + true => DisableNodeAggregate::create( + $subject->workspaceName, + $subject->aggregateId, + $subject->originDimensionSpacePoint->toDimensionSpacePoint(), + NodeVariantSelectionStrategy::STRATEGY_ALL_SPECIALIZATIONS + ) + }; $contentRepository->handle($command); } - private function handleNodeTypeChange(Node $subject, string $propertyName): void + private function handleNodeTypeChange(Node $subject): void { $contentRepository = $this->contentRepositoryRegistry->get($subject->contentRepositoryId); - $value = $this->nodePropertyConversionService->convert( - $this->getNodeType($subject)->getPropertyType($propertyName), - $this->getValue() - ); + // todo simplify conversion + /** @var string $value */ + $value = $this->nodePropertyConversionService->convert('string', $this->getValue()); $contentRepository->handle( ChangeNodeAggregateType::create( @@ -294,11 +287,11 @@ private function handleNodeTypeChange(Node $subject, string $propertyName): void ); } - private function handlePropertyChange(Node $subject, string $propertyName): void + private function handlePropertyChange(Node $subject, NodeType $nodeType, string $propertyName): void { $contentRepository = $this->contentRepositoryRegistry->get($subject->contentRepositoryId); $value = $this->nodePropertyConversionService->convert( - $this->getNodeType($subject)->getPropertyType($propertyName), + $nodeType->getPropertyType($propertyName), $this->getValue() ); diff --git a/Classes/Domain/Model/Changes/Remove.php b/Classes/Domain/Model/Changes/Remove.php index 8dbd864c88..b56371ea37 100644 --- a/Classes/Domain/Model/Changes/Remove.php +++ b/Classes/Domain/Model/Changes/Remove.php @@ -101,7 +101,7 @@ private function getRemovalAttachmentPoint(): ?NodeAggregateId { $subgraph = $this->contentRepositoryRegistry->subgraphForNode($this->subject); - if ($this->subject->nodeType?->isOfType(NodeTypeNameFactory::NAME_DOCUMENT)) { + if ($this->getNodeType($this->subject)?->isOfType(NodeTypeNameFactory::NAME_DOCUMENT)) { $closestSiteNode = $subgraph->findClosestNode($this->subject->aggregateId, FindClosestNodeFilter::create(nodeTypes: NodeTypeNameFactory::NAME_SITE)); return $closestSiteNode?->aggregateId; } diff --git a/Classes/Domain/Model/Feedback/Operations/NodeCreated.php b/Classes/Domain/Model/Feedback/Operations/NodeCreated.php index d2e884191b..d5a13fe77c 100644 --- a/Classes/Domain/Model/Feedback/Operations/NodeCreated.php +++ b/Classes/Domain/Model/Feedback/Operations/NodeCreated.php @@ -19,15 +19,12 @@ use Neos\Neos\Domain\Service\NodeTypeNameFactory; use Neos\Neos\Ui\Domain\Model\AbstractFeedback; use Neos\Neos\Ui\Domain\Model\FeedbackInterface; -use Neos\Neos\Utility\NodeTypeWithFallbackProvider; /** * @internal */ class NodeCreated extends AbstractFeedback { - use NodeTypeWithFallbackProvider; - #[Flow\Inject] protected ContentRepositoryRegistry $contentRepositoryRegistry; @@ -93,11 +90,12 @@ public function serializePayload(ControllerContext $controllerContext) { $node = $this->getNode(); $contentRepository = $this->contentRepositoryRegistry->get($node->contentRepositoryId); + $nodeType = $contentRepository->getNodeTypeManager()->getNodeType($node->nodeTypeName); $nodeAddressFactory = NodeAddressFactory::create($contentRepository); return [ 'contextPath' => $nodeAddressFactory->createFromNode($node)->serializeForUri(), 'identifier' => $node->aggregateId->value, - 'isDocument' => $this->getNodeType($node)->isOfType(NodeTypeNameFactory::NAME_DOCUMENT) + 'isDocument' => $nodeType?->isOfType(NodeTypeNameFactory::NAME_DOCUMENT) ]; } } diff --git a/Classes/Infrastructure/ContentRepository/CreationDialog/PromotedElementsCreationHandlerFactory.php b/Classes/Infrastructure/ContentRepository/CreationDialog/PromotedElementsCreationHandlerFactory.php index 5dababedaa..88066dab9e 100644 --- a/Classes/Infrastructure/ContentRepository/CreationDialog/PromotedElementsCreationHandlerFactory.php +++ b/Classes/Infrastructure/ContentRepository/CreationDialog/PromotedElementsCreationHandlerFactory.php @@ -35,7 +35,9 @@ public function __construct( public function handle(NodeCreationCommands $commands, NodeCreationElements $elements): NodeCreationCommands { $nodeType = $this->nodeTypeManager->getNodeType($commands->first->nodeTypeName); - + if (!$nodeType) { + return $commands; + } $propertyValues = $commands->first->initialPropertyValues; $setReferencesCommands = []; foreach ($elements as $elementName => $elementValue) { diff --git a/Classes/Infrastructure/Neos/UriPathSegmentNodeCreationHandlerFactory.php b/Classes/Infrastructure/Neos/UriPathSegmentNodeCreationHandlerFactory.php index c646b1c48c..92ae008ced 100644 --- a/Classes/Infrastructure/Neos/UriPathSegmentNodeCreationHandlerFactory.php +++ b/Classes/Infrastructure/Neos/UriPathSegmentNodeCreationHandlerFactory.php @@ -47,7 +47,7 @@ public function handle(NodeCreationCommands $commands, NodeCreationElements $ele { if ( !$this->nodeTypeManager->getNodeType($commands->first->nodeTypeName) - ->isOfType('Neos.Neos:Document') + ?->isOfType('Neos.Neos:Document') ) { return $commands; }