From 4fe6b983a32bf559c6a78f5e74038c4d9de16a78 Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Wed, 23 Oct 2024 18:55:42 +0200 Subject: [PATCH] 4191 - Adjust to aggregate scoped changes --- ...gregateWithNodeAndSerializedProperties.php | 2 +- .../Command/DisableNodeAggregate.php | 2 +- .../Command/CopyNodesRecursively.php | 2 +- .../Command/SetSerializedNodeProperties.php | 2 +- .../Command/SetSerializedNodeReferences.php | 2 +- .../Command/CreateNodeVariant.php | 2 +- .../SubtreeTagging/Command/TagSubtree.php | 2 +- .../SubtreeTagging/Command/UntagSubtree.php | 2 +- .../Dto/NodeIdToPublishOrDiscard.php | 7 ++- .../CatchUpHook/AssetUsageCatchUpHook.php | 4 ++ .../Service/WorkspacePublishingService.php | 47 +++++++++++++------ .../PendingChangesProjection/Change.php | 12 +++-- .../ChangeProjection.php | 2 +- .../Controller/WorkspaceController.php | 8 +++- 14 files changed, 64 insertions(+), 32 deletions(-) diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php b/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php index f295cd6dabe..79f5412eaa5 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php @@ -157,7 +157,7 @@ public function matchesNodeId(NodeIdToPublishOrDiscard $nodeIdToPublish): bool { return ( $this->nodeAggregateId->equals($nodeIdToPublish->nodeAggregateId) - && $this->originDimensionSpacePoint->equals($nodeIdToPublish->dimensionSpacePoint) + && $nodeIdToPublish->dimensionSpacePoint?->equals($this->originDimensionSpacePoint) ); } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeDisabling/Command/DisableNodeAggregate.php b/Neos.ContentRepository.Core/Classes/Feature/NodeDisabling/Command/DisableNodeAggregate.php index 454b7c2ccb2..f92f938df9c 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeDisabling/Command/DisableNodeAggregate.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeDisabling/Command/DisableNodeAggregate.php @@ -84,7 +84,7 @@ public function jsonSerialize(): array public function matchesNodeId(NodeIdToPublishOrDiscard $nodeIdToPublish): bool { return ( - $this->coveredDimensionSpacePoint === $nodeIdToPublish->dimensionSpacePoint + $this->coveredDimensionSpacePoint === $nodeIdToPublish->dimensionSpacePoint && $this->nodeAggregateId->equals($nodeIdToPublish->nodeAggregateId) ); } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/Command/CopyNodesRecursively.php b/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/Command/CopyNodesRecursively.php index 52355fd5e4a..ba31a07c601 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/Command/CopyNodesRecursively.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/Command/CopyNodesRecursively.php @@ -133,7 +133,7 @@ public function matchesNodeId(NodeIdToPublishOrDiscard $nodeIdToPublish): bool ); return ( !is_null($targetNodeAggregateId) - && $this->targetDimensionSpacePoint->equals($nodeIdToPublish->dimensionSpacePoint) + && $nodeIdToPublish->dimensionSpacePoint?->equals($this->targetDimensionSpacePoint) && $targetNodeAggregateId->equals($nodeIdToPublish->nodeAggregateId) ); } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php b/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php index ca589337e85..a2d684f6035 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php @@ -103,7 +103,7 @@ public function jsonSerialize(): array public function matchesNodeId(NodeIdToPublishOrDiscard $nodeIdToPublish): bool { return ( - $this->originDimensionSpacePoint->equals($nodeIdToPublish->dimensionSpacePoint) + $nodeIdToPublish->dimensionSpacePoint?->equals($this->originDimensionSpacePoint) && $this->nodeAggregateId->equals($nodeIdToPublish->nodeAggregateId) ); } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php b/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php index 3f635af08e0..1edf8409040 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php @@ -91,7 +91,7 @@ public function jsonSerialize(): array public function matchesNodeId(NodeIdToPublishOrDiscard $nodeIdToPublish): bool { - return ($this->sourceOriginDimensionSpacePoint->equals($nodeIdToPublish->dimensionSpacePoint) + return ($nodeIdToPublish->dimensionSpacePoint?->equals($this->sourceOriginDimensionSpacePoint) && $this->sourceNodeAggregateId->equals($nodeIdToPublish->nodeAggregateId) ); } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeVariation/Command/CreateNodeVariant.php b/Neos.ContentRepository.Core/Classes/Feature/NodeVariation/Command/CreateNodeVariant.php index 001f9bd66e9..54873f489dc 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeVariation/Command/CreateNodeVariant.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeVariation/Command/CreateNodeVariant.php @@ -84,7 +84,7 @@ public function jsonSerialize(): array public function matchesNodeId(NodeIdToPublishOrDiscard $nodeIdToPublish): bool { return $this->nodeAggregateId->equals($nodeIdToPublish->nodeAggregateId) - && $this->targetOrigin->equals($nodeIdToPublish->dimensionSpacePoint); + && $nodeIdToPublish->dimensionSpacePoint?->equals($this->targetOrigin); } public function createCopyForWorkspace( diff --git a/Neos.ContentRepository.Core/Classes/Feature/SubtreeTagging/Command/TagSubtree.php b/Neos.ContentRepository.Core/Classes/Feature/SubtreeTagging/Command/TagSubtree.php index 71fb012b0cc..d4d37c8b8cb 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/SubtreeTagging/Command/TagSubtree.php +++ b/Neos.ContentRepository.Core/Classes/Feature/SubtreeTagging/Command/TagSubtree.php @@ -92,7 +92,7 @@ public function createCopyForWorkspace(WorkspaceName $targetWorkspaceName): self public function matchesNodeId(NodeIdToPublishOrDiscard $nodeIdToPublish): bool { return $this->nodeAggregateId->equals($nodeIdToPublish->nodeAggregateId) - && $this->coveredDimensionSpacePoint->equals($nodeIdToPublish->dimensionSpacePoint); + && $nodeIdToPublish->dimensionSpacePoint === $this->coveredDimensionSpacePoint; } /** diff --git a/Neos.ContentRepository.Core/Classes/Feature/SubtreeTagging/Command/UntagSubtree.php b/Neos.ContentRepository.Core/Classes/Feature/SubtreeTagging/Command/UntagSubtree.php index cca49333c95..1ae9b4624a2 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/SubtreeTagging/Command/UntagSubtree.php +++ b/Neos.ContentRepository.Core/Classes/Feature/SubtreeTagging/Command/UntagSubtree.php @@ -93,7 +93,7 @@ public function createCopyForWorkspace(WorkspaceName $targetWorkspaceName): self public function matchesNodeId(NodeIdToPublishOrDiscard $nodeIdToPublish): bool { return $this->nodeAggregateId->equals($nodeIdToPublish->nodeAggregateId) - && $this->coveredDimensionSpacePoint->equals($nodeIdToPublish->dimensionSpacePoint); + && $this->coveredDimensionSpacePoint === $nodeIdToPublish->dimensionSpacePoint; } /** diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Dto/NodeIdToPublishOrDiscard.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Dto/NodeIdToPublishOrDiscard.php index a9a7e1339e2..b2b5c346be7 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Dto/NodeIdToPublishOrDiscard.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Dto/NodeIdToPublishOrDiscard.php @@ -30,7 +30,8 @@ { public function __construct( public NodeAggregateId $nodeAggregateId, - public DimensionSpacePoint $dimensionSpacePoint, + /** Can be null for aggregate scoped changes, e.g. ChangeNodeAggregateName or ChangeNodeAggregateName */ + public ?DimensionSpacePoint $dimensionSpacePoint, ) { } @@ -41,7 +42,9 @@ public static function fromArray(array $array): self { return new self( NodeAggregateId::fromString($array['nodeAggregateId']), - DimensionSpacePoint::fromArray($array['dimensionSpacePoint']), + is_array($array['dimensionSpacePoint'] ?? null) + ? DimensionSpacePoint::fromArray($array['dimensionSpacePoint']) + : null, ); } diff --git a/Neos.Neos/Classes/AssetUsage/CatchUpHook/AssetUsageCatchUpHook.php b/Neos.Neos/Classes/AssetUsage/CatchUpHook/AssetUsageCatchUpHook.php index e240adb41bc..7867326e1ea 100644 --- a/Neos.Neos/Classes/AssetUsage/CatchUpHook/AssetUsageCatchUpHook.php +++ b/Neos.Neos/Classes/AssetUsage/CatchUpHook/AssetUsageCatchUpHook.php @@ -146,6 +146,10 @@ private function discardWorkspace(WorkspaceName $workspaceName): void private function discardNodes(WorkspaceName $workspaceName, NodeIdsToPublishOrDiscard $nodeIds): void { foreach ($nodeIds as $nodeId) { + if (!$nodeId->dimensionSpacePoint) { + // NodeAggregateTypeWasChanged and NodeAggregateNameWasChanged don't impact asset usage + continue; + } $this->assetUsageIndexingService->removeIndexForWorkspaceNameNodeAggregateIdAndDimensionSpacePoint( $this->contentRepository->id, $workspaceName, diff --git a/Neos.Neos/Classes/Domain/Service/WorkspacePublishingService.php b/Neos.Neos/Classes/Domain/Service/WorkspacePublishingService.php index 31836d383d2..cb27d2b92db 100644 --- a/Neos.Neos/Classes/Domain/Service/WorkspacePublishingService.php +++ b/Neos.Neos/Classes/Domain/Service/WorkspacePublishingService.php @@ -26,9 +26,11 @@ use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Dto\RebaseErrorHandlingStrategy; use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Exception\WorkspaceRebaseFailed; use Neos\ContentRepository\Core\NodeType\NodeTypeName; +use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphInterface; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; +use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateIds; use Neos\ContentRepository\Core\SharedModel\Workspace\Workspace as ContentRepositoryWorkspace; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregateCurrentlyDoesNotExist; @@ -339,7 +341,7 @@ private function resolveNodeIdsToPublishOrDiscard( $nodeIdsToPublishOrDiscard[] = new NodeIdToPublishOrDiscard( $change->nodeAggregateId, - $change->originDimensionSpacePoint->toDimensionSpacePoint() + $change->originDimensionSpacePoint?->toDimensionSpacePoint() ); } @@ -358,7 +360,6 @@ private function countPendingWorkspaceChangesInternal(ContentRepository $content return $contentRepository->projectionState(ChangeFinder::class)->countByContentStreamId($crWorkspace->currentContentStreamId); } - private function isChangePublishableWithinAncestorScope( ContentRepository $contentRepository, WorkspaceName $workspaceName, @@ -374,20 +375,38 @@ private function isChangePublishableWithinAncestorScope( } } - $subgraph = $contentRepository->getContentGraph($workspaceName)->getSubgraph( - $change->originDimensionSpacePoint->toDimensionSpacePoint(), - VisibilityConstraints::withoutRestrictions() - ); + if ($change->originDimensionSpacePoint) { + $subgraph = $contentRepository->getContentGraph($workspaceName)->getSubgraph( + $change->originDimensionSpacePoint->toDimensionSpacePoint(), + VisibilityConstraints::withoutRestrictions() + ); - // A Change is publishable if the respective node (or the respective - // removal attachment point) has a closest ancestor that matches our - // current ancestor scope (Document/Site) - $actualAncestorNode = $subgraph->findClosestNode( - $change->removalAttachmentPoint ?? $change->nodeAggregateId, - FindClosestNodeFilter::create(nodeTypes: $ancestorNodeTypeName->value) - ); + // A Change is publishable if the respective node (or the respective + // removal attachment point) has a closest ancestor that matches our + // current ancestor scope (Document/Site) + $actualAncestorNode = $subgraph->findClosestNode( + $change->removalAttachmentPoint ?? $change->nodeAggregateId, + FindClosestNodeFilter::create(nodeTypes: $ancestorNodeTypeName->value) + ); + + return $actualAncestorNode?->aggregateId->equals($ancestorId) ?? false; + } else { + return $this->findAncestorAggregateIds( + $contentRepository->getContentGraph($workspaceName), + $change->nodeAggregateId + )->contain($ancestorId); + } + } + + private function findAncestorAggregateIds(ContentGraphInterface $contentGraph, NodeAggregateId $descendantNodeAggregateId): NodeAggregateIds + { + $nodeAggregateIds = NodeAggregateIds::create($descendantNodeAggregateId); + foreach ($contentGraph->findParentNodeAggregates($descendantNodeAggregateId) as $parentNodeAggregate) { + $nodeAggregateIds = $nodeAggregateIds->merge(NodeAggregateIds::create($parentNodeAggregate->nodeAggregateId)); + $nodeAggregateIds = $nodeAggregateIds->merge($this->findAncestorAggregateIds($contentGraph, $parentNodeAggregate->nodeAggregateId)); + } - return $actualAncestorNode?->aggregateId->equals($ancestorId) ?? false; + return $nodeAggregateIds; } /** diff --git a/Neos.Neos/Classes/PendingChangesProjection/Change.php b/Neos.Neos/Classes/PendingChangesProjection/Change.php index 467cc2c1a82..7b616e47b6c 100644 --- a/Neos.Neos/Classes/PendingChangesProjection/Change.php +++ b/Neos.Neos/Classes/PendingChangesProjection/Change.php @@ -56,8 +56,8 @@ public function addToDatabase(Connection $databaseConnection, string $tableName) $databaseConnection->insert($tableName, [ 'contentStreamId' => $this->contentStreamId->value, 'nodeAggregateId' => $this->nodeAggregateId->value, - 'originDimensionSpacePoint' => $this->originDimensionSpacePoint->toJson(), - 'originDimensionSpacePointHash' => $this->originDimensionSpacePoint->hash, + 'originDimensionSpacePoint' => $this->originDimensionSpacePoint?->toJson(), + 'originDimensionSpacePointHash' => $this->originDimensionSpacePoint?->hash ?: 'AGGREGATE', 'created' => (int)$this->created, 'changed' => (int)$this->changed, 'moved' => (int)$this->moved, @@ -84,8 +84,8 @@ public function updateToDatabase(Connection $databaseConnection, string $tableNa [ 'contentStreamId' => $this->contentStreamId->value, 'nodeAggregateId' => $this->nodeAggregateId->value, - 'originDimensionSpacePoint' => $this->originDimensionSpacePoint->toJson(), - 'originDimensionSpacePointHash' => $this->originDimensionSpacePoint->hash, + 'originDimensionSpacePoint' => $this->originDimensionSpacePoint?->toJson(), + 'originDimensionSpacePointHash' => $this->originDimensionSpacePoint?->hash ?: 'AGGREGATE', ] ); } catch (DbalException $e) { @@ -101,7 +101,9 @@ public static function fromDatabaseRow(array $databaseRow): self return new self( ContentStreamId::fromString($databaseRow['contentStreamId']), NodeAggregateId::fromString($databaseRow['nodeAggregateId']), - OriginDimensionSpacePoint::fromJsonString($databaseRow['originDimensionSpacePoint']), + $databaseRow['originDimensionSpacePoint'] ?? null + ? OriginDimensionSpacePoint::fromJsonString($databaseRow['originDimensionSpacePoint']) + : null, (bool)$databaseRow['created'], (bool)$databaseRow['changed'], (bool)$databaseRow['moved'], diff --git a/Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php b/Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php index 30f47541e28..1544b774835 100644 --- a/Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php +++ b/Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php @@ -128,7 +128,7 @@ private function determineRequiredSqlStatements(): array (new Column('moved', Type::getType(Types::BOOLEAN)))->setNotnull(true), DbalSchemaFactory::columnForNodeAggregateId('nodeAggregateId')->setNotnull(true), DbalSchemaFactory::columnForDimensionSpacePoint('originDimensionSpacePoint')->setNotnull(false), - DbalSchemaFactory::columnForDimensionSpacePointHash('originDimensionSpacePointHash')->setNotnull(false), + DbalSchemaFactory::columnForDimensionSpacePointHash('originDimensionSpacePointHash')->setNotnull(true), (new Column('deleted', Type::getType(Types::BOOLEAN)))->setNotnull(true), // Despite the name suggesting this might be an anchor point of sorts, this is a nodeAggregateId type DbalSchemaFactory::columnForNodeAggregateId('removalAttachmentPoint')->setNotnull(false) diff --git a/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php b/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php index b6f7b4553a5..7e64c6a70c5 100644 --- a/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php +++ b/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php @@ -16,6 +16,7 @@ use Doctrine\DBAL\Exception as DBALException; use Neos\ContentRepository\Core\ContentRepository; +use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Exception\WorkspaceAlreadyExists; use Neos\ContentRepository\Core\Feature\WorkspaceModification\Command\DeleteWorkspace; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Command\DiscardIndividualNodesFromWorkspace; @@ -684,6 +685,9 @@ protected function computeSiteChanges(Workspace $selectedWorkspace, ContentRepos ->findByContentStreamId( $selectedWorkspace->currentContentStreamId ); + $dimensionSpacePoints = iterator_to_array($contentRepository->getVariationGraph()->getDimensionSpacePoints()); + /** @var DimensionSpacePoint $arbitraryDimensionSpacePoint */ + $arbitraryDimensionSpacePoint = reset($dimensionSpacePoints); foreach ($changes as $change) { $workspaceName = $selectedWorkspace->workspaceName; @@ -697,7 +701,7 @@ protected function computeSiteChanges(Workspace $selectedWorkspace, ContentRepos $workspaceName = $baseWorkspace->workspaceName; } $subgraph = $contentRepository->getContentGraph($workspaceName)->getSubgraph( - $change->originDimensionSpacePoint->toDimensionSpacePoint(), + $change->originDimensionSpacePoint?->toDimensionSpacePoint() ?: $arbitraryDimensionSpacePoint, VisibilityConstraints::withoutRestrictions() ); @@ -765,7 +769,7 @@ protected function computeSiteChanges(Workspace $selectedWorkspace, ContentRepos $nodeAddress = NodeAddress::create( $contentRepository->id, $selectedWorkspace->workspaceName, - $change->originDimensionSpacePoint->toDimensionSpacePoint(), + $change->originDimensionSpacePoint?->toDimensionSpacePoint() ?: $arbitraryDimensionSpacePoint, $change->nodeAggregateId );