From 087e96490f39467c647defbe8832e5c1c0bb1135 Mon Sep 17 00:00:00 2001
From: mhsdesign <85400359+mhsdesign@users.noreply.github.com>
Date: Tue, 26 Sep 2023 23:37:33 +0200
Subject: [PATCH 01/15] FEATURE: `Neos.Neos:Site` NodeType
---
Neos.Neos/Configuration/NodeTypes.Sites.yaml | 3 ---
Neos.Neos/NodeTypes/Mixin/Document.yaml | 2 ++
Neos.Neos/NodeTypes/Mixin/Site.yaml | 10 ++++++++++
Neos.Neos/NodeTypes/Mixin/Sites.yaml | 11 +++++++++++
4 files changed, 23 insertions(+), 3 deletions(-)
delete mode 100644 Neos.Neos/Configuration/NodeTypes.Sites.yaml
create mode 100644 Neos.Neos/NodeTypes/Mixin/Site.yaml
create mode 100644 Neos.Neos/NodeTypes/Mixin/Sites.yaml
diff --git a/Neos.Neos/Configuration/NodeTypes.Sites.yaml b/Neos.Neos/Configuration/NodeTypes.Sites.yaml
deleted file mode 100644
index fa2556e5904..00000000000
--- a/Neos.Neos/Configuration/NodeTypes.Sites.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
-'Neos.Neos:Sites':
- superTypes:
- 'Neos.ContentRepository:Root': true
diff --git a/Neos.Neos/NodeTypes/Mixin/Document.yaml b/Neos.Neos/NodeTypes/Mixin/Document.yaml
index 41d37e48cea..f00b1f0dd85 100644
--- a/Neos.Neos/NodeTypes/Mixin/Document.yaml
+++ b/Neos.Neos/NodeTypes/Mixin/Document.yaml
@@ -11,6 +11,8 @@
constraints:
nodeTypes:
'*': false
+ # explicitly disallow to create a homepage below a regular document
+ 'Neos.Neos:Site': false
'Neos.Neos:Document': true
postprocessors:
'CreationDialogPostprocessor':
diff --git a/Neos.Neos/NodeTypes/Mixin/Site.yaml b/Neos.Neos/NodeTypes/Mixin/Site.yaml
new file mode 100644
index 00000000000..c2d38ef77a3
--- /dev/null
+++ b/Neos.Neos/NodeTypes/Mixin/Site.yaml
@@ -0,0 +1,10 @@
+#
+# Abstract NodeType for a Neos.Neos site.
+# Each homepage must extend this NodeType.
+# Nodes of this type must be direct children of the Neos.Neos:Site Root
+# and must not be created at any other place in the tree.
+#
+'Neos.Neos:Site':
+ abstract: true
+ superTypes:
+ 'Neos.Neos:Document': true
diff --git a/Neos.Neos/NodeTypes/Mixin/Sites.yaml b/Neos.Neos/NodeTypes/Mixin/Sites.yaml
new file mode 100644
index 00000000000..229957b03dd
--- /dev/null
+++ b/Neos.Neos/NodeTypes/Mixin/Sites.yaml
@@ -0,0 +1,11 @@
+#
+# Root NodeType for a Neos.Neos content repository.
+# Any Neos Site node must be its direct child.
+#
+'Neos.Neos:Sites':
+ superTypes:
+ 'Neos.ContentRepository:Root': true
+ constraints:
+ nodeTypes:
+ '*': false
+ 'Neos.Neos:Site': true
From 144ad066dbe6555da5fe5b139cd991cb77082399 Mon Sep 17 00:00:00 2001
From: mhsdesign <85400359+mhsdesign@users.noreply.github.com>
Date: Wed, 27 Sep 2023 09:33:15 +0200
Subject: [PATCH 02/15] TASK: Remove unused exceptions
---
.../Domain/Exception/CurrentUserIsMissing.php | 29 ------------------
.../Exception/LiveWorkspaceIsMissing.php | 29 ------------------
.../Domain/Exception/SitesNodeIsMissing.php | 30 -------------------
.../Domain/Service/SiteServiceInternals.php | 24 +++++----------
4 files changed, 7 insertions(+), 105 deletions(-)
delete mode 100644 Neos.Neos/Classes/Domain/Exception/CurrentUserIsMissing.php
delete mode 100644 Neos.Neos/Classes/Domain/Exception/LiveWorkspaceIsMissing.php
delete mode 100644 Neos.Neos/Classes/Domain/Exception/SitesNodeIsMissing.php
diff --git a/Neos.Neos/Classes/Domain/Exception/CurrentUserIsMissing.php b/Neos.Neos/Classes/Domain/Exception/CurrentUserIsMissing.php
deleted file mode 100644
index 17ee064d9c3..00000000000
--- a/Neos.Neos/Classes/Domain/Exception/CurrentUserIsMissing.php
+++ /dev/null
@@ -1,29 +0,0 @@
-value . '" root node is missing.',
- 1651956364
- );
- }
-}
diff --git a/Neos.Neos/Classes/Domain/Service/SiteServiceInternals.php b/Neos.Neos/Classes/Domain/Service/SiteServiceInternals.php
index 5e9ce9ce471..e09e3465c32 100644
--- a/Neos.Neos/Classes/Domain/Service/SiteServiceInternals.php
+++ b/Neos.Neos/Classes/Domain/Service/SiteServiceInternals.php
@@ -15,32 +15,22 @@
namespace Neos\Neos\Domain\Service;
use Neos\ContentRepository\Core\ContentRepository;
-use Neos\ContentRepository\Core\DimensionSpace\ContentDimensionZookeeper;
use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint;
use Neos\ContentRepository\Core\DimensionSpace\InterDimensionalVariationGraph;
+use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint;
use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceInterface;
-use Neos\ContentRepository\Core\SharedModel\Exception\NodeTypeNotFoundException;
-use Neos\ContentRepository\Core\SharedModel\Node\NodeVariantSelectionStrategy;
-use Neos\ContentRepository\Core\Feature\NodeModification\Dto\PropertyValuesToWrite;
use Neos\ContentRepository\Core\Feature\NodeCreation\Command\CreateNodeAggregateWithNode;
+use Neos\ContentRepository\Core\Feature\NodeModification\Dto\PropertyValuesToWrite;
use Neos\ContentRepository\Core\Feature\NodeRemoval\Command\RemoveNodeAggregate;
use Neos\ContentRepository\Core\Feature\NodeVariation\Command\CreateNodeVariant;
-use Neos\ContentRepository\Core\Feature\RootNodeCreation\Command\CreateRootNodeAggregateWithNode;
-use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Command\CreateRootWorkspace;
+use Neos\ContentRepository\Core\NodeType\NodeTypeManager;
+use Neos\ContentRepository\Core\NodeType\NodeTypeName;
use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate;
-use Neos\ContentRepository\Core\Projection\Workspace\Workspace;
use Neos\ContentRepository\Core\Service\ContentRepositoryBootstrapper;
+use Neos\ContentRepository\Core\SharedModel\Exception\NodeTypeNotFoundException;
use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId;
-use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint;
-use Neos\ContentRepository\Core\NodeType\NodeTypeManager;
-use Neos\ContentRepository\Core\NodeType\NodeTypeName;
-use Neos\ContentRepository\Core\SharedModel\User\UserId;
-use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId;
-use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceDescription;
-use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName;
-use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceTitle;
-use Neos\Neos\Domain\Exception\LiveWorkspaceIsMissing;
-use Neos\Neos\Domain\Exception\SitesNodeIsMissing;
+use Neos\ContentRepository\Core\SharedModel\Node\NodeVariantSelectionStrategy;
+use Neos\Neos\Domain\Exception\SiteNodeTypeIsInvalid;
use Neos\Neos\Domain\Model\Site;
use Neos\Neos\Domain\Model\SiteNodeName;
From a27a7339b165e71bac03bd70f1e60e02cc0be283 Mon Sep 17 00:00:00 2001
From: mhsdesign <85400359+mhsdesign@users.noreply.github.com>
Date: Wed, 27 Sep 2023 09:34:50 +0200
Subject: [PATCH 03/15] TASK: Assert in `site:create` that homepage node must
be of type `Neos.Neos:Site`
---
Neos.Neos/Classes/Domain/Exception/SiteNodeTypeIsInvalid.php | 2 +-
Neos.Neos/Classes/Domain/Service/SiteServiceInternals.php | 5 +++++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/Neos.Neos/Classes/Domain/Exception/SiteNodeTypeIsInvalid.php b/Neos.Neos/Classes/Domain/Exception/SiteNodeTypeIsInvalid.php
index ed29ca17d87..c38806a3233 100644
--- a/Neos.Neos/Classes/Domain/Exception/SiteNodeTypeIsInvalid.php
+++ b/Neos.Neos/Classes/Domain/Exception/SiteNodeTypeIsInvalid.php
@@ -25,7 +25,7 @@ public static function becauseItIsNotOfTypeSite(NodeTypeName $attemptedNodeTypeN
{
return new self(
'Node type name "' . $attemptedNodeTypeName->value
- . '" is not of required type "' . NodeTypeNameFactory::forSite()->value . '"',
+ . '" is not of required type "' . NodeTypeNameFactory::NAME_SITE . '"',
1412372375
);
}
diff --git a/Neos.Neos/Classes/Domain/Service/SiteServiceInternals.php b/Neos.Neos/Classes/Domain/Service/SiteServiceInternals.php
index e09e3465c32..3c84afc9010 100644
--- a/Neos.Neos/Classes/Domain/Service/SiteServiceInternals.php
+++ b/Neos.Neos/Classes/Domain/Service/SiteServiceInternals.php
@@ -95,6 +95,11 @@ public function createSiteNodeIfNotExists(Site $site, string $nodeTypeName): voi
1412372375
);
}
+
+ if (!$siteNodeType->isOfType(NodeTypeNameFactory::NAME_SITE)) {
+ throw SiteNodeTypeIsInvalid::becauseItIsNotOfTypeSite(NodeTypeName::fromString($nodeTypeName));
+ }
+
$siteNodeAggregate = $this->contentRepository->getContentGraph()->findChildNodeAggregatesByName(
$liveContentStreamId,
$sitesNodeIdentifier,
From 0fc62752b31f9003c466558a99f759b9a84b1e5a Mon Sep 17 00:00:00 2001
From: mhsdesign <85400359+mhsdesign@users.noreply.github.com>
Date: Wed, 27 Sep 2023 09:35:34 +0200
Subject: [PATCH 04/15] TASK: Correctly stringify NodeTypeName
---
Neos.Neos/Classes/Command/SiteCommandController.php | 2 +-
.../Controller/Module/Administration/SitesController.php | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/Neos.Neos/Classes/Command/SiteCommandController.php b/Neos.Neos/Classes/Command/SiteCommandController.php
index 5de738b7e24..14354cd743b 100644
--- a/Neos.Neos/Classes/Command/SiteCommandController.php
+++ b/Neos.Neos/Classes/Command/SiteCommandController.php
@@ -95,7 +95,7 @@ public function createCommand($name, $packageKey, $nodeType, $nodeName = null, $
} catch (SiteNodeTypeIsInvalid $exception) {
$this->outputLine(
'The given node type "%s" is not based on the superType "%s"',
- [$nodeType, NodeTypeNameFactory::forSite()]
+ [$nodeType, NodeTypeNameFactory::NAME_SITE]
);
$this->quit(1);
} catch (SiteNodeNameIsAlreadyInUseByAnotherSite | NodeNameIsAlreadyOccupied $exception) {
diff --git a/Neos.Neos/Classes/Controller/Module/Administration/SitesController.php b/Neos.Neos/Classes/Controller/Module/Administration/SitesController.php
index 5cc1a00fb17..ca5b04ed8fb 100755
--- a/Neos.Neos/Classes/Controller/Module/Administration/SitesController.php
+++ b/Neos.Neos/Classes/Controller/Module/Administration/SitesController.php
@@ -399,7 +399,7 @@ public function createSiteNodeAction($packageKey, $siteName, $nodeType)
$this->addFlashMessage(
$this->getModuleLabel(
'sites.siteCreationError.givenNodeTypeNotBasedOnSuperType.body',
- [$nodeType, NodeTypeNameFactory::forSite()]
+ [$nodeType, NodeTypeNameFactory::NAME_SITE]
),
$this->getModuleLabel('sites.siteCreationError.givenNodeTypeNotBasedOnSuperType.title'),
Message::SEVERITY_ERROR,
From deae06c1a1124ee1b2d8991e8b267db6f514a304 Mon Sep 17 00:00:00 2001
From: mhsdesign <85400359+mhsdesign@users.noreply.github.com>
Date: Wed, 27 Sep 2023 10:05:42 +0200
Subject: [PATCH 05/15] TASK: Adjust legacy node migrations to enforce that
site node must be of type `Neos.Neos:Site`.
---
.../Classes/NodeDataToEventsProcessor.php | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php b/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php
index 6e827a4eb69..b4b4cbceb38 100644
--- a/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php
+++ b/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php
@@ -45,14 +45,13 @@
use Neos\ContentRepository\Core\Projection\ContentGraph\NodePath;
use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint;
use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePointSet;
-use Neos\ContentRepository\Core\SharedModel\Node\PropertyName;
use Neos\ContentRepository\Core\NodeType\NodeType;
use Neos\ContentRepository\Core\NodeType\NodeTypeManager;
use Neos\ContentRepository\Core\NodeType\NodeTypeName;
-use Neos\ContentRepository\Core\SharedModel\User\UserId;
use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId;
use Neos\Flow\Persistence\Doctrine\DataTypes\JsonArrayType;
use Neos\Flow\Property\PropertyMapper;
+use Neos\Neos\Domain\Service\NodeTypeNameFactory;
use Ramsey\Uuid\Uuid;
use Webmozart\Assert\Assert;
@@ -243,6 +242,13 @@ public function processNodeDataWithoutFallbackToEmptyDimension(NodeAggregateId $
$nodeType = $this->nodeTypeManager->getNodeType($nodeTypeName);
$serializedPropertyValuesAndReferences = $this->extractPropertyValuesAndReferences($nodeDataRow, $nodeType);
+ $isSiteNode = $nodeDataRow['parentpath'] === '/sites';
+ if ($isSiteNode && !$nodeType->isOfType(NodeTypeNameFactory::NAME_SITE)) {
+ throw new MigrationException(sprintf(
+ 'The site node "%s" (type: "%s") must be of type "Neos.Neos:Site".', $nodeDataRow['identifier'], $nodeTypeName->value,
+ ), 1695801620);
+ }
+
if ($this->isAutoCreatedChildNode($parentNodeAggregate->nodeTypeName, $nodeName) && !$this->visitedNodes->containsNodeAggregate($nodeAggregateId)) {
// Create tethered node if the node was not found before.
// If the node was already visited, we want to create a node variant (and keep the tethering status)
From 724df3c3a3ae48cf7f6ea1a069d731d7b51a4e43 Mon Sep 17 00:00:00 2001
From: mhsdesign <85400359+mhsdesign@users.noreply.github.com>
Date: Wed, 27 Sep 2023 10:15:30 +0200
Subject: [PATCH 06/15] TASK: Guard
`NodeDataToEventsProcessor::setSitesNodeType`
---
.../Classes/NodeDataToEventsProcessor.php | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php b/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php
index b4b4cbceb38..cb50f45e471 100644
--- a/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php
+++ b/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php
@@ -86,7 +86,7 @@ public function __construct(
private readonly Filesystem $files,
private readonly iterable $nodeDataRows,
) {
- $this->sitesNodeTypeName = NodeTypeName::fromString('Neos.Neos:Sites');
+ $this->sitesNodeTypeName = NodeTypeName::fromString(NodeTypeNameFactory::NAME_SITES);
$this->contentStreamId = ContentStreamId::create();
$this->visitedNodes = new VisitedNodeAggregates();
}
@@ -98,6 +98,13 @@ public function setContentStreamId(ContentStreamId $contentStreamId): void
public function setSitesNodeType(NodeTypeName $nodeTypeName): void
{
+ $nodeType = $this->nodeTypeManager->getNodeType($nodeTypeName);
+ if (!$nodeType->isOfType(NodeTypeNameFactory::NAME_SITES)) {
+ throw new \InvalidArgumentException(
+ sprintf('Sites NodeType "%s" must be of type "%s".', $nodeTypeName->value, NodeTypeNameFactory::NAME_SITES),
+ 1695802415
+ );
+ }
$this->sitesNodeTypeName = $nodeTypeName;
}
@@ -245,7 +252,7 @@ public function processNodeDataWithoutFallbackToEmptyDimension(NodeAggregateId $
$isSiteNode = $nodeDataRow['parentpath'] === '/sites';
if ($isSiteNode && !$nodeType->isOfType(NodeTypeNameFactory::NAME_SITE)) {
throw new MigrationException(sprintf(
- 'The site node "%s" (type: "%s") must be of type "Neos.Neos:Site".', $nodeDataRow['identifier'], $nodeTypeName->value,
+ 'The site node "%s" (type: "%s") must be of type "%s".', $nodeDataRow['identifier'], $nodeTypeName->value, NodeTypeNameFactory::NAME_SITE
), 1695801620);
}
From 405a03d17a159c1e26dcf9be5cc545792e05804d Mon Sep 17 00:00:00 2001
From: Marc Henry Schultz <85400359+mhsdesign@users.noreply.github.com>
Date: Fri, 29 Sep 2023 08:51:07 +0200
Subject: [PATCH 07/15] TASK: Use `NodeTypeName::forSites` correctly
Co-authored-by: Denny Lubitz
---
.../Classes/NodeDataToEventsProcessor.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php b/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php
index cb50f45e471..58d7f5d2dfc 100644
--- a/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php
+++ b/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php
@@ -86,7 +86,7 @@ public function __construct(
private readonly Filesystem $files,
private readonly iterable $nodeDataRows,
) {
- $this->sitesNodeTypeName = NodeTypeName::fromString(NodeTypeNameFactory::NAME_SITES);
+ $this->sitesNodeTypeName = NodeTypeName::forSites();
$this->contentStreamId = ContentStreamId::create();
$this->visitedNodes = new VisitedNodeAggregates();
}
From b2cd87c513a02f53f6ae4168c03c841dac43b38a Mon Sep 17 00:00:00 2001
From: mhsdesign <85400359+mhsdesign@users.noreply.github.com>
Date: Fri, 29 Sep 2023 13:39:48 +0200
Subject: [PATCH 08/15] TASK: Adjust Legacy migration tests to `Neos.Neos:Site`
---
.../Classes/NodeDataToEventsProcessor.php | 2 +-
.../Tests/Behavior/Features/Assets.feature | 19 +++---
.../Tests/Behavior/Features/Basic.feature | 10 ++-
.../Tests/Behavior/Features/Errors.feature | 63 +++++++++--------
.../Behavior/Features/References.feature | 6 +-
.../Tests/Behavior/Features/Variants.feature | 67 +++++++++----------
6 files changed, 93 insertions(+), 74 deletions(-)
diff --git a/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php b/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php
index 27bb51523de..87cb005fd6e 100644
--- a/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php
+++ b/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php
@@ -87,7 +87,7 @@ public function __construct(
private readonly Filesystem $files,
private readonly iterable $nodeDataRows,
) {
- $this->sitesNodeTypeName = NodeTypeName::forSites();
+ $this->sitesNodeTypeName = NodeTypeNameFactory::forSites();
$this->contentStreamId = ContentStreamId::create();
$this->visitedNodes = new VisitedNodeAggregates();
}
diff --git a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Assets.feature b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Assets.feature
index 220bda3b208..bc5cf9671ea 100644
--- a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Assets.feature
+++ b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Assets.feature
@@ -8,7 +8,10 @@ Feature: Export of used Assets, Image Variants and Persistent Resources
And using the following node types:
"""yaml
'unstructured': {}
- 'Some.Package:SomeNodeType':
+ 'Neos.Neos:Site': {}
+ 'Some.Package:Homepage':
+ superTypes:
+ 'Neos.Neos:Site': true
properties:
'string':
type: string
@@ -43,7 +46,7 @@ Feature: Export of used Assets, Image Variants and Persistent Resources
When I have the following node data rows:
| Identifier | Path | Node Type | Properties |
| sites-node-id | /sites | unstructured | |
- | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"string": "asset:\/\/variant1"} |
+ | site-node-id | /sites/test-site | Some.Package:Homepage | {"string": "asset:\/\/variant1"} |
And I run the asset migration
Then I expect the following Assets to be exported:
"""
@@ -87,10 +90,10 @@ Feature: Export of used Assets, Image Variants and Persistent Resources
When I have the following node data rows:
| Identifier | Path | Node Type | Dimension Values | Properties |
| sites-node-id | /sites | unstructured | | |
- | site-node-id | /sites/test-site | Some.Package:SomeNodeType | | {"string": "asset:\/\/asset1"} |
- | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"language": ["ch"]} | {"image": {"__flow_object_type": "Neos\\Media\\Domain\\Model\\Image", "__identifier": "asset2"}} |
- | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"language": ["en"]} | {"assets": [{"__flow_object_type": "Neos\\Media\\Domain\\Model\\Document", "__identifier": "asset3"}, {"__flow_object_type": "Neos\\Media\\Domain\\Model\\Image", "__identifier": "asset2"}, {"__flow_object_type": "Neos\\Media\\Domain\\Model\\ImageVariant", "__identifier": "variant1"}]} |
- | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"language": ["de"]} | {"string": "some text with an asset link"} |
+ | site-node-id | /sites/test-site | Some.Package:Homepage | | {"string": "asset:\/\/asset1"} |
+ | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["ch"]} | {"image": {"__flow_object_type": "Neos\\Media\\Domain\\Model\\Image", "__identifier": "asset2"}} |
+ | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["en"]} | {"assets": [{"__flow_object_type": "Neos\\Media\\Domain\\Model\\Document", "__identifier": "asset3"}, {"__flow_object_type": "Neos\\Media\\Domain\\Model\\Image", "__identifier": "asset2"}, {"__flow_object_type": "Neos\\Media\\Domain\\Model\\ImageVariant", "__identifier": "variant1"}]} |
+ | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["de"]} | {"string": "some text with an asset link"} |
And I run the asset migration
Then I expect the following Assets to be exported:
"""
@@ -178,10 +181,10 @@ Feature: Export of used Assets, Image Variants and Persistent Resources
When I have the following node data rows:
| Identifier | Path | Node Type | Properties |
| sites-node-id | /sites | unstructured | |
- | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"string": "asset:\/\/non-existing-asset"} |
+ | site-node-id | /sites/test-site | Some.Package:Homepage | {"string": "asset:\/\/non-existing-asset"} |
And I run the asset migration
Then I expect no Assets to be exported
And I expect no ImageVariants to be exported
And I expect no PersistentResources to be exported
And I expect the following errors to be logged
- | Failed to extract assets of property "string" of node "site-node-id" (type: "Some.Package:SomeNodeType"): Failed to find mock asset with id "non-existing-asset" |
+ | Failed to extract assets of property "string" of node "site-node-id" (type: "Some.Package:Homepage"): Failed to find mock asset with id "non-existing-asset" |
diff --git a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Basic.feature b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Basic.feature
index 20462bc12b0..3623e2fe61a 100644
--- a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Basic.feature
+++ b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Basic.feature
@@ -5,7 +5,11 @@ Feature: Simple migrations without content dimensions
Given using no content dimensions
And using the following node types:
"""yaml
- 'Some.Package:SomeNodeType':
+ 'unstructured': {}
+ 'Neos.Neos:Site': {}
+ 'Some.Package:Homepage':
+ superTypes:
+ 'Neos.Neos:Site': true
properties:
'text':
type: string
@@ -18,9 +22,9 @@ Feature: Simple migrations without content dimensions
When I have the following node data rows:
| Identifier | Path | Node Type | Properties |
| sites-node-id | /sites | unstructured | |
- | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"text": "foo"} |
+ | site-node-id | /sites/test-site | Some.Package:Homepage | {"text": "foo"} |
And I run the event migration for content stream "cs-id"
Then I expect the following events to be exported
| Type | Payload |
| RootNodeAggregateWithNodeWasCreated | {"contentStreamId": "cs-id", "nodeAggregateId": "sites-node-id", "nodeTypeName": "Neos.Neos:Sites", "nodeAggregateClassification": "root"} |
- | NodeAggregateWithNodeWasCreated | {"contentStreamId": "cs-id", "nodeAggregateId": "site-node-id", "nodeTypeName": "Some.Package:SomeNodeType", "nodeName": "test-site", "parentNodeAggregateId": "sites-node-id", "nodeAggregateClassification": "regular", "initialPropertyValues": {"text": {"type": "string", "value": "foo"}}} |
+ | NodeAggregateWithNodeWasCreated | {"contentStreamId": "cs-id", "nodeAggregateId": "site-node-id", "nodeTypeName": "Some.Package:Homepage", "nodeName": "test-site", "parentNodeAggregateId": "sites-node-id", "nodeAggregateClassification": "regular", "initialPropertyValues": {"text": {"type": "string", "value": "foo"}}} |
diff --git a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Errors.feature b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Errors.feature
index c036cb2bf52..0f98894c60a 100644
--- a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Errors.feature
+++ b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Errors.feature
@@ -5,13 +5,22 @@ Feature: Exceptional cases during migrations
Given using no content dimensions
And using the following node types:
"""yaml
- 'unstructured': []
- 'Some.Package:SomeNodeType':
+ 'unstructured': {}
+ 'Neos.Neos:Site': {}
+ 'Some.Package:Homepage':
+ superTypes:
+ 'Neos.Neos:Site': true
properties:
'text':
type: string
defaultValue: 'My default text'
- 'Some.Package:SomeOtherNodeType': []
+ 'Some.Package:SomeNodeType':
+ properties:
+ 'text':
+ type: string
+ 'Some.Package:SomeOtherHomepage':
+ superTypes:
+ 'Neos.Neos:Site': true
"""
And using identifier "default", I define a content repository
And I am in content repository "default"
@@ -23,26 +32,26 @@ Feature: Exceptional cases during migrations
When I have the following node data rows:
| Identifier | Path | Node Type | Dimension Values |
| sites-node-id | /sites | unstructured | |
- | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"language": ["de"]} |
- | site-node-id | /sites/test-site | Some.Package:SomeOtherNodeType | {"language": ["en"]} |
+ | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["de"]} |
+ | site-node-id | /sites/test-site | Some.Package:SomeOtherHomepage | {"language": ["en"]} |
And I run the event migration
Then I expect a MigrationError with the message
"""
- Node aggregate with id "site-node-id" has a type of "Some.Package:SomeOtherNodeType" in content dimension [{"language":"en"}]. I was visited previously for content dimension [{"language":"de"}] with the type "Some.Package:SomeNodeType". Node variants must not have different types
+ Node aggregate with id "site-node-id" has a type of "Some.Package:SomeOtherHomepage" in content dimension [{"language":"en"}]. I was visited previously for content dimension [{"language":"de"}] with the type "Some.Package:Homepage". Node variants must not have different types
"""
# Note: The behavior was changed with https://github.com/neos/neos-development-collection/pull/4201
Scenario: Node with missing parent
When I have the following node data rows:
- | Identifier | Path |
- | sites | /sites |
- | a | /sites/a |
- | c | /sites/b/c |
+ | Identifier | Path | Node Type |
+ | sites | /sites | unstructured |
+ | a | /sites/a | Some.Package:Homepage |
+ | c | /sites/b/c | unstructured |
And I run the event migration
Then I expect the following events to be exported
| Type | Payload |
| RootNodeAggregateWithNodeWasCreated | {"nodeAggregateId": "sites", "nodeTypeName": "Neos.Neos:Sites", "nodeAggregateClassification": "root"} |
- | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "a", "parentNodeAggregateId": "sites"} |
+ | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "a", "nodeTypeName": "Some.Package:Homepage", "parentNodeAggregateId": "sites"} |
And I expect the following errors to be logged
| Failed to find parent node for node with id "c" and dimensions: []. Please ensure that the new content repository has a valid content dimension configuration. Also note that the old CR can sometimes have orphaned nodes. |
@@ -50,17 +59,17 @@ Feature: Exceptional cases during migrations
# Note: The behavior was changed with https://github.com/neos/neos-development-collection/pull/4201
Scenario: Nodes out of order
When I have the following node data rows:
- | Identifier | Path |
- | sites | /sites |
- | a | /sites/a |
- | c | /sites/b/c |
- | b | /sites/b |
+ | Identifier | Path | Node Type |
+ | sites | /sites | unstructured |
+ | a | /sites/a | Some.Package:Homepage |
+ | c | /sites/b/c | unstructured |
+ | b | /sites/b | Some.Package:Homepage |
And I run the event migration
Then I expect the following events to be exported
| Type | Payload |
| RootNodeAggregateWithNodeWasCreated | {"nodeAggregateId": "sites", "nodeTypeName": "Neos.Neos:Sites", "nodeAggregateClassification": "root"} |
- | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "a", "parentNodeAggregateId": "sites"} |
- | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "b", "parentNodeAggregateId": "sites"} |
+ | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "a", "nodeTypeName": "Some.Package:Homepage", "parentNodeAggregateId": "sites"} |
+ | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "b", "nodeTypeName": "Some.Package:Homepage", "parentNodeAggregateId": "sites"} |
And I expect the following errors to be logged
| Failed to find parent node for node with id "c" and dimensions: []. Please ensure that the new content repository has a valid content dimension configuration. Also note that the old CR can sometimes have orphaned nodes. |
@@ -104,11 +113,11 @@ Feature: Exceptional cases during migrations
| Identifier | Default | Values | Generalizations |
| language | en | en, de, ch | ch->de |
When I have the following node data rows:
- | Identifier | Path | Dimension Values |
- | sites-node-id | /sites | |
- | site-node-id | /sites/test-site | {"language": ["de"]} |
- | site-node-id | /sites/test-site | {"language": ["ch"]} |
- | site-node-id | /sites/test-site | {"language": ["ch"]} |
+ | Identifier | Path | Node Type | Dimension Values |
+ | sites-node-id | /sites | unstructured | |
+ | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["de"]} |
+ | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["ch"]} |
+ | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["ch"]} |
And I run the event migration
Then I expect a MigrationError with the message
"""
@@ -120,10 +129,10 @@ Feature: Exceptional cases during migrations
| Identifier | Default | Values | Generalizations |
| language | en | en, de, ch | ch->de |
When I have the following node data rows:
- | Identifier | Path | Dimension Values |
- | sites-node-id | /sites | |
- | site-node-id | /sites/test-site | {"language": ["de"]} |
- | site-node-id | /sites/test-site | {"language": ["de"]} |
+ | Identifier | Path | Node Type | Dimension Values |
+ | sites-node-id | /sites | unstructured | |
+ | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["de"]} |
+ | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["de"]} |
And I run the event migration
Then I expect a MigrationError with the message
"""
diff --git a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/References.feature b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/References.feature
index e9dcb7dfc60..7c67812eb50 100644
--- a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/References.feature
+++ b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/References.feature
@@ -5,7 +5,11 @@ Feature: Migrations that contain nodes with "reference" or "references propertie
Given using no content dimensions
And using the following node types:
"""yaml
- 'Some.Package:Homepage': []
+ 'unstructured': {}
+ 'Neos.Neos:Site': {}
+ 'Some.Package:Homepage':
+ superTypes:
+ 'Neos.Neos:Site': true
'Some.Package:SomeNodeType':
properties:
'text':
diff --git a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Variants.feature b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Variants.feature
index f5a1299ec0b..e6285a44323 100644
--- a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Variants.feature
+++ b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Variants.feature
@@ -8,27 +8,26 @@ Feature: Migrating nodes with content dimensions
And using the following node types:
"""yaml
'unstructured': {}
- 'Some.Package:SomeNodeType':
- properties:
- 'text':
- type: string
- defaultValue: 'My default text'
+ 'Neos.Neos:Site': {}
+ 'Some.Package:Homepage':
+ superTypes:
+ 'Neos.Neos:Site': true
"""
And using identifier "default", I define a content repository
And I am in content repository "default"
Scenario: Node specialization variants are prioritized over peer variants
When I have the following node data rows:
- | Identifier | Path | Node Type | Dimension Values |
- | sites-node-id | /sites | unstructured | |
- | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"language": ["de"]} |
- | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"language": ["en"]} |
- | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"language": ["ch"]} |
+ | Identifier | Path | Node Type | Dimension Values |
+ | sites-node-id | /sites | unstructured | |
+ | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["de"]} |
+ | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["en"]} |
+ | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["ch"]} |
And I run the event migration
Then I expect the following events to be exported
| Type | Payload |
| RootNodeAggregateWithNodeWasCreated | {"nodeAggregateId": "sites-node-id", "nodeTypeName": "Neos.Neos:Sites", "coveredDimensionSpacePoints": [{"language": "en"},{"language": "de"},{"language": "ch"}], "nodeAggregateClassification": "root"} |
- | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "site-node-id", "nodeTypeName": "Some.Package:SomeNodeType", "nodeName": "test-site", "originDimensionSpacePoint": {"language": "de"}, "coveredDimensionSpacePoints": [{"language": "de"},{"language": "ch"}], "parentNodeAggregateId": "sites-node-id", "nodeAggregateClassification": "regular"} |
+ | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "site-node-id", "nodeTypeName": "Some.Package:Homepage", "nodeName": "test-site", "originDimensionSpacePoint": {"language": "de"}, "coveredDimensionSpacePoints": [{"language": "de"},{"language": "ch"}], "parentNodeAggregateId": "sites-node-id", "nodeAggregateClassification": "regular"} |
| NodePeerVariantWasCreated | {"nodeAggregateId": "site-node-id", "sourceOrigin": {"language": "de"}, "peerOrigin": {"language": "en"}, "peerCoverage": [{"language": "en"}]} |
| NodeSpecializationVariantWasCreated | {"nodeAggregateId": "site-node-id", "sourceOrigin": {"language": "de"}, "specializationOrigin": {"language": "ch"}, "specializationCoverage": [{"language": "ch"}]} |
@@ -36,14 +35,14 @@ Feature: Migrating nodes with content dimensions
When I have the following node data rows:
| Identifier | Path | Node Type | Dimension Values |
| sites-node-id | /sites | unstructured | |
- | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"language": ["ch"]} |
- | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"language": ["en"]} |
- | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"language": ["de"]} |
+ | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["ch"]} |
+ | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["en"]} |
+ | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["de"]} |
And I run the event migration
Then I expect the following events to be exported
| Type | Payload |
| RootNodeAggregateWithNodeWasCreated | {"nodeAggregateId": "sites-node-id", "nodeTypeName": "Neos.Neos:Sites", "coveredDimensionSpacePoints": [{"language": "en"},{"language": "de"},{"language": "ch"}], "nodeAggregateClassification": "root"} |
- | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "site-node-id", "nodeTypeName": "Some.Package:SomeNodeType", "nodeName": "test-site", "originDimensionSpacePoint": {"language": "ch"}, "coveredDimensionSpacePoints": [{"language": "ch"}], "parentNodeAggregateId": "sites-node-id", "nodeAggregateClassification": "regular"} |
+ | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "site-node-id", "nodeTypeName": "Some.Package:Homepage", "nodeName": "test-site", "originDimensionSpacePoint": {"language": "ch"}, "coveredDimensionSpacePoints": [{"language": "ch"}], "parentNodeAggregateId": "sites-node-id", "nodeAggregateClassification": "regular"} |
| NodePeerVariantWasCreated | {"nodeAggregateId": "site-node-id", "sourceOrigin": {"language": "ch"}, "peerOrigin": {"language": "en"}, "peerCoverage": [{"language": "en"}]} |
| NodeGeneralizationVariantWasCreated | {"nodeAggregateId": "site-node-id", "sourceOrigin": {"language": "ch"}, "generalizationOrigin": {"language": "de"}, "generalizationCoverage": [{"language": "de"}]} |
@@ -52,10 +51,10 @@ Feature: Migrating nodes with content dimensions
| Identifier | Default | Values | Generalizations |
| language | mul | mul, en, de, ch | ch->de->mul |
When I have the following node data rows:
- | Identifier | Path | Dimension Values |
- | sites | /sites | |
- | site | /sites/site | {"language": ["mul"]} |
- | site | /sites/site | {"language": ["de"]} |
+ | Identifier | Path | Node Type | Dimension Values |
+ | sites | /sites | unstructured | |
+ | site | /sites/site | Some.Package:Homepage | {"language": ["mul"]} |
+ | site | /sites/site | Some.Package:Homepage | {"language": ["de"]} |
And I run the event migration
Then I expect the following events to be exported
| Type | Payload |
@@ -65,13 +64,13 @@ Feature: Migrating nodes with content dimensions
Scenario: Node variant with different parent node (moved)
When I have the following node data rows:
- | Identifier | Path | Dimension Values |
- | sites | /sites | |
- | site | /sites/site | {"language": ["de"]} |
- | a | /sites/site/a | {"language": ["de"]} |
- | a1 | /sites/site/a/a1 | {"language": ["de"]} |
- | b | /sites/site/b | {"language": ["de"]} |
- | a1 | /sites/site/b/a1 | {"language": ["ch"]} |
+ | Identifier | Path | Node Type | Dimension Values |
+ | sites | /sites | unstructured | |
+ | site | /sites/site | Some.Package:Homepage | {"language": ["de"]} |
+ | a | /sites/site/a | unstructured | {"language": ["de"]} |
+ | a1 | /sites/site/a/a1 | unstructured | {"language": ["de"]} |
+ | b | /sites/site/b | unstructured | {"language": ["de"]} |
+ | a1 | /sites/site/b/a1 | unstructured | {"language": ["ch"]} |
And I run the event migration
Then I expect the following events to be exported
| Type | Payload |
@@ -86,14 +85,14 @@ Feature: Migrating nodes with content dimensions
Scenario: Node variant with different grand parent node (ancestor node was moved) - Note: There is only NodeAggregateWasMoved event for "a" and not for "a1"
When I have the following node data rows:
- | Identifier | Path | Dimension Values |
- | sites | /sites | |
- | site | /sites/site | {"language": ["de"]} |
- | a | /sites/site/a | {"language": ["de"]} |
- | a1 | /sites/site/a/a1 | {"language": ["de"]} |
- | b | /sites/site/b | {"language": ["de"]} |
- | a | /sites/site/b/a | {"language": ["ch"]} |
- | a1 | /sites/site/b/a/a1 | {"language": ["ch"]} |
+ | Identifier | Path | Node Type | Dimension Values |
+ | sites | /sites | unstructured | |
+ | site | /sites/site | Some.Package:Homepage | {"language": ["de"]} |
+ | a | /sites/site/a | unstructured | {"language": ["de"]} |
+ | a1 | /sites/site/a/a1 | unstructured | {"language": ["de"]} |
+ | b | /sites/site/b | unstructured | {"language": ["de"]} |
+ | a | /sites/site/b/a | unstructured | {"language": ["ch"]} |
+ | a1 | /sites/site/b/a/a1 | unstructured | {"language": ["ch"]} |
And I run the event migration
Then I expect the following events to be exported
| Type | Payload |
From d72070b0cd51e70a3b5997d84d3baffb897f487d Mon Sep 17 00:00:00 2001
From: mhsdesign <85400359+mhsdesign@users.noreply.github.com>
Date: Fri, 29 Sep 2023 13:42:53 +0200
Subject: [PATCH 09/15] TASK: Legacy migration test scenario: Homepage node is
not of type "Neos.Neos:Site"
---
.../Classes/NodeDataToEventsProcessor.php | 4 ++--
.../Tests/Behavior/Features/Errors.feature | 11 +++++++++++
2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php b/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php
index 87cb005fd6e..8d256106bc8 100644
--- a/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php
+++ b/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php
@@ -102,7 +102,7 @@ public function setSitesNodeType(NodeTypeName $nodeTypeName): void
$nodeType = $this->nodeTypeManager->getNodeType($nodeTypeName);
if (!$nodeType->isOfType(NodeTypeNameFactory::NAME_SITES)) {
throw new \InvalidArgumentException(
- sprintf('Sites NodeType "%s" must be of type "%s".', $nodeTypeName->value, NodeTypeNameFactory::NAME_SITES),
+ sprintf('Sites NodeType "%s" must be of type "%s"', $nodeTypeName->value, NodeTypeNameFactory::NAME_SITES),
1695802415
);
}
@@ -253,7 +253,7 @@ public function processNodeDataWithoutFallbackToEmptyDimension(NodeAggregateId $
$isSiteNode = $nodeDataRow['parentpath'] === '/sites';
if ($isSiteNode && !$nodeType->isOfType(NodeTypeNameFactory::NAME_SITE)) {
throw new MigrationException(sprintf(
- 'The site node "%s" (type: "%s") must be of type "%s".', $nodeDataRow['identifier'], $nodeTypeName->value, NodeTypeNameFactory::NAME_SITE
+ 'The site node "%s" (type: "%s") must be of type "%s"', $nodeDataRow['identifier'], $nodeTypeName->value, NodeTypeNameFactory::NAME_SITE
), 1695801620);
}
diff --git a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Errors.feature b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Errors.feature
index 0f98894c60a..4cf57e96a4c 100644
--- a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Errors.feature
+++ b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Errors.feature
@@ -138,3 +138,14 @@ Feature: Exceptional cases during migrations
"""
Node "site-node-id" for dimension {"language":"de"} was already created previously
"""
+
+ Scenario: Homepage node is not of type "Neos.Neos:Site"
+ When I have the following node data rows:
+ | Identifier | Path | Node Type |
+ | sites-node-id | /sites | unstructured |
+ | site-node-id | /sites/test-site | unstructured |
+ And I run the event migration
+ Then I expect a MigrationError with the message
+ """
+ The site node "site-node-id" (type: "unstructured") must be of type "Neos.Neos:Site"
+ """
From 5d700f53aa02695f45b40af8927b1fdbb7aa17c2 Mon Sep 17 00:00:00 2001
From: mhsdesign <85400359+mhsdesign@users.noreply.github.com>
Date: Fri, 29 Sep 2023 16:40:08 +0200
Subject: [PATCH 10/15] TASK: Adjust `SiteNodeUtility` to use 'Neos.Neos:Sites'
---
.../Service/NodeSiteResolvingService.php | 25 ++++++-------------
.../Domain/Service/SiteNodeUtility.php | 21 ++++++----------
2 files changed, 16 insertions(+), 30 deletions(-)
diff --git a/Neos.Neos/Classes/Domain/Service/NodeSiteResolvingService.php b/Neos.Neos/Classes/Domain/Service/NodeSiteResolvingService.php
index 0807b96ccd3..ada2ab0f811 100644
--- a/Neos.Neos/Classes/Domain/Service/NodeSiteResolvingService.php
+++ b/Neos.Neos/Classes/Domain/Service/NodeSiteResolvingService.php
@@ -15,7 +15,7 @@
namespace Neos\Neos\Domain\Service;
use Neos\ContentRepository\Core\Factory\ContentRepositoryId;
-use Neos\ContentRepository\Core\Projection\ContentGraph\ContentSubgraphIdentity;
+use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter;
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
use Neos\Neos\FrontendRouting\NodeAddress;
use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints;
@@ -25,12 +25,10 @@
#[Flow\Scope('singleton')]
class NodeSiteResolvingService
{
- /**
- * @Flow\Inject
- * @var ContentRepositoryRegistry
- */
- protected $contentRepositoryRegistry;
+ #[Flow\Inject]
+ protected ContentRepositoryRegistry $contentRepositoryRegistry;
+ /** @internal */
public function findSiteNodeForNodeAddress(
NodeAddress $nodeAddress,
ContentRepositoryId $contentRepositoryId
@@ -45,20 +43,13 @@ public function findSiteNodeForNodeAddress(
? VisibilityConstraints::frontend()
: VisibilityConstraints::withoutRestrictions()
);
+
$node = $subgraph->findNodeById($nodeAddress->nodeAggregateId);
- if (is_null($node)) {
+ if (!$node) {
return null;
}
- $previousNode = null;
- do {
- if ($node->nodeType->isOfType('Neos.Neos:Sites')) {
- // the Site node is the one one level underneath the "Sites" node.
- return $previousNode;
- }
- $previousNode = $node;
- } while ($node = $subgraph->findParentNode($node->nodeAggregateId));
+ $siteNode = $subgraph->findClosestNode($node->nodeAggregateId, FindClosestNodeFilter::create(NodeTypeNameFactory::NAME_SITE));
- // no Site node found at rootline
- return null;
+ return $siteNode;
}
}
diff --git a/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php b/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php
index e676f4579c0..0b3f88b92e9 100644
--- a/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php
+++ b/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php
@@ -17,6 +17,7 @@
use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint;
use Neos\ContentRepository\Core\Factory\ContentRepositoryId;
+use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter;
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
use Neos\ContentRepository\Core\NodeType\NodeTypeName;
use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints;
@@ -39,23 +40,17 @@ public function __construct(
public function findSiteNode(Node $node): Node
{
- $previousNode = null;
$subgraph = $this->contentRepositoryRegistry->subgraphForNode($node);
- do {
- if ($node->nodeType->isOfType('Neos.Neos:Sites')) {
- // the Site node is the one one level underneath the "Sites" node.
- if (is_null($previousNode)) {
- break;
- }
- return $previousNode;
- }
- $previousNode = $node;
- } while ($node = $subgraph->findParentNode($node->nodeAggregateId));
+ $siteNode = $subgraph->findClosestNode($node->nodeAggregateId, FindClosestNodeFilter::create(NodeTypeNameFactory::NAME_SITE));
+
+ if (!$siteNode) {
+ throw new \RuntimeException('No site node found!');
+ }
- // no Site node found at rootline
- throw new \RuntimeException('No site node found!');
+ return $siteNode;
}
+ /** @internal */
public function findCurrentSiteNode(
ContentRepositoryId $contentRepositoryId,
ContentStreamId $contentStreamId,
From 4088711eaedc656fb1149d8cddf67a3b60e45c5f Mon Sep 17 00:00:00 2001
From: mhsdesign <85400359+mhsdesign@users.noreply.github.com>
Date: Wed, 11 Oct 2023 21:50:36 +0200
Subject: [PATCH 11/15] TASK: Inline `SiteNodeUtility::findSiteNode`
---
.../Classes/Controller/UsageController.php | 29 +++++++++----------
.../Domain/Service/SiteNodeUtility.php | 14 +--------
.../Classes/Domain/Service/SiteService.php | 17 ++++-------
Neos.Neos/Classes/View/FusionView.php | 16 +++++-----
4 files changed, 28 insertions(+), 48 deletions(-)
diff --git a/Neos.Media.Browser/Classes/Controller/UsageController.php b/Neos.Media.Browser/Classes/Controller/UsageController.php
index eb3dab88e26..6a1c6b924fe 100644
--- a/Neos.Media.Browser/Classes/Controller/UsageController.php
+++ b/Neos.Media.Browser/Classes/Controller/UsageController.php
@@ -12,20 +12,21 @@
* source code.
*/
+use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter;
+use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints;
use Neos\ContentRepository\Core\SharedModel\Exception\NodeTypeNotFoundException;
use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName;
use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry;
-use Neos\Eel\FlowQuery\FlowQuery;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Mvc\Controller\ActionController;
use Neos\Media\Domain\Model\AssetInterface;
use Neos\Media\Domain\Service\AssetService;
use Neos\Neos\Domain\Repository\SiteRepository;
+use Neos\Neos\Domain\Service\NodeTypeNameFactory;
use Neos\Neos\FrontendRouting\SiteDetection\SiteDetectionResult;
use Neos\Neos\Service\UserService;
use Neos\Neos\Domain\Service\UserService as DomainUserService;
use Neos\Neos\AssetUsage\Dto\AssetUsageReference;
-use Neos\Neos\Domain\Service\SiteNodeUtility;
use Neos\Neos\Domain\Model\Site;
/**
@@ -65,12 +66,6 @@ class UsageController extends ActionController
*/
protected $domainUserService;
- /**
- * @Flow\Inject
- * @var SiteNodeUtility
- */
- protected $siteNodeUtility;
-
/**
* Get Related Nodes for an asset
*
@@ -126,28 +121,32 @@ public function relatedNodesAction(AssetInterface $asset)
continue;
}
- $node = $contentRepository->getContentGraph()->findNodeByIdAndOriginDimensionSpacePoint(
+ $subgraph = $contentRepository->getContentGraph()->getSubgraph(
$usage->getContentStreamId(),
- $usage->getNodeAggregateId(),
- $usage->getOriginDimensionSpacePoint()
+ $usage->getOriginDimensionSpacePoint()->toDimensionSpacePoint(),
+ VisibilityConstraints::withoutRestrictions()
);
+ $node = $subgraph->findNodeById($usage->getNodeAggregateId());
// this should actually never happen.
if (!$node) {
$inaccessibleRelations[] = $inaccessibleRelation;
continue;
}
- $flowQuery = new FlowQuery([$node]);
- $documentNode = $flowQuery->closest('[instanceof Neos.Neos:Document]')->get(0);
+ $documentNode = $subgraph->findClosestNode($node->nodeAggregateId, FindClosestNodeFilter::create(nodeTypeConstraints: NodeTypeNameFactory::NAME_DOCUMENT));
// this should actually never happen, too.
if (!$documentNode) {
$inaccessibleRelations[] = $inaccessibleRelation;
continue;
}
-
- $siteNode = $this->siteNodeUtility->findSiteNode($node);
+ $siteNode = $subgraph->findClosestNode($node->nodeAggregateId, FindClosestNodeFilter::create(nodeTypeConstraints: NodeTypeNameFactory::NAME_SITE));
+ // this should actually never happen, too. :D
+ if (!$siteNode) {
+ $inaccessibleRelations[] = $inaccessibleRelation;
+ continue;
+ }
foreach ($existingSites as $existingSite) {
/** @var Site $existingSite * */
if ($siteNode->nodeName->equals($existingSite->getNodeName()->toNodeName())) {
diff --git a/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php b/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php
index 0dafb768443..1c0ef9a65cd 100644
--- a/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php
+++ b/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php
@@ -17,7 +17,6 @@
use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint;
use Neos\ContentRepository\Core\Factory\ContentRepositoryId;
-use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter;
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints;
use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId;
@@ -27,6 +26,7 @@
use Neos\Neos\Domain\Repository\DomainRepository;
use Neos\Neos\Domain\Repository\SiteRepository;
+/** @internal */
#[Flow\Scope('singleton')]
final class SiteNodeUtility
{
@@ -37,18 +37,6 @@ public function __construct(
) {
}
- public function findSiteNode(Node $node): Node
- {
- $subgraph = $this->contentRepositoryRegistry->subgraphForNode($node);
- $siteNode = $subgraph->findClosestNode($node->nodeAggregateId, FindClosestNodeFilter::create(NodeTypeNameFactory::NAME_SITE));
-
- if (!$siteNode) {
- throw new \RuntimeException('No site node found!');
- }
-
- return $siteNode;
- }
-
/** @internal */
public function findCurrentSiteNode(
ContentRepositoryId $contentRepositoryId,
diff --git a/Neos.Neos/Classes/Domain/Service/SiteService.php b/Neos.Neos/Classes/Domain/Service/SiteService.php
index 0331b8be881..c1fafe378bf 100644
--- a/Neos.Neos/Classes/Domain/Service/SiteService.php
+++ b/Neos.Neos/Classes/Domain/Service/SiteService.php
@@ -14,11 +14,10 @@
namespace Neos\Neos\Domain\Service;
+use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter;
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
use Neos\ContentRepository\Core\SharedModel\Node\NodeName;
-use Neos\ContentRepository\Core\SharedModel\User\UserId;
use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry;
-use Neos\ContentRepository\Core\Factory\ContentRepositoryId;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Persistence\PersistenceManagerInterface;
use Neos\Media\Domain\Model\Asset;
@@ -65,12 +64,6 @@ class SiteService
*/
protected $assetCollectionRepository;
- #[Flow\Inject]
- protected SiteNodeUtility $siteNodeUtility;
-
- #[Flow\Inject]
- protected UserService $domainUserService;
-
/**
* Remove given site all nodes for that site and all domains associated.
*/
@@ -121,12 +114,12 @@ public function pruneAll()
*/
public function assignUploadedAssetToSiteAssetCollection(Asset $asset, Node $node, string $propertyName)
{
- try {
- $siteNode = $this->siteNodeUtility->findSiteNode($node);
- } catch (\InvalidArgumentException $exception) {
+ $subgraph = $this->contentRepositoryRegistry->subgraphForNode($node);
+ $siteNode = $subgraph->findClosestNode($node->nodeAggregateId, FindClosestNodeFilter::create(nodeTypeConstraints: NodeTypeNameFactory::NAME_SITE));
+ if (!$siteNode) {
+ // should not happen
return;
}
-
if ($siteNode->nodeName === null) {
return;
}
diff --git a/Neos.Neos/Classes/View/FusionView.php b/Neos.Neos/Classes/View/FusionView.php
index 29a469857d8..e9593985608 100644
--- a/Neos.Neos/Classes/View/FusionView.php
+++ b/Neos.Neos/Classes/View/FusionView.php
@@ -15,6 +15,7 @@
namespace Neos\Neos\View;
use GuzzleHttp\Psr7\Message;
+use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter;
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry;
use Neos\Flow\Annotations as Flow;
@@ -28,7 +29,6 @@
use Neos\Neos\Domain\Repository\SiteRepository;
use Neos\Neos\Domain\Service\FusionService;
use Neos\Neos\Domain\Service\NodeTypeNameFactory;
-use Neos\Neos\Domain\Service\SiteNodeUtility;
use Neos\Neos\Domain\Service\RenderingModeService;
use Neos\Neos\Exception;
use Neos\Neos\Utility\NodeTypeWithFallbackProvider;
@@ -45,12 +45,6 @@ class FusionView extends AbstractView
#[Flow\Inject]
protected ContentRepositoryRegistry $contentRepositoryRegistry;
- /**
- * @Flow\Inject
- * @var SiteNodeUtility
- */
- protected $siteNodeUtility;
-
#[Flow\Inject]
protected RuntimeFactory $runtimeFactory;
@@ -71,7 +65,13 @@ public function render(): string|ResponseInterface
{
$currentNode = $this->getCurrentNode();
- $currentSiteNode = $this->siteNodeUtility->findSiteNode($currentNode);
+ $subgraph = $this->contentRepositoryRegistry->subgraphForNode($currentNode);
+ $currentSiteNode = $subgraph->findClosestNode($currentNode->nodeAggregateId, FindClosestNodeFilter::create(nodeTypeConstraints: NodeTypeNameFactory::NAME_SITE));
+
+ if (!$currentSiteNode) {
+ throw new \RuntimeException('No site node found!', 1697053346);
+ }
+
$fusionRuntime = $this->getFusionRuntime($currentSiteNode);
$fusionRuntime->pushContextArray([
From 526aee3812cafa895d0e84b64f6794fef53d5d7f Mon Sep 17 00:00:00 2001
From: mhsdesign <85400359+mhsdesign@users.noreply.github.com>
Date: Wed, 11 Oct 2023 21:57:32 +0200
Subject: [PATCH 12/15] TASK: Use named arguments for `FindClosestNodeFilter`
---
Neos.Neos/Classes/Domain/Service/NodeSiteResolvingService.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Neos.Neos/Classes/Domain/Service/NodeSiteResolvingService.php b/Neos.Neos/Classes/Domain/Service/NodeSiteResolvingService.php
index 237db1fc8af..5fd9c00d611 100644
--- a/Neos.Neos/Classes/Domain/Service/NodeSiteResolvingService.php
+++ b/Neos.Neos/Classes/Domain/Service/NodeSiteResolvingService.php
@@ -48,7 +48,7 @@ public function findSiteNodeForNodeAddress(
if (!$node) {
return null;
}
- $siteNode = $subgraph->findClosestNode($node->nodeAggregateId, FindClosestNodeFilter::create(NodeTypeNameFactory::NAME_SITE));
+ $siteNode = $subgraph->findClosestNode($node->nodeAggregateId, FindClosestNodeFilter::create(nodeTypeConstraints: NodeTypeNameFactory::NAME_SITE));
return $siteNode;
}
From c2dbecbdfba06f9acb1c6303c9b02c636db62763 Mon Sep 17 00:00:00 2001
From: mhsdesign <85400359+mhsdesign@users.noreply.github.com>
Date: Thu, 12 Oct 2023 13:13:35 +0200
Subject: [PATCH 13/15] TASK: Utilize `Neos.Neos:Site` at various places
---
.../FlowQueryOperations/ParentsOperation.php | 1 -
.../Management/WorkspacesController.php | 3 ++-
.../Domain/Repository/SiteRepository.php | 14 +++++++++++++
.../Classes/Fusion/Helper/SiteHelper.php | 21 ++++++-------------
4 files changed, 22 insertions(+), 17 deletions(-)
diff --git a/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/ParentsOperation.php b/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/ParentsOperation.php
index dcf0d4233c3..2310ee2d59f 100644
--- a/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/ParentsOperation.php
+++ b/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/ParentsOperation.php
@@ -61,7 +61,6 @@ public function canEvaluate($context)
*
* @param FlowQuery $flowQuery the FlowQuery object
* @param array $arguments the arguments for this operation
- * @todo Compare to node type Neos.Neos:Site instead of path once it is available
* @return void
*/
public function evaluate(FlowQuery $flowQuery, array $arguments)
diff --git a/Neos.Neos/Classes/Controller/Module/Management/WorkspacesController.php b/Neos.Neos/Classes/Controller/Module/Management/WorkspacesController.php
index 34ba8e99ea5..682c71b212e 100644
--- a/Neos.Neos/Classes/Controller/Module/Management/WorkspacesController.php
+++ b/Neos.Neos/Classes/Controller/Module/Management/WorkspacesController.php
@@ -798,7 +798,8 @@ protected function computeSiteChanges(Workspace $selectedWorkspace, ContentRepos
if (is_null($documentNode)) {
$documentNode = $ancestor;
}
- // the site node is the last ancestor of type Document
+ }
+ if ($this->getNodeType($ancestor)->isOfType(NodeTypeNameFactory::NAME_SITE)) {
$siteNode = $documentNode;
}
}
diff --git a/Neos.Neos/Classes/Domain/Repository/SiteRepository.php b/Neos.Neos/Classes/Domain/Repository/SiteRepository.php
index 815d9057028..811344b1e52 100644
--- a/Neos.Neos/Classes/Domain/Repository/SiteRepository.php
+++ b/Neos.Neos/Classes/Domain/Repository/SiteRepository.php
@@ -15,6 +15,7 @@
namespace Neos\Neos\Domain\Repository;
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
+use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Persistence\QueryInterface;
use Neos\Flow\Persistence\QueryResultInterface;
@@ -22,6 +23,8 @@
use Neos\Neos\Domain\Model\Site;
use Neos\Neos\Domain\Exception as NeosException;
use Neos\Neos\Domain\Model\SiteNodeName;
+use Neos\Neos\Domain\Service\NodeTypeNameFactory;
+use Neos\Neos\Utility\NodeTypeWithFallbackProvider;
/**
* The Site Repository
@@ -33,6 +36,11 @@
*/
class SiteRepository extends Repository
{
+ use NodeTypeWithFallbackProvider;
+
+ #[Flow\Inject]
+ protected ContentRepositoryRegistry $contentRepositoryRegistry;
+
/**
* @var array
*/
@@ -95,8 +103,14 @@ public function findOneByNodeName(string|SiteNodeName $nodeName): ?Site
return $site;
}
+ /**
+ * @throws \Neos\Neos\Domain\Exception in case the passed $siteNode is not a real site node or no site matches this site node.
+ */
public function findSiteBySiteNode(Node $siteNode): Site
{
+ if (!$this->getNodeType($siteNode)->isOfType(NodeTypeNameFactory::NAME_SITE)) {
+ throw new \Neos\Neos\Domain\Exception(sprintf('Node %s is not a site node. Site nodes must be of type "%s".', $siteNode->nodeAggregateId->value, NodeTypeNameFactory::NAME_SITE), 1697108987);
+ }
if ($siteNode->nodeName === null) {
throw new \Neos\Neos\Domain\Exception(sprintf('Site node "%s" is unnamed', $siteNode->nodeAggregateId->value), 1681286146);
}
diff --git a/Neos.Neos/Classes/Fusion/Helper/SiteHelper.php b/Neos.Neos/Classes/Fusion/Helper/SiteHelper.php
index 05e8a283d5f..c00989affe8 100644
--- a/Neos.Neos/Classes/Fusion/Helper/SiteHelper.php
+++ b/Neos.Neos/Classes/Fusion/Helper/SiteHelper.php
@@ -14,16 +14,11 @@
namespace Neos\Neos\Fusion\Helper;
-use Neos\ContentRepository\Core\Projection\ContentGraph\NodePath;
-use Neos\Neos\Domain\Model\Site;
-use Neos\Neos\Domain\Model\SiteNodeName;
-use Neos\Neos\Domain\Repository\SiteRepository;
-use Neos\Neos\FrontendRouting\NodeAddressFactory;
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
-use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry;
-use Neos\Flow\Annotations as Flow;
use Neos\Eel\ProtectedContextAwareInterface;
-use Neos\Neos\Domain\Exception;
+use Neos\Flow\Annotations as Flow;
+use Neos\Neos\Domain\Model\Site;
+use Neos\Neos\Domain\Repository\SiteRepository;
/**
* Eel helper for accessing the Site object
@@ -36,17 +31,13 @@ class SiteHelper implements ProtectedContextAwareInterface
*/
protected $siteRepository;
- /**
- *
- * @throws Exception
- */
public function findBySiteNode(Node $siteNode): ?Site
{
- if ($siteNode->nodeName === null) {
+ try {
+ return $this->siteRepository->findSiteBySiteNode($siteNode);
+ } catch (\Neos\Neos\Domain\Exception) {
return null;
}
- $siteNodeName = SiteNodeName::fromNodeName($siteNode->nodeName);
- return $this->siteRepository->findOneByNodeName($siteNodeName);
}
/**
From 4c5343818657579fa9c134109a51a559cb46652b Mon Sep 17 00:00:00 2001
From: mhsdesign <85400359+mhsdesign@users.noreply.github.com>
Date: Thu, 12 Oct 2023 23:47:04 +0200
Subject: [PATCH 14/15] FEATURE: Add `SiteNodeUtility::findSiteNodeBySite`
The rather hacky method `findCurrentSiteNode` was refactored and its usage adjusted.
---
.../Domain/Repository/SiteRepository.php | 15 +++-
.../Domain/Service/SiteNodeUtility.php | 90 +++++++++++--------
.../Classes/View/FusionExceptionView.php | 26 +++---
3 files changed, 80 insertions(+), 51 deletions(-)
diff --git a/Neos.Neos/Classes/Domain/Repository/SiteRepository.php b/Neos.Neos/Classes/Domain/Repository/SiteRepository.php
index 811344b1e52..d097041e88d 100644
--- a/Neos.Neos/Classes/Domain/Repository/SiteRepository.php
+++ b/Neos.Neos/Classes/Domain/Repository/SiteRepository.php
@@ -20,10 +20,11 @@
use Neos\Flow\Persistence\QueryInterface;
use Neos\Flow\Persistence\QueryResultInterface;
use Neos\Flow\Persistence\Repository;
-use Neos\Neos\Domain\Model\Site;
use Neos\Neos\Domain\Exception as NeosException;
+use Neos\Neos\Domain\Model\Site;
use Neos\Neos\Domain\Model\SiteNodeName;
use Neos\Neos\Domain\Service\NodeTypeNameFactory;
+use Neos\Neos\Domain\Service\SiteNodeUtility;
use Neos\Neos\Utility\NodeTypeWithFallbackProvider;
/**
@@ -104,6 +105,18 @@ public function findOneByNodeName(string|SiteNodeName $nodeName): ?Site
}
/**
+ * Finds a given site by site node.
+ *
+ * To find the correct site node by its descended child node leverage `findClosestNode`:
+ * ```php
+ * $siteNode = $subgraph->findClosestNode(
+ * $node->nodeAggregateId,
+ * FindClosestNodeFilter::create(nodeTypeConstraints: NodeTypeNameFactory::NAME_SITE)
+ * );
+ * ```
+ *
+ * To resolve the SiteNode by a Site use {@see SiteNodeUtility::findSiteNodeBySite()}
+ *
* @throws \Neos\Neos\Domain\Exception in case the passed $siteNode is not a real site node or no site matches this site node.
*/
public function findSiteBySiteNode(Node $siteNode): Site
diff --git a/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php b/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php
index 1c0ef9a65cd..6d00cc314ae 100644
--- a/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php
+++ b/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php
@@ -16,64 +16,82 @@
namespace Neos\Neos\Domain\Service;
use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint;
-use Neos\ContentRepository\Core\Factory\ContentRepositoryId;
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints;
use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId;
use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry;
use Neos\Flow\Annotations as Flow;
use Neos\Neos\Domain\Model\Site;
-use Neos\Neos\Domain\Repository\DomainRepository;
use Neos\Neos\Domain\Repository\SiteRepository;
+use Neos\Neos\Utility\NodeTypeWithFallbackProvider;
-/** @internal */
#[Flow\Scope('singleton')]
final class SiteNodeUtility
{
+ use NodeTypeWithFallbackProvider;
+
public function __construct(
- private readonly ContentRepositoryRegistry $contentRepositoryRegistry,
- private readonly DomainRepository $domainRepository,
- private readonly SiteRepository $siteRepository
+ private readonly ContentRepositoryRegistry $contentRepositoryRegistry
) {
}
- /** @internal */
- public function findCurrentSiteNode(
- ContentRepositoryId $contentRepositoryId,
+ /**
+ * Find the site node by the neos site entity.
+ *
+ * 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,
+ * DimensionSpacePoint::fromArray([]),
+ * VisibilityConstraints::frontend()
+ * );
+ * ```
+ *
+ * To resolve the Site by a node use {@see SiteRepository::findSiteBySiteNode()}
+ */
+ public function findSiteNodeBySite(
+ Site $site,
ContentStreamId $contentStreamId,
DimensionSpacePoint $dimensionSpacePoint,
VisibilityConstraints $visibilityConstraints
): Node {
- $domain = $this->domainRepository->findOneByActiveRequest();
- $site = $domain
- ? $domain->getSite()
- : $this->siteRepository->findDefault();
+ $contentRepository = $this->contentRepositoryRegistry->get($site->getConfiguration()->contentRepositoryId);
+
+ $subgraph = $contentRepository->getContentGraph()->getSubgraph(
+ $contentStreamId,
+ $dimensionSpacePoint,
+ $visibilityConstraints,
+ );
+
+ $rootNodeAggregate = $contentRepository->getContentGraph()->findRootNodeAggregateByType(
+ $contentStreamId,
+ NodeTypeNameFactory::forSites()
+ );
+ $rootNode = $rootNodeAggregate->getNodeByCoveredDimensionSpacePoint($dimensionSpacePoint);
- if ($site instanceof Site) {
- $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId);
- $subgraph = $contentRepository->getContentGraph()->getSubgraph(
- $contentStreamId,
- $dimensionSpacePoint,
- $visibilityConstraints,
- );
+ $siteNode = $subgraph->findChildNodeConnectedThroughEdgeName(
+ $rootNode->nodeAggregateId,
+ $site->getNodeName()->toNodeName()
+ );
+
+ if (!$siteNode) {
+ throw new \RuntimeException(sprintf(
+ 'No site node found for site "%s"', $site->getNodeName()
+ ), 1697140379);
+ }
- $rootNodeAggregate = $contentRepository->getContentGraph()
- ->findRootNodeAggregateByType(
- $contentStreamId,
- NodeTypeNameFactory::forSites()
- );
- $sitesNode = $subgraph->findNodeById($rootNodeAggregate->nodeAggregateId);
- if ($sitesNode) {
- $siteNode = $subgraph->findChildNodeConnectedThroughEdgeName(
- $sitesNode->nodeAggregateId,
- $site->getNodeName()->toNodeName()
- );
- if ($siteNode instanceof Node) {
- return $siteNode;
- }
- }
+ if (!$this->getNodeType($siteNode)->isOfType(NodeTypeNameFactory::NAME_SITE)) {
+ throw new \RuntimeException(sprintf(
+ 'The site node "%s" (type: "%s") must be of type "%s"', $siteNode->nodeAggregateId->value, $siteNode->nodeTypeName->value, NodeTypeNameFactory::NAME_SITE
+ ), 1697140367);
}
- throw new \RuntimeException('No site node found for domain "' . $domain?->getHostname() . '" and site "' . $site?->getNodeName() . '"');
+ return $siteNode;
}
}
diff --git a/Neos.Neos/Classes/View/FusionExceptionView.php b/Neos.Neos/Classes/View/FusionExceptionView.php
index 6910e8ffe6b..414c5fd80dc 100644
--- a/Neos.Neos/Classes/View/FusionExceptionView.php
+++ b/Neos.Neos/Classes/View/FusionExceptionView.php
@@ -14,10 +14,8 @@
namespace Neos\Neos\View;
-use GuzzleHttp\Psr7\ServerRequest;
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;
@@ -36,10 +34,10 @@
use Neos\Fusion\Core\RuntimeFactory;
use Neos\Fusion\Exception\RuntimeException;
use Neos\Neos\Domain\Model\RenderingMode;
+use Neos\Neos\Domain\Repository\DomainRepository;
use Neos\Neos\Domain\Repository\SiteRepository;
use Neos\Neos\Domain\Service\FusionService;
use Neos\Neos\Domain\Service\SiteNodeUtility;
-use Neos\Neos\Domain\Service\RenderingModeService;
use Neos\Neos\FrontendRouting\SiteDetection\SiteDetectionResult;
class FusionExceptionView extends AbstractView
@@ -90,7 +88,7 @@ class FusionExceptionView extends AbstractView
protected ContentRepositoryRegistry $contentRepositoryRegistry;
#[Flow\Inject]
- protected RenderingModeService $userInterfaceModeService;
+ protected DomainRepository $domainRepository;
/**
* @return string
@@ -117,14 +115,15 @@ public function render()
);
$dimensionSpacePoint = $fusionExceptionViewInternals->getArbitraryDimensionSpacePoint();
- $contentStreamId = $contentRepository->getWorkspaceFinder()->findOneByName(WorkspaceName::forLive())
- ?->currentContentStreamId;
+ $liveWorkspace = $contentRepository->getWorkspaceFinder()->findOneByName(WorkspaceName::forLive());
$currentSiteNode = null;
- if ($contentStreamId instanceof ContentStreamId) {
- $currentSiteNode = $this->siteNodeUtility->findCurrentSiteNode(
- $siteDetectionResult->contentRepositoryId,
- $contentStreamId,
+ if ($liveWorkspace) {
+ $site = $this->siteRepository->findOneByNodeName($siteDetectionResult->siteNodeName);
+
+ $currentSiteNode = $this->siteNodeUtility->findSiteNodeBySite(
+ $site,
+ $liveWorkspace->currentContentStreamId,
$dimensionSpacePoint,
VisibilityConstraints::frontend()
);
@@ -163,13 +162,12 @@ public function render()
try {
$output = $fusionRuntime->render('error');
- $output = $this->extractBodyFromOutput($output);
+ return $this->extractBodyFromOutput($output);
} catch (RuntimeException $exception) {
throw $exception->getPrevious() ?: $exception;
+ } finally {
+ $fusionRuntime->popContext();
}
- $fusionRuntime->popContext();
-
- return $output;
}
return '';
From 404cd2bba0ed15cf507cdfd4afd5a22579484c4d Mon Sep 17 00:00:00 2001
From: mhsdesign <85400359+mhsdesign@users.noreply.github.com>
Date: Fri, 13 Oct 2023 00:06:21 +0200
Subject: [PATCH 15/15] TASK: Fix ci
---
Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php | 9 +++++----
Neos.Neos/Classes/View/FusionExceptionView.php | 5 ++---
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php b/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php
index 6d00cc314ae..9f5e7b9a4ff 100644
--- a/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php
+++ b/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php
@@ -81,14 +81,15 @@ public function findSiteNodeBySite(
);
if (!$siteNode) {
- throw new \RuntimeException(sprintf(
- 'No site node found for site "%s"', $site->getNodeName()
- ), 1697140379);
+ throw new \RuntimeException(sprintf('No site node found for site "%s"', $site->getNodeName()), 1697140379);
}
if (!$this->getNodeType($siteNode)->isOfType(NodeTypeNameFactory::NAME_SITE)) {
throw new \RuntimeException(sprintf(
- 'The site node "%s" (type: "%s") must be of type "%s"', $siteNode->nodeAggregateId->value, $siteNode->nodeTypeName->value, NodeTypeNameFactory::NAME_SITE
+ 'The site node "%s" (type: "%s") must be of type "%s"',
+ $siteNode->nodeAggregateId->value,
+ $siteNode->nodeTypeName->value,
+ NodeTypeNameFactory::NAME_SITE
), 1697140367);
}
diff --git a/Neos.Neos/Classes/View/FusionExceptionView.php b/Neos.Neos/Classes/View/FusionExceptionView.php
index 414c5fd80dc..4406031ca8c 100644
--- a/Neos.Neos/Classes/View/FusionExceptionView.php
+++ b/Neos.Neos/Classes/View/FusionExceptionView.php
@@ -118,9 +118,8 @@ public function render()
$liveWorkspace = $contentRepository->getWorkspaceFinder()->findOneByName(WorkspaceName::forLive());
$currentSiteNode = null;
- if ($liveWorkspace) {
- $site = $this->siteRepository->findOneByNodeName($siteDetectionResult->siteNodeName);
-
+ $site = $this->siteRepository->findOneByNodeName($siteDetectionResult->siteNodeName);
+ if ($liveWorkspace && $site) {
$currentSiteNode = $this->siteNodeUtility->findSiteNodeBySite(
$site,
$liveWorkspace->currentContentStreamId,