From 78848eec409f4b215e1b4a0c6b137dba34fc0f15 Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Mon, 18 Mar 2024 23:58:40 +0100 Subject: [PATCH 1/6] TASK: Deprecate `NodeAddress` The nodeadress was added 6 years ago without the concept of multiple crs. It will be replaced by the node identity --- Neos.Neos/Classes/FrontendRouting/NodeAddress.php | 4 +++- Neos.Neos/Classes/FrontendRouting/NodeAddressFactory.php | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Neos.Neos/Classes/FrontendRouting/NodeAddress.php b/Neos.Neos/Classes/FrontendRouting/NodeAddress.php index 02425474659..19708e4d101 100644 --- a/Neos.Neos/Classes/FrontendRouting/NodeAddress.php +++ b/Neos.Neos/Classes/FrontendRouting/NodeAddress.php @@ -31,7 +31,9 @@ * * It is used in Neos Routing to build a URI to a node. * - * @api + * @deprecated will be removed before Final 9.0 + * The NodeAddress was added 6 years ago without the concept of multiple crs + * Its usages will be replaced by the node identity */ #[Flow\Proxy(false)] final class NodeAddress diff --git a/Neos.Neos/Classes/FrontendRouting/NodeAddressFactory.php b/Neos.Neos/Classes/FrontendRouting/NodeAddressFactory.php index 3a2f28c2a7f..9781840a45a 100644 --- a/Neos.Neos/Classes/FrontendRouting/NodeAddressFactory.php +++ b/Neos.Neos/Classes/FrontendRouting/NodeAddressFactory.php @@ -22,7 +22,7 @@ use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** - * @api + * @deprecated will be removed before Final 9.0 */ class NodeAddressFactory { From 75aecf05b417dc75154cac8eeecfc52bfa33d61f Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Mon, 18 Mar 2024 23:59:56 +0100 Subject: [PATCH 2/6] The ~bourne~ node identity --- .../Classes/SharedModel/Node/NodeIdentity.php | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 Neos.ContentRepository.Core/Classes/SharedModel/Node/NodeIdentity.php diff --git a/Neos.ContentRepository.Core/Classes/SharedModel/Node/NodeIdentity.php b/Neos.ContentRepository.Core/Classes/SharedModel/Node/NodeIdentity.php new file mode 100644 index 00000000000..6e0dd820572 --- /dev/null +++ b/Neos.ContentRepository.Core/Classes/SharedModel/Node/NodeIdentity.php @@ -0,0 +1,93 @@ +getWorkspaceFinder()->findOneByName($identity->workspaceName); + * $subgraph = $contentGraph->getSubgraph( + * $workspace->currentContentStreamId, + * $nodeIdentity->dimensionSpacePoint, + * // resolve also all disabled nodes + * VisibilityConstraints::withoutRestrictions() + * ); + * $node = $subgraph->findNodeById($nodeIdentity->nodeAggregateId); + * + * @api + */ +final readonly class NodeIdentity implements \JsonSerializable +{ + private function __construct( + public ContentRepositoryId $contentRepositoryId, + public WorkspaceName $workspaceName, + public DimensionSpacePoint $dimensionSpacePoint, + public NodeAggregateId $nodeAggregateId, + ) { + } + + public static function create( + ContentRepositoryId $contentRepositoryId, + WorkspaceName $workspaceName, + DimensionSpacePoint $dimensionSpacePoint, + NodeAggregateId $nodeAggregateId, + ): self { + return new self($contentRepositoryId, $workspaceName, $dimensionSpacePoint, $nodeAggregateId); + } + + /** + * @param array $array + */ + public static function fromArray(array $array): self + { + return new self( + ContentRepositoryId::fromString($array['contentRepositoryId']), + WorkspaceName::fromString($array['workspaceName']), + DimensionSpacePoint::fromArray($array['dimensionSpacePoint']), + NodeAggregateId::fromString($array['nodeAggregateId']) + ); + } + + public static function fromJsonString(string $jsonString): self + { + return self::fromArray(\json_decode($jsonString, true, JSON_THROW_ON_ERROR)); + } + + public function withNodeAggregateId(NodeAggregateId $nodeAggregateId): self + { + return new self($this->contentRepositoryId, $this->workspaceName, $this->dimensionSpacePoint, $nodeAggregateId); + } + + public function equals(self $other): bool + { + return $this->contentRepositoryId->equals($other->contentRepositoryId) + && $this->workspaceName->equals($other->workspaceName) + && $this->dimensionSpacePoint->equals($other->dimensionSpacePoint) + && $this->nodeAggregateId->equals($other->nodeAggregateId); + } + + public function toJson(): string + { + return json_encode($this, JSON_THROW_ON_ERROR); + } + + public function jsonSerialize(): mixed + { + return [ + 'contentRepositoryId' => $this->contentRepositoryId, + 'workspaceName' => $this->workspaceName, + 'dimensionSpacePoint' => $this->dimensionSpacePoint, + 'nodeAggregateId' => $this->nodeAggregateId + ]; + } +} From ea65fdf8838d19915479e33828957207856796da Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Tue, 19 Mar 2024 21:37:41 +0100 Subject: [PATCH 3/6] WIP: Prepare node factory to build nodes with node identity --- .../src/Domain/Repository/ContentGraph.php | 3 ++ .../src/Domain/Repository/ContentSubgraph.php | 31 +++++++++++-- .../src/Domain/Repository/NodeFactory.php | 43 ++++++++++++++----- .../src/Domain/Repository/NodeFactory.php | 11 ++++- .../Classes/Projection/ContentGraph/Node.php | 9 +++- .../Projection/ContentGraph/NodeAggregate.php | 1 + .../Classes/Unit/NodeSubjectProvider.php | 10 ++++- 7 files changed, 90 insertions(+), 18 deletions(-) diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ContentGraph.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ContentGraph.php index 1df35d06fa3..2282f51de73 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ContentGraph.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ContentGraph.php @@ -40,6 +40,7 @@ use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * The Doctrine DBAL adapter content graph @@ -88,6 +89,8 @@ final public function getSubgraph( $this->subgraphs[$index] = new ContentSubgraphWithRuntimeCaches( new ContentSubgraph( $this->contentRepositoryId, + // todo accept Workspace + WorkspaceName::forLive(), $contentStreamId, $dimensionSpacePoint, $visibilityConstraints, diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ContentSubgraph.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ContentSubgraph.php index c1a278822d7..8f2831e18af 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ContentSubgraph.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ContentSubgraph.php @@ -72,6 +72,7 @@ use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\ContentRepository\Core\SharedModel\Node\PropertyName; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * The content subgraph application repository @@ -105,6 +106,7 @@ final class ContentSubgraph implements ContentSubgraphInterface public function __construct( private readonly ContentRepositoryId $contentRepositoryId, + private readonly WorkspaceName $workspaceName, private readonly ContentStreamId $contentStreamId, private readonly DimensionSpacePoint $dimensionSpacePoint, private readonly VisibilityConstraints $visibilityConstraints, @@ -328,7 +330,13 @@ public function findSubtree(NodeAggregateId $entryNodeAggregateId, FindSubtreeFi foreach (array_reverse($result) as $nodeData) { $nodeAggregateId = $nodeData['nodeaggregateid']; $parentNodeAggregateId = $nodeData['parentNodeAggregateId']; - $node = $this->nodeFactory->mapNodeRowToNode($nodeData, $this->contentStreamId, $this->dimensionSpacePoint, $this->visibilityConstraints); + $node = $this->nodeFactory->mapNodeRowToNode( + $nodeData, + $this->workspaceName, + $this->contentStreamId, + $this->dimensionSpacePoint, + $this->visibilityConstraints + ); $subtree = new Subtree((int)$nodeData['level'], $node, array_key_exists($nodeAggregateId, $subtreesByParentNodeId) ? array_reverse($subtreesByParentNodeId[$nodeAggregateId]) : []); if ($subtree->level === 0) { return $subtree; @@ -357,6 +365,7 @@ public function findAncestorNodes(NodeAggregateId $entryNodeAggregateId, FindAnc return $this->nodeFactory->mapNodeRowsToNodes( $nodeRows, + $this->workspaceName, $this->contentStreamId, $this->dimensionSpacePoint, $this->visibilityConstraints @@ -418,6 +427,7 @@ public function findClosestNode(NodeAggregateId $entryNodeAggregateId, FindClose ); return $this->nodeFactory->mapNodeRowsToNodes( $nodeRows, + $this->workspaceName, $this->contentStreamId, $this->dimensionSpacePoint, $this->visibilityConstraints @@ -435,7 +445,13 @@ public function findDescendantNodes(NodeAggregateId $entryNodeAggregateId, FindD } $queryBuilderCte->addOrderBy('level')->addOrderBy('position'); $nodeRows = $this->fetchCteResults($queryBuilderInitial, $queryBuilderRecursive, $queryBuilderCte, 'tree'); - return $this->nodeFactory->mapNodeRowsToNodes($nodeRows, $this->contentStreamId, $this->dimensionSpacePoint, $this->visibilityConstraints); + return $this->nodeFactory->mapNodeRowsToNodes( + $nodeRows, + $this->workspaceName, + $this->contentStreamId, + $this->dimensionSpacePoint, + $this->visibilityConstraints + ); } public function countDescendantNodes(NodeAggregateId $entryNodeAggregateId, CountDescendantNodesFilter $filter): int @@ -863,6 +879,7 @@ private function fetchNode(QueryBuilder $queryBuilder): ?Node } return $this->nodeFactory->mapNodeRowToNode( $nodeRow, + $this->workspaceName, $this->contentStreamId, $this->dimensionSpacePoint, $this->visibilityConstraints @@ -876,7 +893,13 @@ private function fetchNodes(QueryBuilder $queryBuilder): Nodes } catch (DbalDriverException | DbalException $e) { throw new \RuntimeException(sprintf('Failed to fetch nodes: %s', $e->getMessage()), 1678292896, $e); } - return $this->nodeFactory->mapNodeRowsToNodes($nodeRows, $this->contentStreamId, $this->dimensionSpacePoint, $this->visibilityConstraints); + return $this->nodeFactory->mapNodeRowsToNodes( + $nodeRows, + $this->workspaceName, + $this->contentStreamId, + $this->dimensionSpacePoint, + $this->visibilityConstraints + ); } private function fetchCount(QueryBuilder $queryBuilder): int @@ -895,7 +918,7 @@ private function fetchReferences(QueryBuilder $queryBuilder): References } catch (DbalDriverException | DbalException $e) { throw new \RuntimeException(sprintf('Failed to fetch references: %s', $e->getMessage()), 1678364944, $e); } - return $this->nodeFactory->mapReferenceRowsToReferences($referenceRows, $this->contentStreamId, $this->dimensionSpacePoint, $this->visibilityConstraints); + return $this->nodeFactory->mapReferenceRowsToReferences($referenceRows, $this->workspaceName, $this->contentStreamId, $this->dimensionSpacePoint, $this->visibilityConstraints); } /** diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/NodeFactory.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/NodeFactory.php index 88887b67d9a..0fe0b89ff34 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/NodeFactory.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/NodeFactory.php @@ -16,7 +16,6 @@ use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet; -use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePointSet; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValues; use Neos\ContentRepository\Core\Feature\SubtreeTagging\Dto\SubtreeTags; @@ -40,9 +39,11 @@ use Neos\ContentRepository\Core\SharedModel\Exception\NodeTypeNotFoundException; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateClassification; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; +use Neos\ContentRepository\Core\SharedModel\Node\NodeIdentity; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\ContentRepository\Core\SharedModel\Node\ReferenceName; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * Implementation detail of ContentGraph and ContentSubgraph @@ -64,22 +65,29 @@ public function __construct( */ public function mapNodeRowToNode( array $nodeRow, + WorkspaceName $workspaceName, ContentStreamId $contentStreamId, DimensionSpacePoint $dimensionSpacePoint, - VisibilityConstraints $visibilityConstraints + VisibilityConstraints $visibilityConstraints, ): Node { $nodeType = $this->nodeTypeManager->hasNodeType($nodeRow['nodetypename']) ? $this->nodeTypeManager->getNodeType($nodeRow['nodetypename']) : null; return Node::create( + NodeIdentity::create( + $this->contentRepositoryId, + $workspaceName, + $dimensionSpacePoint, + $nodeId = NodeAggregateId::fromString($nodeRow['nodeaggregateid']) + ), ContentSubgraphIdentity::create( $this->contentRepositoryId, $contentStreamId, $dimensionSpacePoint, $visibilityConstraints ), - NodeAggregateId::fromString($nodeRow['nodeaggregateid']), + $nodeId, $this->dimensionSpacePointRepository->getOriginDimensionSpacePointByHash($nodeRow['origindimensionspacepointhash']), NodeAggregateClassification::from($nodeRow['classification']), NodeTypeName::fromString($nodeRow['nodetypename']), @@ -99,10 +107,21 @@ public function mapNodeRowToNode( /** * @param array> $nodeRows */ - public function mapNodeRowsToNodes(array $nodeRows, ContentStreamId $contentStreamId, DimensionSpacePoint $dimensionSpacePoint, VisibilityConstraints $visibilityConstraints): Nodes - { + public function mapNodeRowsToNodes( + array $nodeRows, + WorkspaceName $workspaceName, + ContentStreamId $contentStreamId, + DimensionSpacePoint $dimensionSpacePoint, + VisibilityConstraints $visibilityConstraints + ): Nodes { return Nodes::fromArray( - array_map(fn (array $nodeRow) => $this->mapNodeRowToNode($nodeRow, $contentStreamId, $dimensionSpacePoint, $visibilityConstraints), $nodeRows) + array_map(fn (array $nodeRow) => $this->mapNodeRowToNode( + $nodeRow, + $workspaceName, + $contentStreamId, + $dimensionSpacePoint, + $visibilityConstraints + ), $nodeRows) ); } @@ -119,6 +138,7 @@ public function createPropertyCollectionFromJsonString(string $jsonString): Prop */ public function mapReferenceRowsToReferences( array $nodeRows, + WorkspaceName $workspaceName, ContentStreamId $contentStreamId, DimensionSpacePoint $dimensionSpacePoint, VisibilityConstraints $visibilityConstraints @@ -127,6 +147,7 @@ public function mapReferenceRowsToReferences( foreach ($nodeRows as $nodeRow) { $node = $this->mapNodeRowToNode( $nodeRow, + $workspaceName, $contentStreamId, $dimensionSpacePoint, $visibilityConstraints @@ -175,6 +196,7 @@ public function mapNodeRowsToNodeAggregate( // ... so we handle occupation exactly once ... $nodesByOccupiedDimensionSpacePoints[$occupiedDimensionSpacePoint->hash] = $this->mapNodeRowToNode( $nodeRow, + WorkspaceName::forLive(), // todo use workspace name in content graph api $contentStreamId, $occupiedDimensionSpacePoint->toDimensionSpacePoint(), $visibilityConstraints @@ -255,10 +277,11 @@ public function mapNodeRowsToNodeAggregates( // ... so we handle occupation exactly once ... $nodesByOccupiedDimensionSpacePointsByNodeAggregate [$rawNodeAggregateId][$occupiedDimensionSpacePoint->hash] = $this->mapNodeRowToNode( - $nodeRow, - $contentStreamId, - $occupiedDimensionSpacePoint->toDimensionSpacePoint(), - $visibilityConstraints + $nodeRow, + WorkspaceName::forLive(), // todo use workspace name in content graph api + $contentStreamId, + $occupiedDimensionSpacePoint->toDimensionSpacePoint(), + $visibilityConstraints ); $occupiedDimensionSpacePointsByNodeAggregate[$rawNodeAggregateId][] = $occupiedDimensionSpacePoint; diff --git a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Repository/NodeFactory.php b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Repository/NodeFactory.php index da9b96cf28c..147283b0735 100644 --- a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Repository/NodeFactory.php +++ b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Repository/NodeFactory.php @@ -39,9 +39,11 @@ use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateClassification; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; +use Neos\ContentRepository\Core\SharedModel\Node\NodeIdentity; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\ContentRepository\Core\SharedModel\Node\ReferenceName; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * The node factory for mapping database rows to nodes and node aggregates @@ -77,13 +79,20 @@ public function mapNodeRowToNode( : null; return Node::create( + NodeIdentity::create( + $this->contentRepositoryId, + // todo use actual workspace name + WorkspaceName::fromString('missing'), + $dimensionSpacePoint ?: DimensionSpacePoint::fromJsonString($nodeRow['dimensionspacepoint']), + $nodeId = NodeAggregateId::fromString($nodeRow['nodeaggregateid']) + ), ContentSubgraphIdentity::create( $this->contentRepositoryId, $contentStreamId ?: ContentStreamId::fromString($nodeRow['contentstreamid']), $dimensionSpacePoint ?: DimensionSpacePoint::fromJsonString($nodeRow['dimensionspacepoint']), $visibilityConstraints ), - NodeAggregateId::fromString($nodeRow['nodeaggregateid']), + $nodeId, OriginDimensionSpacePoint::fromJsonString($nodeRow['origindimensionspacepoint']), NodeAggregateClassification::from($nodeRow['classification']), NodeTypeName::fromString($nodeRow['nodetypename']), diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Node.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Node.php index e89b8aec790..e86a7c17c77 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Node.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Node.php @@ -19,6 +19,7 @@ use Neos\ContentRepository\Core\NodeType\NodeTypeName; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateClassification; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; +use Neos\ContentRepository\Core\SharedModel\Node\NodeIdentity; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; /** @@ -34,6 +35,8 @@ * call findChildNodes() {@see ContentSubgraphInterface::findChildNodes()} * on the subgraph. * + * The identity of a node is summarized here {@see NodeIdentity} + * * @api Note: The constructor is not part of the public API */ final readonly class Node @@ -51,6 +54,8 @@ * @param Timestamps $timestamps Creation and modification timestamps of this node */ private function __construct( + public NodeIdentity $identity, + /** @deprecated will be removed before the final 9.0 release */ public ContentSubgraphIdentity $subgraphIdentity, public NodeAggregateId $nodeAggregateId, public OriginDimensionSpacePoint $originDimensionSpacePoint, @@ -70,9 +75,9 @@ private function __construct( /** * @internal The signature of this method can change in the future! */ - public static function create(ContentSubgraphIdentity $subgraphIdentity, NodeAggregateId $nodeAggregateId, OriginDimensionSpacePoint $originDimensionSpacePoint, NodeAggregateClassification $classification, NodeTypeName $nodeTypeName, ?NodeType $nodeType, PropertyCollection $properties, ?NodeName $nodeName, NodeTags $tags, Timestamps $timestamps): self + public static function create(NodeIdentity $identity, ContentSubgraphIdentity $subgraphIdentity, NodeAggregateId $nodeAggregateId, OriginDimensionSpacePoint $originDimensionSpacePoint, NodeAggregateClassification $classification, NodeTypeName $nodeTypeName, ?NodeType $nodeType, PropertyCollection $properties, ?NodeName $nodeName, NodeTags $tags, Timestamps $timestamps): self { - return new self($subgraphIdentity, $nodeAggregateId, $originDimensionSpacePoint, $classification, $nodeTypeName, $nodeType, $properties, $nodeName, $tags, $timestamps); + return new self($identity, $subgraphIdentity, $nodeAggregateId, $originDimensionSpacePoint, $classification, $nodeTypeName, $nodeType, $properties, $nodeName, $tags, $timestamps); } /** diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/NodeAggregate.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/NodeAggregate.php index 8db6d42a471..098afc28c99 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/NodeAggregate.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/NodeAggregate.php @@ -65,6 +65,7 @@ final class NodeAggregate * @param OriginByCoverage $occupationByCovered * @param DimensionSpacePointsBySubtreeTags $dimensionSpacePointsBySubtreeTags dimension space points for every subtree tag this aggregate is *explicitly* tagged with (excluding inherited tags) */ + // todo add workspace name and content repository id and remove cs id public function __construct( public readonly ContentStreamId $contentStreamId, public readonly NodeAggregateId $nodeAggregateId, diff --git a/Neos.ContentRepository.TestSuite/Classes/Unit/NodeSubjectProvider.php b/Neos.ContentRepository.TestSuite/Classes/Unit/NodeSubjectProvider.php index 61ce76d10d0..1b1abc4fb62 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Unit/NodeSubjectProvider.php +++ b/Neos.ContentRepository.TestSuite/Classes/Unit/NodeSubjectProvider.php @@ -37,8 +37,10 @@ use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateClassification; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; +use Neos\ContentRepository\Core\SharedModel\Node\NodeIdentity; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Symfony\Component\Serializer\Normalizer\BackedEnumNormalizer; use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; use Symfony\Component\Serializer\Serializer; @@ -87,13 +89,19 @@ public function createMinimalNodeOfType( ): Node { $serializedDefaultPropertyValues = SerializedPropertyValues::defaultFromNodeType($nodeType, $this->propertyConverter); return Node::create( + NodeIdentity::create( + ContentRepositoryId::fromString('default'), + WorkspaceName::forLive(), + DimensionSpacePoint::createWithoutDimensions(), + $id = NodeAggregateId::create() + ), ContentSubgraphIdentity::create( ContentRepositoryId::fromString('default'), ContentStreamId::fromString('cs-id'), DimensionSpacePoint::createWithoutDimensions(), VisibilityConstraints::withoutRestrictions() ), - NodeAggregateId::create(), + $id, OriginDimensionSpacePoint::createWithoutDimensions(), NodeAggregateClassification::CLASSIFICATION_REGULAR, $nodeType->name, From f6e4e7fbd53828036042bd4ae8d59ffbfca96669 Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Tue, 19 Mar 2024 22:10:44 +0100 Subject: [PATCH 4/6] TASK: Add `cr_default_p_graph_workspaces` table It will keep track of the current workspace name to content stream id mapping --- .../DoctrineDbalContentGraphProjection.php | 37 ++++++- .../DoctrineDbalContentGraphSchemaBuilder.php | 13 ++- .../CurrentWorkspaceContentStreamId.php | 98 +++++++++++++++++++ .../Repository/ProjectionContentGraph.php | 2 +- 4 files changed, 147 insertions(+), 3 deletions(-) create mode 100644 Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/CurrentWorkspaceContentStreamId.php diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphProjection.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphProjection.php index 54e6296c3b3..f7bd293e2b2 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphProjection.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphProjection.php @@ -7,6 +7,7 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\Schema\AbstractSchemaManager; use Doctrine\DBAL\Types\Types; +use Neos\ContentGraph\DoctrineDbalAdapter\Domain\Projection\Feature\CurrentWorkspaceContentStreamId; use Neos\ContentGraph\DoctrineDbalAdapter\Domain\Projection\Feature\NodeMove; use Neos\ContentGraph\DoctrineDbalAdapter\Domain\Projection\Feature\NodeRemoval; use Neos\ContentGraph\DoctrineDbalAdapter\Domain\Projection\Feature\NodeVariation; @@ -43,6 +44,15 @@ use Neos\ContentRepository\Core\Feature\SubtreeTagging\Dto\SubtreeTags; use Neos\ContentRepository\Core\Feature\SubtreeTagging\Event\SubtreeWasTagged; use Neos\ContentRepository\Core\Feature\SubtreeTagging\Event\SubtreeWasUntagged; +use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Event\RootWorkspaceWasCreated; +use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Event\WorkspaceWasCreated; +use Neos\ContentRepository\Core\Feature\WorkspaceModification\Event\WorkspaceBaseWorkspaceWasChanged; +use Neos\ContentRepository\Core\Feature\WorkspaceModification\Event\WorkspaceWasRemoved; +use Neos\ContentRepository\Core\Feature\WorkspacePublication\Event\WorkspaceWasDiscarded; +use Neos\ContentRepository\Core\Feature\WorkspacePublication\Event\WorkspaceWasPartiallyDiscarded; +use Neos\ContentRepository\Core\Feature\WorkspacePublication\Event\WorkspaceWasPartiallyPublished; +use Neos\ContentRepository\Core\Feature\WorkspacePublication\Event\WorkspaceWasPublished; +use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Event\WorkspaceWasRebased; use Neos\ContentRepository\Core\Infrastructure\DbalCheckpointStorage; use Neos\ContentRepository\Core\Infrastructure\DbalClientInterface; use Neos\ContentRepository\Core\Infrastructure\DbalSchemaDiff; @@ -72,7 +82,7 @@ final class DoctrineDbalContentGraphProjection implements ProjectionInterface, W use SubtreeTagging; use NodeRemoval; use NodeMove; - + use CurrentWorkspaceContentStreamId; public const RELATION_DEFAULT_OFFSET = 128; @@ -177,6 +187,7 @@ private function truncateDatabaseTables(): void $connection->executeQuery('TRUNCATE table ' . $this->tableNamePrefix . '_hierarchyrelation'); $connection->executeQuery('TRUNCATE table ' . $this->tableNamePrefix . '_referencerelation'); $connection->executeQuery('TRUNCATE table ' . $this->tableNamePrefix . '_dimensionspacepoints'); + $connection->executeQuery('TRUNCATE table ' . $this->tableNamePrefix . '_workspaces'); } public function canHandle(EventInterface $event): bool @@ -200,6 +211,21 @@ public function canHandle(EventInterface $event): bool NodePeerVariantWasCreated::class, SubtreeWasTagged::class, SubtreeWasUntagged::class, + + /** + * Workspace related commands, see {@see CurrentWorkspaceContentStreamId} + * We are not interested in the events WorkspaceWasRenamed, WorkspaceRebaseFailed and WorkspaceOwnerWasChanged + * As they do not change the current content stream id + */ + WorkspaceWasCreated::class, + RootWorkspaceWasCreated::class, + WorkspaceWasDiscarded::class, + WorkspaceWasPartiallyDiscarded::class, + WorkspaceWasPartiallyPublished::class, + WorkspaceWasPublished::class, + WorkspaceWasRebased::class, + WorkspaceWasRemoved::class, + WorkspaceBaseWorkspaceWasChanged::class, ]); } @@ -224,6 +250,15 @@ public function apply(EventInterface $event, EventEnvelope $eventEnvelope): void NodePeerVariantWasCreated::class => $this->whenNodePeerVariantWasCreated($event, $eventEnvelope), SubtreeWasTagged::class => $this->whenSubtreeWasTagged($event), SubtreeWasUntagged::class => $this->whenSubtreeWasUntagged($event), + WorkspaceWasCreated::class => $this->whenWorkspaceWasCreated($event), + RootWorkspaceWasCreated::class => $this->whenRootWorkspaceWasCreated($event), + WorkspaceWasDiscarded::class => $this->whenWorkspaceWasDiscarded($event), + WorkspaceWasPartiallyDiscarded::class => $this->whenWorkspaceWasPartiallyDiscarded($event), + WorkspaceWasPartiallyPublished::class => $this->whenWorkspaceWasPartiallyPublished($event), + WorkspaceWasPublished::class => $this->whenWorkspaceWasPublished($event), + WorkspaceWasRebased::class => $this->whenWorkspaceWasRebased($event), + WorkspaceWasRemoved::class => $this->whenWorkspaceWasRemoved($event), + WorkspaceBaseWorkspaceWasChanged::class => $this->whenWorkspaceBaseWorkspaceWasChanged($event), default => throw new \InvalidArgumentException(sprintf('Unsupported event %s', get_debug_type($event))), }; } diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphSchemaBuilder.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphSchemaBuilder.php index 06cc35ff431..879105fbd86 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphSchemaBuilder.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphSchemaBuilder.php @@ -28,7 +28,8 @@ public function buildSchema(AbstractSchemaManager $schemaManager): Schema $this->createNodeTable(), $this->createHierarchyRelationTable(), $this->createReferenceRelationTable(), - $this->createDimensionSpacePointsTable() + $this->createDimensionSpacePointsTable(), + $this->createWorkspacesTable() ]); } @@ -94,4 +95,14 @@ private function createReferenceRelationTable(): Table return $table ->setPrimaryKey(['name', 'position', 'nodeanchorpoint']); } + + private function createWorkspacesTable(): Table + { + $workspaceTable = new Table($this->tableNamePrefix . '_workspaces', [ + (new Column('workspacename', Type::getType(Types::STRING)))->setLength(255)->setNotnull(true)->setCustomSchemaOption('collation', self::DEFAULT_TEXT_COLLATION), + DbalSchemaFactory::columnForContentStreamId('currentcontentstreamid')->setNotNull(true), + ]); + + return $workspaceTable->setPrimaryKey(['workspacename']); + } } diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/CurrentWorkspaceContentStreamId.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/CurrentWorkspaceContentStreamId.php new file mode 100644 index 00000000000..5a2b2e96844 --- /dev/null +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/CurrentWorkspaceContentStreamId.php @@ -0,0 +1,98 @@ +getDatabaseConnection()->insert($this->getTableNamePrefix() . '_workspaces', [ + 'workspaceName' => $event->workspaceName->value, + 'currentContentStreamId' => $event->newContentStreamId->value + ]); + } + + private function whenRootWorkspaceWasCreated(RootWorkspaceWasCreated $event): void + { + $this->getDatabaseConnection()->insert($this->getTableNamePrefix() . '_workspaces', [ + 'workspaceName' => $event->workspaceName->value, + 'currentContentStreamId' => $event->newContentStreamId->value + ]); + } + + private function whenWorkspaceWasDiscarded(WorkspaceWasDiscarded $event): void + { + $this->updateContentStreamId($event->newContentStreamId, $event->workspaceName); + } + + private function whenWorkspaceWasPartiallyDiscarded(WorkspaceWasPartiallyDiscarded $event): void + { + $this->updateContentStreamId($event->newContentStreamId, $event->workspaceName); + } + + private function whenWorkspaceWasPartiallyPublished(WorkspaceWasPartiallyPublished $event): void + { + $this->updateContentStreamId($event->newSourceContentStreamId, $event->sourceWorkspaceName); + } + + private function whenWorkspaceWasPublished(WorkspaceWasPublished $event): void + { + $this->updateContentStreamId($event->newSourceContentStreamId, $event->sourceWorkspaceName); + } + + private function whenWorkspaceWasRebased(WorkspaceWasRebased $event): void + { + $this->updateContentStreamId($event->newContentStreamId, $event->workspaceName); + } + + private function whenWorkspaceWasRemoved(WorkspaceWasRemoved $event): void + { + $this->getDatabaseConnection()->delete( + $this->getTableNamePrefix() . '_workspaces', + ['workspaceName' => $event->workspaceName->value] + ); + } + + private function whenWorkspaceBaseWorkspaceWasChanged(WorkspaceBaseWorkspaceWasChanged $event): void + { + $this->updateContentStreamId($event->newContentStreamId, $event->workspaceName); + } + + private function updateContentStreamId( + ContentStreamId $contentStreamId, + WorkspaceName $workspaceName, + ): void { + $this->getDatabaseConnection()->update($this->getTableNamePrefix() . '_workspaces', [ + 'currentContentStreamId' => $contentStreamId->value, + ], [ + 'workspaceName' => $workspaceName->value + ]); + } +} diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ProjectionContentGraph.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ProjectionContentGraph.php index 02e6b63e5b9..78e10958e8e 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ProjectionContentGraph.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ProjectionContentGraph.php @@ -30,7 +30,7 @@ use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; /** - * The read only content graph for use by the {@see GraphProjector}. This is the class for low-level operations + * The read only content graph for use by the {@see DoctrineDbalContentGraphProjection}. This is the class for low-level operations * within the projector, where implementation details of the graph structure are known. * * This is NO PUBLIC API in any way. From 53a16874ca15e56a90c8da46c842db48e9d0ba06 Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Tue, 19 Mar 2024 23:02:33 +0100 Subject: [PATCH 5/6] !!! TASK: Require `WorkspaceName` in `getSubgraph` instead of `ContentStreamId` --- .../src/Domain/Repository/ContentGraph.php | 37 ++++++++++++++--- .../Domain/Repository/ContentHypergraph.php | 10 ++++- .../Feature/NodeTypeChange/NodeTypeChange.php | 2 +- .../ContentGraph/ContentGraphInterface.php | 3 +- .../Classes/SharedModel/Node/NodeIdentity.php | 3 +- .../Adjustment/TetheredNodeAdjustments.php | 1 + .../Command/ContentCommandController.php | 27 ++++++++----- .../Classes/ContentRepositoryRegistry.php | 6 +-- .../Service/AssetUsageSyncService.php | 1 + .../Controller/Backend/ContentController.php | 2 +- .../Controller/Frontend/NodeController.php | 4 +- .../Management/WorkspacesController.php | 27 +++++++------ .../Controller/Service/NodesController.php | 40 ++++++++----------- .../Domain/Service/SiteNodeUtility.php | 18 ++++----- .../Cache/NeosFusionContextSerializer.php | 20 +++++----- .../DimensionsMenuItemsImplementation.php | 4 +- .../Classes/Fusion/Helper/DimensionHelper.php | 6 +-- Neos.Neos/Classes/Service/LinkingService.php | 2 +- .../HackyNodeAddressToNodeConverter.php | 2 +- .../Classes/View/FusionExceptionView.php | 18 ++++----- .../ViewHelpers/Link/NodeViewHelper.php | 4 +- .../ViewHelpers/Uri/NodeViewHelper.php | 2 +- .../Service/TimeableNodeVisibilityService.php | 15 +++---- 23 files changed, 143 insertions(+), 111 deletions(-) diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ContentGraph.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ContentGraph.php index 2282f51de73..249bc8b373c 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ContentGraph.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ContentGraph.php @@ -36,6 +36,7 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; use Neos\ContentRepository\Core\SharedModel\Exception\RootNodeAggregateDoesNotExist; +use Neos\ContentRepository\Core\SharedModel\Exception\WorkspaceDoesNotExist; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateClassification; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; @@ -80,17 +81,20 @@ public function __construct( } final public function getSubgraph( - ContentStreamId $contentStreamId, + WorkspaceName $workspaceName, DimensionSpacePoint $dimensionSpacePoint, VisibilityConstraints $visibilityConstraints ): ContentSubgraphInterface { - $index = $contentStreamId->value . '-' . $dimensionSpacePoint->hash . '-' . $visibilityConstraints->getHash(); + $index = $workspaceName->value . '-' . $dimensionSpacePoint->hash . '-' . $visibilityConstraints->getHash(); if (!isset($this->subgraphs[$index])) { + $contentStreamId = $this->findCurrentContentStreamIdForWorkspaceName($workspaceName); + if (!$contentStreamId) { + throw WorkspaceDoesNotExist::butWasSupposedTo($workspaceName); + } $this->subgraphs[$index] = new ContentSubgraphWithRuntimeCaches( new ContentSubgraph( $this->contentRepositoryId, - // todo accept Workspace - WorkspaceName::forLive(), + $workspaceName, $contentStreamId, $dimensionSpacePoint, $visibilityConstraints, @@ -356,7 +360,7 @@ public function countNodes(): int try { return (int)$result->fetchOne(); } catch (DriverException | DBALException $e) { - throw new \RuntimeException(sprintf('Failed to fetch rows from database: %s', $e->getMessage()), 1701444590, $e); + throw new \RuntimeException(sprintf('Failed to count rows in database: %s', $e->getMessage()), 1701444590, $e); } } @@ -429,4 +433,27 @@ private function fetchRows(QueryBuilder $queryBuilder): array throw new \RuntimeException(sprintf('Failed to fetch rows from database: %s', $e->getMessage()), 1701444358, $e); } } + + private function findCurrentContentStreamIdForWorkspaceName(WorkspaceName $workspaceName): ?ContentStreamId + { + $query = $this->createQueryBuilder() + ->select('workspaces.currentContentStreamId') + ->from($this->tableNamePrefix . '_workspaces', 'workspaces') + ->where('workspaces.workspaceName = :workspaceName') + ->setParameter(':workspaceName', $workspaceName->value); + + $result = $query->execute(); + if (!$result instanceof Result) { + throw new \RuntimeException(sprintf('Failed to fetch contents stream for workspace. Expected result to be of type %s, got: %s', Result::class, get_debug_type($result)), 1710883555); + } + try { + $contentStreamId = $result->fetchOne(); + if ($contentStreamId === false) { + return null; + } + return ContentStreamId::fromString((string)$contentStreamId); + } catch (DriverException | DBALException $e) { + throw new \RuntimeException(sprintf('Failed to fetch row in database: %s', $e->getMessage()), 1710883554, $e); + } + } } diff --git a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Repository/ContentHypergraph.php b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Repository/ContentHypergraph.php index 49f9b7af5be..451b33811f1 100644 --- a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Repository/ContentHypergraph.php +++ b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Repository/ContentHypergraph.php @@ -35,6 +35,7 @@ use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * The PostgreSQL adapter content hypergraph @@ -50,6 +51,7 @@ final class ContentHypergraph implements ContentGraphInterface private NodeFactory $nodeFactory; /** + * @phpstan-ignore-next-line unused * @var array|ContentSubhypergraph[] */ private array $subhypergraphs; @@ -57,7 +59,9 @@ final class ContentHypergraph implements ContentGraphInterface public function __construct( PostgresDbalClientInterface $databaseClient, NodeFactory $nodeFactory, + /** @phpstan-ignore-next-line unused */ private readonly ContentRepositoryId $contentRepositoryId, + /** @phpstan-ignore-next-line unused */ private readonly NodeTypeManager $nodeTypeManager, private readonly string $tableNamePrefix ) { @@ -66,10 +70,13 @@ public function __construct( } public function getSubgraph( - ContentStreamId $contentStreamId, + WorkspaceName $workspaceName, DimensionSpacePoint $dimensionSpacePoint, VisibilityConstraints $visibilityConstraints ): ContentSubgraphInterface { + throw new \BadMethodCallException('The postgres adapter is not functional.'); + + /* $index = $contentStreamId->value . '-' . $dimensionSpacePoint->hash . '-' . $visibilityConstraints->getHash(); if (!isset($this->subhypergraphs[$index])) { $this->subhypergraphs[$index] = new ContentSubhypergraph( @@ -85,6 +92,7 @@ public function getSubgraph( } return $this->subhypergraphs[$index]; + */ } public function findRootNodeAggregateByType( diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeTypeChange/NodeTypeChange.php b/Neos.ContentRepository.Core/Classes/Feature/NodeTypeChange/NodeTypeChange.php index 25e60f27449..acd794e5d64 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeTypeChange/NodeTypeChange.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeTypeChange/NodeTypeChange.php @@ -193,7 +193,7 @@ private function handleChangeNodeAggregateType( $tetheredNodeName = NodeName::fromString($serializedTetheredNodeName); $subgraph = $contentRepository->getContentGraph()->getSubgraph( - $node->subgraphIdentity->contentStreamId, + $node->identity->workspaceName, $node->originDimensionSpacePoint->toDimensionSpacePoint(), VisibilityConstraints::withoutRestrictions() ); diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/ContentGraphInterface.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/ContentGraphInterface.php index 4d8d7e4a4a7..409480920c6 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/ContentGraphInterface.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/ContentGraphInterface.php @@ -24,6 +24,7 @@ use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * This is the MAIN ENTRY POINT for the Content Repository. This class exists only @@ -40,7 +41,7 @@ interface ContentGraphInterface extends ProjectionStateInterface * @api main API method of ContentGraph */ public function getSubgraph( - ContentStreamId $contentStreamId, + WorkspaceName $workspaceName, DimensionSpacePoint $dimensionSpacePoint, VisibilityConstraints $visibilityConstraints ): ContentSubgraphInterface; diff --git a/Neos.ContentRepository.Core/Classes/SharedModel/Node/NodeIdentity.php b/Neos.ContentRepository.Core/Classes/SharedModel/Node/NodeIdentity.php index 6e0dd820572..32d4fb1a28b 100644 --- a/Neos.ContentRepository.Core/Classes/SharedModel/Node/NodeIdentity.php +++ b/Neos.ContentRepository.Core/Classes/SharedModel/Node/NodeIdentity.php @@ -15,9 +15,8 @@ * By using the content graph for the content repository * one can build a subgraph with the right perspective to find this node: * - * $workspace = $contentRepository->getWorkspaceFinder()->findOneByName($identity->workspaceName); * $subgraph = $contentGraph->getSubgraph( - * $workspace->currentContentStreamId, + * $identity->workspaceName, * $nodeIdentity->dimensionSpacePoint, * // resolve also all disabled nodes * VisibilityConstraints::withoutRestrictions() diff --git a/Neos.ContentRepository.StructureAdjustment/src/Adjustment/TetheredNodeAdjustments.php b/Neos.ContentRepository.StructureAdjustment/src/Adjustment/TetheredNodeAdjustments.php index 99e87a2ade0..5a9b204da14 100644 --- a/Neos.ContentRepository.StructureAdjustment/src/Adjustment/TetheredNodeAdjustments.php +++ b/Neos.ContentRepository.StructureAdjustment/src/Adjustment/TetheredNodeAdjustments.php @@ -138,6 +138,7 @@ function () use ($tetheredNodeAggregate) { if ($foundMissingOrDisallowedTetheredNodes === false) { foreach ($originDimensionSpacePoints as $originDimensionSpacePoint) { $subgraph = $this->contentRepository->getContentGraph()->getSubgraph( + // todo add workspace to node aggregate $nodeAggregate->contentStreamId, $originDimensionSpacePoint->toDimensionSpacePoint(), VisibilityConstraints::withoutRestrictions() diff --git a/Neos.ContentRepositoryRegistry/Classes/Command/ContentCommandController.php b/Neos.ContentRepositoryRegistry/Classes/Command/ContentCommandController.php index 631da2ad748..75aa4466379 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Command/ContentCommandController.php +++ b/Neos.ContentRepositoryRegistry/Classes/Command/ContentCommandController.php @@ -24,6 +24,7 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindRootNodeAggregatesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; +use Neos\ContentRepository\Core\SharedModel\Exception\WorkspaceDoesNotExist; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; @@ -142,22 +143,26 @@ public function createVariantsRecursivelyCommand(string $source, string $target, $contentRepositoryId = ContentRepositoryId::fromString($contentRepository); $sourceSpacePoint = DimensionSpacePoint::fromJsonString($source); $targetSpacePoint = OriginDimensionSpacePoint::fromJsonString($target); + $workspaceName = WorkspaceName::fromString($workspace); $contentRepositoryInstance = $this->contentRepositoryRegistry->get($contentRepositoryId); - $workspaceInstance = $contentRepositoryInstance->getWorkspaceFinder()->findOneByName(WorkspaceName::fromString($workspace)); - if ($workspaceInstance === null) { - $this->outputLine('Workspace "%s" does not exist', [$workspace]); + + try { + $sourceSubgraph = $contentRepositoryInstance->getContentGraph()->getSubgraph( + $workspaceName, + $sourceSpacePoint, + VisibilityConstraints::withoutRestrictions() + ); + } catch (WorkspaceDoesNotExist $exception) { + $this->outputLine('Workspace "%s" does not exist', [$workspaceName->value]); $this->quit(1); } - $this->outputLine('Creating %s to %s in workspace %s (content repository %s)', [$sourceSpacePoint->toJson(), $targetSpacePoint->toJson(), $workspaceInstance->workspaceName->value, $contentRepositoryId->value]); - $this->outputLine('Resolved content stream %s', [$workspaceInstance->currentContentStreamId->value]); + $this->outputLine('Creating %s to %s in workspace %s (content repository %s)', [$sourceSpacePoint->toJson(), $targetSpacePoint->toJson(), $workspaceName->value, $contentRepositoryId->value]); - $sourceSubgraph = $contentRepositoryInstance->getContentGraph()->getSubgraph( - $workspaceInstance->currentContentStreamId, - $sourceSpacePoint, - VisibilityConstraints::withoutRestrictions() - ); + // todo also refactor the getContentGraph to operate on live workspaces + $workspaceInstance = $contentRepositoryInstance->getWorkspaceFinder()->findOneByName($workspaceName); + assert($workspaceInstance !== null); $rootNodeAggregates = $contentRepositoryInstance->getContentGraph() ->findRootNodeAggregates($workspaceInstance->currentContentStreamId, FindRootNodeAggregatesFilter::create()); @@ -170,7 +175,7 @@ public function createVariantsRecursivelyCommand(string $source, string $target, $rootNodeAggregate->nodeAggregateId, $sourceSubgraph, $targetSpacePoint, - $workspaceInstance->workspaceName, + $workspaceName, $contentRepositoryInstance, ) ); diff --git a/Neos.ContentRepositoryRegistry/Classes/ContentRepositoryRegistry.php b/Neos.ContentRepositoryRegistry/Classes/ContentRepositoryRegistry.php index 25daca7cf84..002fabeb4a4 100644 --- a/Neos.ContentRepositoryRegistry/Classes/ContentRepositoryRegistry.php +++ b/Neos.ContentRepositoryRegistry/Classes/ContentRepositoryRegistry.php @@ -92,10 +92,10 @@ public function resetFactoryInstance(ContentRepositoryId $contentRepositoryId): public function subgraphForNode(Node $node): ContentSubgraphInterface { - $contentRepository = $this->get($node->subgraphIdentity->contentRepositoryId); + $contentRepository = $this->get($node->identity->contentRepositoryId); return $contentRepository->getContentGraph()->getSubgraph( - $node->subgraphIdentity->contentStreamId, - $node->subgraphIdentity->dimensionSpacePoint, + $node->identity->workspaceName, + $node->identity->dimensionSpacePoint, $node->subgraphIdentity->visibilityConstraints ); } diff --git a/Neos.Neos/Classes/AssetUsage/Service/AssetUsageSyncService.php b/Neos.Neos/Classes/AssetUsage/Service/AssetUsageSyncService.php index 02a77386db9..302f67fba42 100644 --- a/Neos.Neos/Classes/AssetUsage/Service/AssetUsageSyncService.php +++ b/Neos.Neos/Classes/AssetUsage/Service/AssetUsageSyncService.php @@ -56,6 +56,7 @@ public function isAssetUsageStillValid(AssetUsage $usage): bool $dimensionSpacePoint = $usage->originDimensionSpacePoint->toDimensionSpacePoint(); $subGraph = $this->contentGraph->getSubgraph( + // todo use workspace name instead!!! $usage->contentStreamId, $dimensionSpacePoint, VisibilityConstraints::withoutRestrictions() diff --git a/Neos.Neos/Classes/Controller/Backend/ContentController.php b/Neos.Neos/Classes/Controller/Backend/ContentController.php index 707cca4d8e9..82aa24edce7 100644 --- a/Neos.Neos/Classes/Controller/Backend/ContentController.php +++ b/Neos.Neos/Classes/Controller/Backend/ContentController.php @@ -154,7 +154,7 @@ public function uploadAssetAction(Asset $asset, string $metadata, string $node, $node = $contentRepository->getContentGraph() ->getSubgraph( - $nodeAddress->contentStreamId, + $nodeAddress->workspaceName, $nodeAddress->dimensionSpacePoint, VisibilityConstraints::withoutRestrictions() ) diff --git a/Neos.Neos/Classes/Controller/Frontend/NodeController.php b/Neos.Neos/Classes/Controller/Frontend/NodeController.php index 4bc115447ee..9ff41f59170 100644 --- a/Neos.Neos/Classes/Controller/Frontend/NodeController.php +++ b/Neos.Neos/Classes/Controller/Frontend/NodeController.php @@ -133,7 +133,7 @@ public function previewAction(string $node): void $nodeAddress = NodeAddressFactory::create($contentRepository)->createFromUriString($node); $subgraph = $contentRepository->getContentGraph()->getSubgraph( - $nodeAddress->contentStreamId, + $nodeAddress->workspaceName, $nodeAddress->dimensionSpacePoint, $visibilityConstraints ); @@ -202,7 +202,7 @@ public function showAction(string $node): void } $subgraph = $contentRepository->getContentGraph()->getSubgraph( - $nodeAddress->contentStreamId, + $nodeAddress->workspaceName, $nodeAddress->dimensionSpacePoint, VisibilityConstraints::frontend() ); diff --git a/Neos.Neos/Classes/Controller/Module/Management/WorkspacesController.php b/Neos.Neos/Classes/Controller/Module/Management/WorkspacesController.php index f59105140d2..4b002debe5a 100644 --- a/Neos.Neos/Classes/Controller/Module/Management/WorkspacesController.php +++ b/Neos.Neos/Classes/Controller/Module/Management/WorkspacesController.php @@ -740,8 +740,6 @@ protected function computeSiteChanges(Workspace $selectedWorkspace, ContentRepos ); foreach ($changes as $change) { - $contentStreamId = $change->contentStreamId; - if ($change->deleted) { // If we deleted a node, there is no way for us to anymore find the deleted node in the ContentStream // where the node was deleted. @@ -749,13 +747,19 @@ protected function computeSiteChanges(Workspace $selectedWorkspace, ContentRepos // // This is safe because the UI basically shows what would be removed once the deletion is published. $baseWorkspace = $this->getBaseWorkspaceWhenSureItExists($selectedWorkspace, $contentRepository); - $contentStreamId = $baseWorkspace->currentContentStreamId; + + $subgraph = $contentRepository->getContentGraph()->getSubgraph( + $baseWorkspace->workspaceName, + $change->originDimensionSpacePoint->toDimensionSpacePoint(), + VisibilityConstraints::withoutRestrictions() + ); + } else { + $subgraph = $contentRepository->getContentGraph()->getSubgraph( + $selectedWorkspace->workspaceName, + $change->originDimensionSpacePoint->toDimensionSpacePoint(), + VisibilityConstraints::withoutRestrictions() + ); } - $subgraph = $contentRepository->getContentGraph()->getSubgraph( - $contentStreamId, - $change->originDimensionSpacePoint->toDimensionSpacePoint(), - VisibilityConstraints::withoutRestrictions() - ); $node = $subgraph->findNodeById($change->nodeAggregateId); if ($node) { @@ -862,11 +866,11 @@ protected function computeSiteChanges(Workspace $selectedWorkspace, ContentRepos */ protected function getOriginalNode( Node $modifiedNode, - ContentStreamId $baseContentStreamId, + WorkspaceName $baseWorkspaceName, ContentRepository $contentRepository, ): ?Node { $baseSubgraph = $contentRepository->getContentGraph()->getSubgraph( - $baseContentStreamId, + $baseWorkspaceName, $modifiedNode->subgraphIdentity->dimensionSpacePoint, VisibilityConstraints::withoutRestrictions() ); @@ -892,8 +896,7 @@ protected function renderContentChanges( $originalNode = null; if ($currentWorkspace !== null) { $baseWorkspace = $this->getBaseWorkspaceWhenSureItExists($currentWorkspace, $contentRepository); - $baseContentStreamId = $baseWorkspace->currentContentStreamId; - $originalNode = $this->getOriginalNode($changedNode, $baseContentStreamId, $contentRepository); + $originalNode = $this->getOriginalNode($changedNode, $baseWorkspace->workspaceName, $contentRepository); } diff --git a/Neos.Neos/Classes/Controller/Service/NodesController.php b/Neos.Neos/Classes/Controller/Service/NodesController.php index a6bc59895c4..7011a82facf 100644 --- a/Neos.Neos/Classes/Controller/Service/NodesController.php +++ b/Neos.Neos/Classes/Controller/Service/NodesController.php @@ -131,23 +131,14 @@ public function indexAction( unset($contextNode); if (is_null($nodeAddress)) { - $workspace = $contentRepository->getWorkspaceFinder()->findOneByName( - WorkspaceName::fromString($workspaceName) - ); - if (is_null($workspace)) { - throw new \InvalidArgumentException( - 'Could not resolve a node address for the given parameters.', - 1645631728 - ); - } $subgraph = $contentRepository->getContentGraph()->getSubgraph( - $workspace->currentContentStreamId, + WorkspaceName::fromString($workspaceName), DimensionSpacePoint::fromLegacyDimensionArray($dimensions), VisibilityConstraints::withoutRestrictions() // we are in a backend controller. ); } else { $subgraph = $contentRepository->getContentGraph()->getSubgraph( - $nodeAddress->contentStreamId, + $nodeAddress->workspaceName, $nodeAddress->dimensionSpacePoint, VisibilityConstraints::withoutRestrictions() // we are in a backend controller. ); @@ -206,14 +197,12 @@ public function showAction(string $identifier, string $workspaceName = 'live', a ->contentRepositoryId; $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); - $workspace = $contentRepository->getWorkspaceFinder() - ->findOneByName(WorkspaceName::fromString($workspaceName)); - assert($workspace instanceof Workspace); + $workspaceName = WorkspaceName::fromString($workspaceName); $dimensionSpacePoint = DimensionSpacePoint::fromLegacyDimensionArray($dimensions); $subgraph = $contentRepository->getContentGraph() ->getSubgraph( - $workspace->currentContentStreamId, + $workspaceName, $dimensionSpacePoint, VisibilityConstraints::withoutRestrictions() ); @@ -223,7 +212,7 @@ public function showAction(string $identifier, string $workspaceName = 'live', a if ($node === null) { $this->addExistingNodeVariantInformationToResponse( $nodeAggregateId, - $workspace->currentContentStreamId, + $workspaceName, $dimensionSpacePoint, $contentRepository ); @@ -275,13 +264,11 @@ public function createAction( ->contentRepositoryId; $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); - $workspace = $contentRepository->getWorkspaceFinder() - ->findOneByName(WorkspaceName::fromString($workspaceName)); - assert($workspace instanceof Workspace); + $workspaceName = WorkspaceName::fromString($workspaceName); $sourceSubgraph = $contentRepository->getContentGraph() ->getSubgraph( - $workspace->currentContentStreamId, + $workspaceName, DimensionSpacePoint::fromLegacyDimensionArray($sourceDimensions), VisibilityConstraints::withoutRestrictions() ); @@ -289,7 +276,7 @@ public function createAction( $targetDimensionSpacePoint = DimensionSpacePoint::fromLegacyDimensionArray($dimensions); $targetSubgraph = $contentRepository->getContentGraph() ->getSubgraph( - $workspace->currentContentStreamId, + $workspaceName, $targetDimensionSpacePoint, VisibilityConstraints::withoutRestrictions() ); @@ -297,7 +284,7 @@ public function createAction( if ($mode === 'adoptFromAnotherDimension' || $mode === 'adoptFromAnotherDimensionAndCopyContent') { CatchUpTriggerWithSynchronousOption::synchronously(fn() => $this->adoptNodeAndParents( - $workspace->workspaceName, + $workspaceName, $nodeAggregateId, $sourceSubgraph, $targetSubgraph, @@ -308,7 +295,7 @@ public function createAction( $this->redirect('show', null, null, [ 'identifier' => $nodeAggregateId->value, - 'workspaceName' => $workspaceName, + 'workspaceName' => $workspaceName->value, 'dimensions' => $dimensions ]); } else { @@ -322,10 +309,15 @@ public function createAction( */ protected function addExistingNodeVariantInformationToResponse( NodeAggregateId $identifier, - ContentStreamId $contentStreamId, + WorkspaceName $workspaceName, DimensionSpacePoint $dimensionSpacePoint, ContentRepository $contentRepository ): void { + // todo also refactor the getContentGraph to operate on live workspaces + $workspace = $contentRepository->getWorkspaceFinder()->findOneByName($workspaceName); + assert($workspace !== null); + $contentStreamId = $workspace->currentContentStreamId; + $contentGraph = $contentRepository->getContentGraph(); $nodeTypeManager = $contentRepository->getNodeTypeManager(); $nodeAggregate = $contentGraph->findNodeAggregateById($contentStreamId, $identifier); diff --git a/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php b/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php index a9b503611e5..997d4f7896c 100644 --- a/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php +++ b/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php @@ -18,7 +18,7 @@ use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; -use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Annotations as Flow; use Neos\Neos\Domain\Model\Site; @@ -41,13 +41,9 @@ public function __construct( * To find the site node for the live workspace in a 0 dimensional content repository use: * * ```php - * $contentRepository = $this->contentRepositoryRegistry->get($site->getConfiguration()->contentRepositoryId); - * $liveWorkspace = $contentRepository->getWorkspaceFinder()->findOneByName(WorkspaceName::forLive()) - * ?? throw new \RuntimeException('Expected live workspace to exist.'); - * * $siteNode = $this->siteNodeUtility->findSiteNodeBySite( * $site, - * $liveWorkspace->currentContentStreamId, + * WorkspaceName::forLive(), * DimensionSpacePoint::createWithoutDimensions(), * VisibilityConstraints::frontend() * ); @@ -57,20 +53,24 @@ public function __construct( */ public function findSiteNodeBySite( Site $site, - ContentStreamId $contentStreamId, + WorkspaceName $workspaceName, DimensionSpacePoint $dimensionSpacePoint, VisibilityConstraints $visibilityConstraints ): Node { $contentRepository = $this->contentRepositoryRegistry->get($site->getConfiguration()->contentRepositoryId); $subgraph = $contentRepository->getContentGraph()->getSubgraph( - $contentStreamId, + $workspaceName, $dimensionSpacePoint, $visibilityConstraints, ); + // todo also refactor the getContentGraph to operate on live workspaces + $workspace = $contentRepository->getWorkspaceFinder()->findOneByName($workspaceName); + assert($workspace !== null); + $rootNodeAggregate = $contentRepository->getContentGraph()->findRootNodeAggregateByType( - $contentStreamId, + $workspace->currentContentStreamId, NodeTypeNameFactory::forSites() ); $rootNode = $rootNodeAggregate->getNodeByCoveredDimensionSpacePoint($dimensionSpacePoint); diff --git a/Neos.Neos/Classes/Fusion/Cache/NeosFusionContextSerializer.php b/Neos.Neos/Classes/Fusion/Cache/NeosFusionContextSerializer.php index 0e50845b659..ed2df161600 100644 --- a/Neos.Neos/Classes/Fusion/Cache/NeosFusionContextSerializer.php +++ b/Neos.Neos/Classes/Fusion/Cache/NeosFusionContextSerializer.php @@ -8,6 +8,7 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; +use Neos\ContentRepository\Core\SharedModel\Exception\WorkspaceDoesNotExist; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; @@ -75,22 +76,21 @@ private function tryDeserializeNode(array $serializedNode): ?Node $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); - $workspace = $contentRepository->getWorkspaceFinder()->findOneByName(WorkspaceName::fromString($serializedNode['workspaceName'])); - if (!$workspace) { + try { + $subgraph = $contentRepository->getContentGraph()->getSubgraph( + $workspaceName = WorkspaceName::fromString($serializedNode['workspaceName']), + DimensionSpacePoint::fromArray($serializedNode['dimensionSpacePoint']), + $workspaceName->isLive() + ? VisibilityConstraints::frontend() + : VisibilityConstraints::withoutRestrictions() + ); + } catch (WorkspaceDoesNotExist $exception) { // in case the workspace was deleted the rendering should probably not come to this very point // still if it does we fail silently // this is also the behaviour for when the property mapper is used return null; } - $subgraph = $contentRepository->getContentGraph()->getSubgraph( - $workspace->currentContentStreamId, - DimensionSpacePoint::fromArray($serializedNode['dimensionSpacePoint']), - $workspace->isPublicWorkspace() - ? VisibilityConstraints::frontend() - : VisibilityConstraints::withoutRestrictions() - ); - $node = $subgraph->findNodeById(NodeAggregateId::fromString($serializedNode['nodeAggregateId'])); if (!$node) { // instead of crashing the whole rendering, by silently returning null we will most likely just break diff --git a/Neos.Neos/Classes/Fusion/DimensionsMenuItemsImplementation.php b/Neos.Neos/Classes/Fusion/DimensionsMenuItemsImplementation.php index 5f2e128a252..54a204eb006 100644 --- a/Neos.Neos/Classes/Fusion/DimensionsMenuItemsImplementation.php +++ b/Neos.Neos/Classes/Fusion/DimensionsMenuItemsImplementation.php @@ -66,7 +66,7 @@ protected function buildItems(): array } else { $variant = $contentRepository->getContentGraph() ->getSubgraph( - $currentNode->subgraphIdentity->contentStreamId, + $currentNode->identity->workspaceName, $dimensionSpacePoint, $currentNode->subgraphIdentity->visibilityConstraints, ) @@ -159,7 +159,7 @@ protected function findClosestGeneralizationMatchingDimensionValue( ) { $variant = $contentRepository->getContentGraph() ->getSubgraph( - $this->currentNode->subgraphIdentity->contentStreamId, + $this->currentNode->identity->workspaceName, $generalization, $this->currentNode->subgraphIdentity->visibilityConstraints, ) diff --git a/Neos.Neos/Classes/Fusion/Helper/DimensionHelper.php b/Neos.Neos/Classes/Fusion/Helper/DimensionHelper.php index 15bafd94ac1..55ba6206212 100644 --- a/Neos.Neos/Classes/Fusion/Helper/DimensionHelper.php +++ b/Neos.Neos/Classes/Fusion/Helper/DimensionHelper.php @@ -142,13 +142,13 @@ public function findVariantInDimension(Node $node, ContentDimensionId|string $di { $contentDimensionId = is_string($dimensionName) ? new ContentDimensionId($dimensionName) : $dimensionName; $contentDimensionValue = is_string($dimensionValue) ? new ContentDimensionValue($dimensionValue) : $dimensionValue; - $contentRepository = $this->contentRepositoryRegistry->get($node->subgraphIdentity->contentRepositoryId); + $contentRepository = $this->contentRepositoryRegistry->get($node->identity->contentRepositoryId); return $contentRepository ->getContentGraph() ->getSubgraph( - $node->subgraphIdentity->contentStreamId, - $node->subgraphIdentity->dimensionSpacePoint->vary($contentDimensionId, $contentDimensionValue->value), + $node->identity->workspaceName, + $node->identity->dimensionSpacePoint->vary($contentDimensionId, $contentDimensionValue->value), $node->subgraphIdentity->visibilityConstraints )->findNodeById($node->nodeAggregateId); } diff --git a/Neos.Neos/Classes/Service/LinkingService.php b/Neos.Neos/Classes/Service/LinkingService.php index 445c1e62b63..53d2934f00e 100644 --- a/Neos.Neos/Classes/Service/LinkingService.php +++ b/Neos.Neos/Classes/Service/LinkingService.php @@ -315,7 +315,7 @@ public function createNodeUri( $nodeAddress = NodeAddressFactory::create($contentRepository)->createFromUriString($node); $workspace = $contentRepository->getWorkspaceFinder()->findOneByName($nodeAddress->workspaceName); $subgraph = $contentRepository->getContentGraph()->getSubgraph( - $nodeAddress->contentStreamId, + $nodeAddress->workspaceName, $nodeAddress->dimensionSpacePoint, $workspace && !$workspace->isPublicWorkspace() ? VisibilityConstraints::withoutRestrictions() diff --git a/Neos.Neos/Classes/TypeConverter/HackyNodeAddressToNodeConverter.php b/Neos.Neos/Classes/TypeConverter/HackyNodeAddressToNodeConverter.php index 50069aed402..37e7cb2f341 100644 --- a/Neos.Neos/Classes/TypeConverter/HackyNodeAddressToNodeConverter.php +++ b/Neos.Neos/Classes/TypeConverter/HackyNodeAddressToNodeConverter.php @@ -82,7 +82,7 @@ public function convertFrom( $subgraph = $contentRepository->getContentGraph() ->getSubgraph( - $nodeAddress->contentStreamId, + $nodeAddress->workspaceName, $nodeAddress->dimensionSpacePoint, $nodeAddress->isInLiveWorkspace() ? VisibilityConstraints::frontend() diff --git a/Neos.Neos/Classes/View/FusionExceptionView.php b/Neos.Neos/Classes/View/FusionExceptionView.php index bf4807b0e65..6557fae955a 100644 --- a/Neos.Neos/Classes/View/FusionExceptionView.php +++ b/Neos.Neos/Classes/View/FusionExceptionView.php @@ -16,6 +16,7 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; +use Neos\ContentRepository\Core\SharedModel\Exception\WorkspaceDoesNotExist; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Annotations as Flow; @@ -114,27 +115,26 @@ public function render() return $this->renderErrorWelcomeScreen(); } - $contentRepository = $this->contentRepositoryRegistry->get($siteDetectionResult->contentRepositoryId); $fusionExceptionViewInternals = $this->contentRepositoryRegistry->buildService( $siteDetectionResult->contentRepositoryId, new FusionExceptionViewInternalsFactory() ); $dimensionSpacePoint = $fusionExceptionViewInternals->getArbitraryDimensionSpacePoint(); - $liveWorkspace = $contentRepository->getWorkspaceFinder()->findOneByName(WorkspaceName::forLive()); - - $currentSiteNode = null; $site = $this->siteRepository->findOneByNodeName($siteDetectionResult->siteNodeName); - if ($liveWorkspace && $site) { + + if (!$site) { + return $this->renderErrorWelcomeScreen(); + } + + try { $currentSiteNode = $this->siteNodeUtility->findSiteNodeBySite( $site, - $liveWorkspace->currentContentStreamId, + WorkspaceName::forLive(), $dimensionSpacePoint, VisibilityConstraints::frontend() ); - } - - if (!$currentSiteNode) { + } catch (WorkspaceDoesNotExist|\RuntimeException $exception) { return $this->renderErrorWelcomeScreen(); } diff --git a/Neos.Neos/Classes/ViewHelpers/Link/NodeViewHelper.php b/Neos.Neos/Classes/ViewHelpers/Link/NodeViewHelper.php index f75ef066aa9..037d9858612 100644 --- a/Neos.Neos/Classes/ViewHelpers/Link/NodeViewHelper.php +++ b/Neos.Neos/Classes/ViewHelpers/Link/NodeViewHelper.php @@ -279,7 +279,7 @@ public function render(): string $subgraph = $contentRepository->getContentGraph() ->getSubgraph( - $nodeAddress->contentStreamId, + $nodeAddress->workspaceName, $nodeAddress->dimensionSpacePoint, $node->subgraphIdentity->visibilityConstraints ); @@ -371,7 +371,7 @@ private function resolveNodeAddressFromString( ); } $subgraph = $contentRepository->getContentGraph()->getSubgraph( - $documentNodeAddress->contentStreamId, + $documentNodeAddress->workspaceName, $documentNodeAddress->dimensionSpacePoint, VisibilityConstraints::withoutRestrictions() ); diff --git a/Neos.Neos/Classes/ViewHelpers/Uri/NodeViewHelper.php b/Neos.Neos/Classes/ViewHelpers/Uri/NodeViewHelper.php index 67438d4afb5..3b1a082f256 100644 --- a/Neos.Neos/Classes/ViewHelpers/Uri/NodeViewHelper.php +++ b/Neos.Neos/Classes/ViewHelpers/Uri/NodeViewHelper.php @@ -274,7 +274,7 @@ private function resolveNodeAddressFromString(string $path): ?NodeAddress ); } $subgraph = $contentRepository->getContentGraph()->getSubgraph( - $documentNodeAddress->contentStreamId, + $documentNodeAddress->workspaceName, $documentNodeAddress->dimensionSpacePoint, VisibilityConstraints::withoutRestrictions() ); diff --git a/Neos.TimeableNodeVisibility/Classes/Service/TimeableNodeVisibilityService.php b/Neos.TimeableNodeVisibility/Classes/Service/TimeableNodeVisibilityService.php index 07bb0429ab9..78071ee704e 100644 --- a/Neos.TimeableNodeVisibility/Classes/Service/TimeableNodeVisibilityService.php +++ b/Neos.TimeableNodeVisibility/Classes/Service/TimeableNodeVisibilityService.php @@ -42,14 +42,9 @@ class TimeableNodeVisibilityService public function handleExceededNodeDates(ContentRepositoryId $contentRepositoryId, WorkspaceName $workspaceName): ChangedVisibilities { $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); - $liveWorkspace = $contentRepository->getWorkspaceFinder()->findOneByName($workspaceName); - if ($liveWorkspace === null) { - throw WorkspaceDoesNotExist::butWasSupposedTo($workspaceName); - } - $now = new \DateTimeImmutable(); - $nodes = $this->getNodesWithExceededDates($contentRepository, $liveWorkspace, $now); + $nodes = $this->getNodesWithExceededDates($contentRepository, $workspaceName, $now); $results = []; /** @var Node $node */ @@ -58,7 +53,7 @@ public function handleExceededNodeDates(ContentRepositoryId $contentRepositoryId if ($this->needsEnabling($node, $now) && $nodeIsDisabled) { $contentRepository->handle( EnableNodeAggregate::create( - $liveWorkspace->workspaceName, + $workspaceName, $node->nodeAggregateId, $node->subgraphIdentity->dimensionSpacePoint, NodeVariantSelectionStrategy::STRATEGY_ALL_SPECIALIZATIONS @@ -72,7 +67,7 @@ public function handleExceededNodeDates(ContentRepositoryId $contentRepositoryId if ($this->needsDisabling($node, $now) && !$nodeIsDisabled) { $contentRepository->handle( DisableNodeAggregate::create( - $liveWorkspace->workspaceName, + $workspaceName, $node->nodeAggregateId, $node->subgraphIdentity->dimensionSpacePoint, NodeVariantSelectionStrategy::STRATEGY_ALL_SPECIALIZATIONS @@ -89,7 +84,7 @@ public function handleExceededNodeDates(ContentRepositoryId $contentRepositoryId /** * @return \Generator */ - private function getNodesWithExceededDates(ContentRepository $contentRepository, Workspace $liveWorkspace, \DateTimeImmutable $now): \Generator + private function getNodesWithExceededDates(ContentRepository $contentRepository, WorkspaceName $workspaceName, \DateTimeImmutable $now): \Generator { $dimensionSpacePoints = $contentRepository->getVariationGraph()->getDimensionSpacePoints(); @@ -99,7 +94,7 @@ private function getNodesWithExceededDates(ContentRepository $contentRepository, // We fetch without restriction to get also all disabled nodes $subgraph = $contentGraph->getSubgraph( - $liveWorkspace->currentContentStreamId, + $workspaceName, $dimensionSpacePoint, VisibilityConstraints::withoutRestrictions() ); From e37a4b893ac87d9c781babd8501299626c276599 Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Tue, 19 Mar 2024 23:13:20 +0100 Subject: [PATCH 6/6] TASK: Adjust to `WorkspaceName` in `getSubgraph` (more complex usages) --- .../DimensionSpaceCommandHandler.php | 12 ++++++---- .../Classes/Feature/NodeMove/NodeMove.php | 22 ++++++++++--------- .../DisallowedChildNodeAdjustment.php | 3 ++- .../Adjustment/TetheredNodeAdjustments.php | 6 ++--- .../Bootstrap/CRTestSuiteRuntimeVariables.php | 2 +- 5 files changed, 26 insertions(+), 19 deletions(-) diff --git a/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/DimensionSpaceCommandHandler.php b/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/DimensionSpaceCommandHandler.php index 74bbd380c4d..974aff40a41 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/DimensionSpaceCommandHandler.php +++ b/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/DimensionSpaceCommandHandler.php @@ -71,6 +71,8 @@ private function handleMoveDimensionSpacePoint( $streamName = ContentStreamEventStreamName::fromContentStreamId($command->contentStreamId) ->getEventStreamName(); + // todo use WorkspaceName here as well but the command doesnt expose it + // https://github.com/neos/neos-development-collection/issues/4942 self::requireDimensionSpacePointToBeEmptyInContentStream( $command->target, $command->contentStreamId, @@ -99,6 +101,8 @@ private function handleAddDimensionShineThrough( $streamName = ContentStreamEventStreamName::fromContentStreamId($command->contentStreamId) ->getEventStreamName(); + // todo use WorkspaceName here as well but the command doesnt expose it + // https://github.com/neos/neos-development-collection/issues/4942 self::requireDimensionSpacePointToBeEmptyInContentStream( $command->target, $command->contentStreamId, @@ -134,18 +138,18 @@ protected function requireDimensionSpacePointToExistInConfiguration(DimensionSpa private static function requireDimensionSpacePointToBeEmptyInContentStream( DimensionSpacePoint $dimensionSpacePoint, - ContentStreamId $contentStreamId, + WorkspaceName $workspaceName, ContentGraphInterface $contentGraph ): void { $subgraph = $contentGraph->getSubgraph( - $contentStreamId, + $workspaceName, $dimensionSpacePoint, VisibilityConstraints::withoutRestrictions() ); if ($subgraph->countNodes() > 0) { throw new DimensionSpacePointAlreadyExists(sprintf( - 'the content stream %s already contained nodes in dimension space point %s - this is not allowed.', - $contentStreamId->value, + 'the workspace %s already contained nodes in dimension space point %s - this is not allowed.', + $workspaceName->value, $dimensionSpacePoint->toJson(), ), 1612898126); } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php index 9290dfdb872..4135828d02d 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php @@ -46,6 +46,7 @@ use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregatesTypeIsAmbiguous; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * @internal implementation detail of Command Handlers @@ -149,7 +150,8 @@ private function handleMoveNodeAggregate( $originNodeMoveMappings[] = new OriginNodeMoveMapping( $movedNodeOrigin, $this->resolveCoverageNodeMoveMappings( - $contentStreamId, + // todo UNSAFE as override via ContentStreamIdOverride will NOT be taken into account!!! + $command->workspaceName, $nodeAggregate, $command->newParentNodeAggregateId, $command->newPrecedingSiblingNodeAggregateId, @@ -188,18 +190,18 @@ private function handleMoveNodeAggregate( * * If no parent node aggregate is defined, it will be resolved from the already evaluated new succeeding siblings. * - * @todo move to content graph for more efficient calculation, if possible + * @todo move to content graph for more efficient calculation, if possible !!! */ private function resolveNewParentAssignments( - /** The content stream the move operation is performed in */ - ContentStreamId $contentStreamId, + /** The workspace the move operation is performed in */ + WorkspaceName $workspaceName, /** The parent node aggregate's id*/ NodeAggregateId $parentId, DimensionSpace\DimensionSpacePoint $coveredDimensionSpacePoint, ContentRepository $contentRepository ): CoverageNodeMoveMapping { $contentSubgraph = $contentRepository->getContentGraph()->getSubgraph( - $contentStreamId, + $workspaceName, $coveredDimensionSpacePoint, VisibilityConstraints::withoutRestrictions() ); @@ -328,8 +330,8 @@ private function resolveSucceedingSiblingFromOriginSiblings( } private function resolveCoverageNodeMoveMappings( - /** The content stream the move operation is performed in */ - ContentStreamId $contentStreamId, + /** The workspace the move operation is performed in */ + WorkspaceName $workspaceName, /** The node aggregate to be moved */ NodeAggregate $nodeAggregate, /** The parent node aggregate id, has precedence over siblings when in doubt */ @@ -349,7 +351,7 @@ private function resolveCoverageNodeMoveMappings( $visibilityConstraints = VisibilityConstraints::withoutRestrictions(); $originContentSubgraph = $contentRepository->getContentGraph()->getSubgraph( - $contentStreamId, + $workspaceName, $originDimensionSpacePoint->toDimensionSpacePoint(), $visibilityConstraints ); @@ -358,7 +360,7 @@ private function resolveCoverageNodeMoveMappings( ->getIntersection($affectedDimensionSpacePoints) as $dimensionSpacePoint ) { $contentSubgraph = $contentRepository->getContentGraph()->getSubgraph( - $contentStreamId, + $workspaceName, $dimensionSpacePoint, $visibilityConstraints ); @@ -426,7 +428,7 @@ private function resolveCoverageNodeMoveMappings( } } $coverageNodeMoveMappings[] = $this->resolveNewParentAssignments( - $contentStreamId, + $workspaceName, $parentId, $dimensionSpacePoint, $contentRepository diff --git a/Neos.ContentRepository.StructureAdjustment/src/Adjustment/DisallowedChildNodeAdjustment.php b/Neos.ContentRepository.StructureAdjustment/src/Adjustment/DisallowedChildNodeAdjustment.php index 1111146fc21..4f116fa87be 100644 --- a/Neos.ContentRepository.StructureAdjustment/src/Adjustment/DisallowedChildNodeAdjustment.php +++ b/Neos.ContentRepository.StructureAdjustment/src/Adjustment/DisallowedChildNodeAdjustment.php @@ -17,6 +17,7 @@ use Neos\ContentRepository\Core\NodeType\NodeTypeName; use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\EventStore\Model\EventStream\ExpectedVersion; class DisallowedChildNodeAdjustment @@ -52,7 +53,7 @@ public function findAdjustmentsForNodeType(NodeTypeName $nodeTypeName): \Generat // Then, we only want to remove the single edge. foreach ($nodeAggregate->coveredDimensionSpacePoints as $coveredDimensionSpacePoint) { $subgraph = $this->contentRepository->getContentGraph()->getSubgraph( - $nodeAggregate->contentStreamId, + WorkspaceName::forLive(), // structure adjustments are only carried out live $coveredDimensionSpacePoint, VisibilityConstraints::withoutRestrictions() ); diff --git a/Neos.ContentRepository.StructureAdjustment/src/Adjustment/TetheredNodeAdjustments.php b/Neos.ContentRepository.StructureAdjustment/src/Adjustment/TetheredNodeAdjustments.php index 5a9b204da14..b0dc59e4967 100644 --- a/Neos.ContentRepository.StructureAdjustment/src/Adjustment/TetheredNodeAdjustments.php +++ b/Neos.ContentRepository.StructureAdjustment/src/Adjustment/TetheredNodeAdjustments.php @@ -27,6 +27,7 @@ use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\EventStore\Model\EventStream\ExpectedVersion; class TetheredNodeAdjustments @@ -70,7 +71,7 @@ public function findAdjustmentsForNodeType(NodeTypeName $nodeTypeName): \Generat $tetheredNodeName = NodeName::fromString($tetheredNodeName); $subgraph = $this->contentRepository->getContentGraph()->getSubgraph( - $nodeAggregate->contentStreamId, + WorkspaceName::forLive(), // structure adjustments are only carried out live $originDimensionSpacePoint->toDimensionSpacePoint(), VisibilityConstraints::withoutRestrictions() ); @@ -138,8 +139,7 @@ function () use ($tetheredNodeAggregate) { if ($foundMissingOrDisallowedTetheredNodes === false) { foreach ($originDimensionSpacePoints as $originDimensionSpacePoint) { $subgraph = $this->contentRepository->getContentGraph()->getSubgraph( - // todo add workspace to node aggregate - $nodeAggregate->contentStreamId, + WorkspaceName::forLive(), // structure adjustments are only carried out live $originDimensionSpacePoint->toDimensionSpacePoint(), VisibilityConstraints::withoutRestrictions() ); diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteRuntimeVariables.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteRuntimeVariables.php index a19eb219002..9e3ee2a7c10 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteRuntimeVariables.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteRuntimeVariables.php @@ -161,7 +161,7 @@ public function visibilityConstraintsAreSetTo(string $restrictionType): void public function getCurrentSubgraph(): ContentSubgraphInterface { return $this->currentContentRepository->getContentGraph()->getSubgraph( - $this->currentContentStreamId, + $this->currentWorkspaceName, $this->currentDimensionSpacePoint, $this->currentVisibilityConstraints );