diff --git a/Neos.Neos/Classes/Domain/Service/WorkspacePublishingService.php b/Neos.Neos/Classes/Domain/Service/WorkspacePublishingService.php index 49c2e5ce40..743024af29 100644 --- a/Neos.Neos/Classes/Domain/Service/WorkspacePublishingService.php +++ b/Neos.Neos/Classes/Domain/Service/WorkspacePublishingService.php @@ -387,38 +387,20 @@ private function isChangePublishableWithinAncestorScope( } } - 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) - ); - - return $actualAncestorNode?->aggregateId->equals($ancestorId) ?? false; - } else { - return $this->findAncestorAggregateIds( - $contentRepository->getContentGraph($workspaceName), - $change->nodeAggregateId - )->contain($ancestorId); - } - } + $subgraph = $contentRepository->getContentGraph($workspaceName)->getSubgraph( + $change->originDimensionSpacePoint->toDimensionSpacePoint(), + VisibilityConstraints::withoutRestrictions() + ); - 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)); - } + // 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 $nodeAggregateIds; + return $actualAncestorNode?->aggregateId->equals($ancestorId) ?? false; } /** diff --git a/Neos.Neos/Classes/PendingChangesProjection/Change.php b/Neos.Neos/Classes/PendingChangesProjection/Change.php index 798902f551..acee1cda5e 100644 --- a/Neos.Neos/Classes/PendingChangesProjection/Change.php +++ b/Neos.Neos/Classes/PendingChangesProjection/Change.php @@ -30,16 +30,13 @@ */ final class Change { - public const AGGREGATE_DIMENSIONSPACEPOINT_HASH_PLACEHOLDER = 'AGGREGATE'; - /** * @param NodeAggregateId|null $removalAttachmentPoint {@see RemoveNodeAggregate::$removalAttachmentPoint} for docs */ public function __construct( public ContentStreamId $contentStreamId, public NodeAggregateId $nodeAggregateId, - // null for aggregate scoped changes (e.g. NodeAggregateNameWasChanged, NodeAggregateTypeWasChanged) - public ?OriginDimensionSpacePoint $originDimensionSpacePoint, + public OriginDimensionSpacePoint $originDimensionSpacePoint, public bool $created, public bool $changed, public bool $moved, @@ -58,8 +55,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 ?: self::AGGREGATE_DIMENSIONSPACEPOINT_HASH_PLACEHOLDER, + 'originDimensionSpacePoint' => $this->originDimensionSpacePoint->toJson(), + 'originDimensionSpacePointHash' => $this->originDimensionSpacePoint->hash, 'created' => (int)$this->created, 'changed' => (int)$this->changed, 'moved' => (int)$this->moved, @@ -86,8 +83,8 @@ public function updateToDatabase(Connection $databaseConnection, string $tableNa [ 'contentStreamId' => $this->contentStreamId->value, 'nodeAggregateId' => $this->nodeAggregateId->value, - 'originDimensionSpacePoint' => $this->originDimensionSpacePoint?->toJson(), - 'originDimensionSpacePointHash' => $this->originDimensionSpacePoint?->hash ?: self::AGGREGATE_DIMENSIONSPACEPOINT_HASH_PLACEHOLDER, + 'originDimensionSpacePoint' => $this->originDimensionSpacePoint->toJson(), + 'originDimensionSpacePointHash' => $this->originDimensionSpacePoint->hash, ] ); } catch (DbalException $e) { @@ -103,9 +100,7 @@ public static function fromDatabaseRow(array $databaseRow): self return new self( ContentStreamId::fromString($databaseRow['contentStreamId']), NodeAggregateId::fromString($databaseRow['nodeAggregateId']), - $databaseRow['originDimensionSpacePoint'] ?? null - ? OriginDimensionSpacePoint::fromJsonString($databaseRow['originDimensionSpacePoint']) - : null, + OriginDimensionSpacePoint::fromJsonString($databaseRow['originDimensionSpacePoint']), (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 da5c068067..bef2ce02dc 100644 --- a/Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php +++ b/Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php @@ -415,10 +415,13 @@ private function whenNodeAggregateTypeWasChanged(NodeAggregateTypeWasChanged $ev if ($event->workspaceName->isLive()) { return; } - $this->markAggregateAsChanged( - $event->contentStreamId, - $event->nodeAggregateId, - ); + foreach ($event->affectedOriginDimensionSpacePoints as $originDimensionSpacePoint) { + $this->markAsChanged( + $event->contentStreamId, + $event->nodeAggregateId, + $originDimensionSpacePoint + ); + } } private function whenNodeAggregateNameWasChanged(NodeAggregateNameWasChanged $event): void @@ -426,10 +429,13 @@ private function whenNodeAggregateNameWasChanged(NodeAggregateNameWasChanged $ev if ($event->workspaceName->isLive()) { return; } - $this->markAggregateAsChanged( - $event->contentStreamId, - $event->nodeAggregateId, - ); + foreach ($event->affectedOriginDimensionSpacePoints as $originDimensionSpacePoint) { + $this->markAsChanged( + $event->contentStreamId, + $event->nodeAggregateId, + $originDimensionSpacePoint + ); + } } private function whenContentStreamWasRemoved(ContentStreamWasRemoved $event): void @@ -452,19 +458,6 @@ static function (Change $change) { ); } - private function markAggregateAsChanged( - ContentStreamId $contentStreamId, - NodeAggregateId $nodeAggregateId, - ): void { - $this->modifyChangeForAggregate( - $contentStreamId, - $nodeAggregateId, - static function (Change $change) { - $change->changed = true; - } - ); - } - private function markAsCreated( ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, @@ -514,23 +507,6 @@ private function modifyChange( } } - private function modifyChangeForAggregate( - ContentStreamId $contentStreamId, - NodeAggregateId $nodeAggregateId, - callable $modifyFn - ): void { - $change = $this->getChangeForAggregate($contentStreamId, $nodeAggregateId); - - if ($change === null) { - $change = new Change($contentStreamId, $nodeAggregateId, null, false, false, false, false); - $modifyFn($change); - $change->addToDatabase($this->dbal, $this->tableNamePrefix); - } else { - $modifyFn($change); - $change->updateToDatabase($this->dbal, $this->tableNamePrefix); - } - } - private function getChange( ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, @@ -552,25 +528,6 @@ private function getChange( return $changeRow ? Change::fromDatabaseRow($changeRow) : null; } - private function getChangeForAggregate( - ContentStreamId $contentStreamId, - NodeAggregateId $nodeAggregateId, - ): ?Change { - $changeRow = $this->dbal->executeQuery( - 'SELECT n.* FROM ' . $this->tableNamePrefix . ' n -WHERE n.contentStreamId = :contentStreamId -AND n.nodeAggregateId = :nodeAggregateId -AND n.origindimensionspacepointhash = :origindimensionspacepointhash', - [ - 'contentStreamId' => $contentStreamId->value, - 'nodeAggregateId' => $nodeAggregateId->value, - 'origindimensionspacepointhash' => Change::AGGREGATE_DIMENSIONSPACEPOINT_HASH_PLACEHOLDER - ] - )->fetchAssociative(); - - return $changeRow ? Change::fromDatabaseRow($changeRow) : null; - } - private function removeChangesForContentStreamId(ContentStreamId $contentStreamId): void { $statement = <<deleted !== (bool)$tableRow['deleted'] || $change->changed !== (bool)$tableRow['changed'] || $change->moved !== (bool)$tableRow['moved'] - || ( - ($change->originDimensionSpacePoint === null && strtolower($tableRow['originDimensionSpacePoint']) !== "null") - && - ($change->originDimensionSpacePoint !== null && strtolower($tableRow['originDimensionSpacePoint']) !== "null" && !$change->originDimensionSpacePoint->equals(DimensionSpacePoint::fromJsonString($tableRow['originDimensionSpacePoint']))) - ) + || !$change->originDimensionSpacePoint->equals(DimensionSpacePoint::fromJsonString($tableRow['originDimensionSpacePoint'])) ) { continue; } diff --git a/Neos.Neos/Tests/Behavior/Features/PendingChanges/08-NodeRenaming/01-ChangeNodeAggregateName_WithoutDimensions.feature b/Neos.Neos/Tests/Behavior/Features/PendingChanges/08-NodeRenaming/01-ChangeNodeAggregateName_WithoutDimensions.feature index 4082df00bd..da8ebf49be 100644 --- a/Neos.Neos/Tests/Behavior/Features/PendingChanges/08-NodeRenaming/01-ChangeNodeAggregateName_WithoutDimensions.feature +++ b/Neos.Neos/Tests/Behavior/Features/PendingChanges/08-NodeRenaming/01-ChangeNodeAggregateName_WithoutDimensions.feature @@ -56,7 +56,7 @@ Feature: Change node aggregate name without dimensions Then I expect the ChangeProjection to have the following changes in "user-cs-id": | nodeAggregateId | created | changed | moved | deleted | originDimensionSpacePoint | - | sir-david-nodenborough | 0 | 1 | 0 | 0 | null | + | sir-david-nodenborough | 0 | 1 | 0 | 0 | {} | And I expect the ChangeProjection to have no changes in "cs-identifier" Scenario: Change the node aggregate name with already applied changes @@ -74,6 +74,5 @@ Feature: Change node aggregate name without dimensions Then I expect the ChangeProjection to have the following changes in "user-cs-id": | nodeAggregateId | created | changed | moved | deleted | originDimensionSpacePoint | - | sir-david-nodenborough | 0 | 1 | 0 | 0 | null | | sir-david-nodenborough | 0 | 1 | 0 | 0 | {} | And I expect the ChangeProjection to have no changes in "cs-identifier" diff --git a/Neos.Neos/Tests/Behavior/Features/PendingChanges/08-NodeRenaming/02-ChangeNodeAggregateName_WithDimensions.feature b/Neos.Neos/Tests/Behavior/Features/PendingChanges/08-NodeRenaming/02-ChangeNodeAggregateName_WithDimensions.feature index 06897a88ee..988d45c394 100644 --- a/Neos.Neos/Tests/Behavior/Features/PendingChanges/08-NodeRenaming/02-ChangeNodeAggregateName_WithDimensions.feature +++ b/Neos.Neos/Tests/Behavior/Features/PendingChanges/08-NodeRenaming/02-ChangeNodeAggregateName_WithDimensions.feature @@ -69,7 +69,8 @@ Feature: Change node aggregate name with dimensions Then I expect the ChangeProjection to have the following changes in "user-cs-id": | nodeAggregateId | created | changed | moved | deleted | originDimensionSpacePoint | - | sir-david-nodenborough | 0 | 1 | 0 | 0 | null | + | sir-david-nodenborough | 0 | 1 | 0 | 0 | {"language":"de"} | + | sir-david-nodenborough | 0 | 1 | 0 | 0 | {"language":"fr"} | And I expect the ChangeProjection to have no changes in "cs-identifier" Scenario: Change the node aggregate type with already applied changes @@ -87,6 +88,6 @@ Feature: Change node aggregate name with dimensions Then I expect the ChangeProjection to have the following changes in "user-cs-id": | nodeAggregateId | created | changed | moved | deleted | originDimensionSpacePoint | - | sir-david-nodenborough | 0 | 1 | 0 | 0 | null | | sir-david-nodenborough | 0 | 1 | 0 | 0 | {"language":"de"} | + | sir-david-nodenborough | 0 | 1 | 0 | 0 | {"language":"fr"} | And I expect the ChangeProjection to have no changes in "cs-identifier" diff --git a/Neos.Neos/Tests/Behavior/Features/PendingChanges/09-NodeTypeChange/01-ChangeNodeAggregateType_WithoutDimensions.feature b/Neos.Neos/Tests/Behavior/Features/PendingChanges/09-NodeTypeChange/01-ChangeNodeAggregateType_WithoutDimensions.feature index ee0793e9ca..caab5b873e 100644 --- a/Neos.Neos/Tests/Behavior/Features/PendingChanges/09-NodeTypeChange/01-ChangeNodeAggregateType_WithoutDimensions.feature +++ b/Neos.Neos/Tests/Behavior/Features/PendingChanges/09-NodeTypeChange/01-ChangeNodeAggregateType_WithoutDimensions.feature @@ -58,7 +58,7 @@ Feature: Change node aggregate type without dimensions Then I expect the ChangeProjection to have the following changes in "user-cs-id": | nodeAggregateId | created | changed | moved | deleted | originDimensionSpacePoint | - | sir-david-nodenborough | 0 | 1 | 0 | 0 | null | + | sir-david-nodenborough | 0 | 1 | 0 | 0 | {} | And I expect the ChangeProjection to have no changes in "cs-identifier" Scenario: Change the node aggregate type with already applied changes @@ -78,6 +78,5 @@ Feature: Change node aggregate type without dimensions Then I expect the ChangeProjection to have the following changes in "user-cs-id": | nodeAggregateId | created | changed | moved | deleted | originDimensionSpacePoint | - | sir-david-nodenborough | 0 | 1 | 0 | 0 | null | | sir-david-nodenborough | 0 | 1 | 0 | 0 | {} | And I expect the ChangeProjection to have no changes in "cs-identifier" diff --git a/Neos.Neos/Tests/Behavior/Features/PendingChanges/09-NodeTypeChange/02-ChangeNodeAggregateType_WithDimensions.feature b/Neos.Neos/Tests/Behavior/Features/PendingChanges/09-NodeTypeChange/02-ChangeNodeAggregateType_WithDimensions.feature index fa37c9700c..5c86289775 100644 --- a/Neos.Neos/Tests/Behavior/Features/PendingChanges/09-NodeTypeChange/02-ChangeNodeAggregateType_WithDimensions.feature +++ b/Neos.Neos/Tests/Behavior/Features/PendingChanges/09-NodeTypeChange/02-ChangeNodeAggregateType_WithDimensions.feature @@ -71,7 +71,8 @@ Feature: Change node aggregate type with dimensions Then I expect the ChangeProjection to have the following changes in "user-cs-id": | nodeAggregateId | created | changed | moved | deleted | originDimensionSpacePoint | - | sir-david-nodenborough | 0 | 1 | 0 | 0 | null | + | sir-david-nodenborough | 0 | 1 | 0 | 0 | {"language":"de"} | + | sir-david-nodenborough | 0 | 1 | 0 | 0 | {"language":"fr"} | And I expect the ChangeProjection to have no changes in "cs-identifier" Scenario: Change the node aggregate type with already applied changes @@ -91,6 +92,6 @@ Feature: Change node aggregate type with dimensions Then I expect the ChangeProjection to have the following changes in "user-cs-id": | nodeAggregateId | created | changed | moved | deleted | originDimensionSpacePoint | - | sir-david-nodenborough | 0 | 1 | 0 | 0 | null | | sir-david-nodenborough | 0 | 1 | 0 | 0 | {"language":"de"} | + | sir-david-nodenborough | 0 | 1 | 0 | 0 | {"language":"fr"} | And I expect the ChangeProjection to have no changes in "cs-identifier" diff --git a/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php b/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php index 8718f28aed..eb106bdb58 100644 --- a/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php +++ b/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php @@ -672,9 +672,6 @@ protected function computeSiteChanges(Workspace $selectedWorkspace, ContentRepos ->findByContentStreamId( $selectedWorkspace->currentContentStreamId ); - $dimensionSpacePoints = iterator_to_array($contentRepository->getVariationGraph()->getDimensionSpacePoints()); - /** @var DimensionSpacePoint $arbitraryDimensionSpacePoint */ - $arbitraryDimensionSpacePoint = reset($dimensionSpacePoints); $selectedWorkspaceContentGraph = $contentRepository->getContentGraph($selectedWorkspace->workspaceName); // If we deleted a node, there is no way for us to anymore find the deleted node in the ContentStream @@ -688,7 +685,7 @@ protected function computeSiteChanges(Workspace $selectedWorkspace, ContentRepos foreach ($changes as $change) { $contentGraph = $change->deleted ? $baseWorkspaceContentGraph : $selectedWorkspaceContentGraph; $subgraph = $contentGraph->getSubgraph( - $change->originDimensionSpacePoint?->toDimensionSpacePoint() ?: $arbitraryDimensionSpacePoint, + $change->originDimensionSpacePoint->toDimensionSpacePoint(), VisibilityConstraints::withoutRestrictions() ); @@ -756,7 +753,7 @@ protected function computeSiteChanges(Workspace $selectedWorkspace, ContentRepos $nodeAddress = NodeAddress::create( $contentRepository->id, $selectedWorkspace->workspaceName, - $change->originDimensionSpacePoint?->toDimensionSpacePoint() ?: $arbitraryDimensionSpacePoint, + $change->originDimensionSpacePoint->toDimensionSpacePoint(), $change->nodeAggregateId );