Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BUGFIX: Handle nodes with missing UriPathSegments in uriPathProjection #5412

Open
wants to merge 4 commits into
base: 9.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
use Neos\ContentRepository\Core\Projection\ProjectionStatus;
use Neos\ContentRepository\Core\Projection\WithMarkStaleInterface;
use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId;
use Neos\ContentRepository\Core\SharedModel\Node\PropertyName;
use Neos\EventStore\Model\EventEnvelope;
use Neos\Neos\Domain\Model\SiteNodeName;
use Neos\Neos\FrontendRouting\Exception\NodeNotFoundException;
Expand Down Expand Up @@ -209,7 +210,7 @@ private function whenNodeAggregateWithNodeWasCreated(NodeAggregateWithNodeWasCre
}

$propertyValues = $event->initialPropertyValues->getPlainValues();
$uriPathSegment = $propertyValues['uriPathSegment'] ?? '';
$uriPathSegment = ($propertyValues['uriPathSegment'] ?? '') ?: $event->nodeAggregateId->value;

$shortcutTarget = null;
if ($documentTypeClassification === DocumentTypeClassification::CLASSIFICATION_SHORTCUT) {
Expand Down Expand Up @@ -494,8 +495,10 @@ private function whenNodePropertiesWereSet(NodePropertiesWereSet $event, EventEn
return;
}
$newPropertyValues = $event->propertyValues->getPlainValues();
$unsetPropertyNames = array_map(fn(PropertyName $propertyName) => $propertyName->value, iterator_to_array($event->propertiesToUnset->getIterator()));
if (
!isset($newPropertyValues['uriPathSegment'])
&& !in_array('uriPathSegment', $unsetPropertyNames)
&& !isset($newPropertyValues['targetMode'])
&& !isset($newPropertyValues['target'])
) {
Expand Down Expand Up @@ -529,12 +532,12 @@ private function whenNodePropertiesWereSet(NodePropertiesWereSet $event, EventEn
);
}

if (!isset($newPropertyValues['uriPathSegment'])) {
if (!isset($newPropertyValues['uriPathSegment']) && !in_array('uriPathSegment', $unsetPropertyNames)) {
continue;
}
$oldUriPath = $node->getUriPath();
$uriPathSegments = explode('/', $oldUriPath);
$uriPathSegments[array_key_last($uriPathSegments)] = $newPropertyValues['uriPathSegment'];
$uriPathSegments[array_key_last($uriPathSegments)] = ($newPropertyValues['uriPathSegment'] ?? '') ?: $event->nodeAggregateId;
$newUriPath = implode('/', $uriPathSegments);

$this->updateNodeQuery(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
@flowEntities @contentrepository
Feature: Routing functionality if path segments are missing like during tethered node creation

Background:
Given using no content dimensions
And using the following node types:
"""yaml
'Neos.Neos:Sites':
superTypes:
'Neos.ContentRepository:Root': true
'Neos.Neos:Document': {}
'Neos.Neos:Content': {}
'Neos.Neos:Test.Routing.Page':
superTypes:
'Neos.Neos:Document': true
properties:
uriPathSegment:
type: string
'Neos.Neos:Test.Routing.Content':
superTypes:
'Neos.Neos:Content': true
properties:
uriPathSegment:
type: string
"""
And using identifier "default", I define a content repository
And I am in content repository "default"
And I am user identified by "initiating-user-identifier"

When the command CreateRootWorkspace is executed with payload:
| Key | Value |
| workspaceName | "live" |
| newContentStreamId | "cs-identifier" |
And I am in workspace "live" and dimension space point {}
And the command CreateRootNodeAggregateWithNode is executed with payload:
| Key | Value |
| nodeAggregateId | "lady-eleonode-rootford" |
| nodeTypeName | "Neos.Neos:Sites" |

# lady-eleonode-rootford
# shernode-homes
# sir-david-nodenborough
# duke-of-contentshire (content node)
# earl-o-documentbourgh
# nody-mc-nodeface
#
And the following CreateNodeAggregateWithNode commands are executed:
| nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | nodeName |
| shernode-homes | lady-eleonode-rootford | Neos.Neos:Test.Routing.Page | {} | node1 |
| sir-david-nodenborough | shernode-homes | Neos.Neos:Test.Routing.Page | {} | node2 |
| duke-of-contentshire | sir-david-nodenborough | Neos.Neos:Test.Routing.Content | {} | node3 |
| earl-o-documentbourgh | sir-david-nodenborough | Neos.Neos:Test.Routing.Page | {} | node4 |
| nody-mc-nodeface | shernode-homes | Neos.Neos:Test.Routing.Page | {} | node5 |
And A site exists for node name "node1"
And the sites configuration is:
"""yaml
Neos:
Neos:
sites:
'node1':
preset: 'default'
uriPathSuffix: ''
contentDimensions:
resolver:
factoryClassName: Neos\Neos\FrontendRouting\DimensionResolution\Resolver\NoopResolverFactory
"""
Scenario: Match homepage URL
When I am on URL "/"
Then the matched node should be "shernode-homes" in content stream "cs-identifier" and dimension "{}"

Scenario: Resolve nodes correctly from homepage
When I am on URL "/"
Then the node "shernode-homes" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/"
And the node "sir-david-nodenborough" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/sir-david-nodenborough"
And the node "earl-o-documentbourgh" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/sir-david-nodenborough/earl-o-documentbourgh"

Scenario: Match node lower in the tree
When I am on URL "/sir-david-nodenborough/earl-o-documentbourgh"
Then the matched node should be "earl-o-documentbourgh" in content stream "cs-identifier" and dimension "{}"

Scenario: Resolve from node lower in the tree
When I am on URL "/sir-david-nodenborough/earl-o-documentbourgh"
Then the node "shernode-homes" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/"
And the node "sir-david-nodenborough" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/sir-david-nodenborough"
And the node "earl-o-documentbourgh" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/sir-david-nodenborough/earl-o-documentbourgh"

Scenario: Add uri path segment on first level
When the command SetNodeProperties is executed with payload:
| Key | Value |
| nodeAggregateId | "sir-david-nodenborough" |
| originDimensionSpacePoint | {} |
| propertyValues | {"uriPathSegment": "david-nodenborough-updated"} |
And I am on URL "/"
Then the node "sir-david-nodenborough" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/david-nodenborough-updated"
And the node "earl-o-documentbourgh" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/david-nodenborough-updated/earl-o-documentbourgh"

Scenario: Add uri path segment on second level
When the command SetNodeProperties is executed with payload:
| Key | Value |
| nodeAggregateId | "earl-o-documentbourgh" |
| originDimensionSpacePoint | {} |
| propertyValues | {"uriPathSegment": "earl-documentbourgh-updated"} |
And I am on URL "/"
Then the node "earl-o-documentbourgh" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/sir-david-nodenborough/earl-documentbourgh-updated"

Scenario: Add empty uri path segment on first level
When the command SetNodeProperties is executed with payload:
| Key | Value |
| nodeAggregateId | "sir-david-nodenborough" |
| originDimensionSpacePoint | {} |
| propertyValues | {"uriPathSegment": ""} |
And I am on URL "/"
Then the node "sir-david-nodenborough" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/sir-david-nodenborough"
And the node "earl-o-documentbourgh" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/sir-david-nodenborough/earl-o-documentbourgh"

Scenario: Uri path segment is unset after having been set before
When the command SetNodeProperties is executed with payload:
| Key | Value |
| nodeAggregateId | "sir-david-nodenborough" |
| originDimensionSpacePoint | {} |
| propertyValues | {"uriPathSegment": "david-nodenborough-updated"} |
And I am on URL "/"
Then the node "sir-david-nodenborough" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/david-nodenborough-updated"
And the node "earl-o-documentbourgh" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/david-nodenborough-updated/earl-o-documentbourgh"
When the command SetNodeProperties is executed with payload:
| Key | Value |
| nodeAggregateId | "sir-david-nodenborough" |
| originDimensionSpacePoint | {} |
| propertyValues | {"uriPathSegment": null} |
Then the node "sir-david-nodenborough" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/sir-david-nodenborough"
And the node "earl-o-documentbourgh" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/sir-david-nodenborough/earl-o-documentbourgh"

Scenario: Uri path segment is set to empty string having been set before
When the command SetNodeProperties is executed with payload:
| Key | Value |
| nodeAggregateId | "sir-david-nodenborough" |
| originDimensionSpacePoint | {} |
| propertyValues | {"uriPathSegment": "david-nodenborough-updated"} |
And I am on URL "/"
Then the node "sir-david-nodenborough" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/david-nodenborough-updated"
And the node "earl-o-documentbourgh" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/david-nodenborough-updated/earl-o-documentbourgh"
When the command SetNodeProperties is executed with payload:
| Key | Value |
| nodeAggregateId | "sir-david-nodenborough" |
| originDimensionSpacePoint | {} |
| propertyValues | {"uriPathSegment": ""} |
Then the node "sir-david-nodenborough" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/sir-david-nodenborough"
And the node "earl-o-documentbourgh" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/sir-david-nodenborough/earl-o-documentbourgh"
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Feature: Test cases for node creation edge cases
| nodeTypeName | "Neos.Neos:Site" |
| parentNodeAggregateId | "lady-eleonode-rootford" |
| originDimensionSpacePoint | {"example":"source"} |
| nodeName | "site" |
And the following CreateNodeAggregateWithNode commands are executed:
| nodeAggregateId | nodeName | parentNodeAggregateId | succeedingSiblingNodeAggregateId | nodeTypeName | initialPropertyValues |
# Let's prepare some siblings to check orderings. Also, everything gets better with siblings.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Feature: Test cases for node variation edge cases
| nodeTypeName | "Neos.Neos:Site" |
| parentNodeAggregateId | "lady-eleonode-rootford" |
| originDimensionSpacePoint | {"example":"source"} |
| nodeName | "site" |
And the command CreateNodeVariant is executed with payload:
| Key | Value |
| nodeAggregateId | "shernode-homes" |
Expand Down Expand Up @@ -135,6 +136,7 @@ Feature: Test cases for node variation edge cases
| nodeTypeName | "Neos.Neos:Site" |
| parentNodeAggregateId | "lady-eleonode-rootford" |
| originDimensionSpacePoint | {"example":"rootGeneral"} |
| nodeName | "site" |
And the following CreateNodeAggregateWithNode commands are executed:
| nodeAggregateId | originDimensionSpacePoint | nodeName | parentNodeAggregateId | succeedingSiblingNodeAggregateId | nodeTypeName | initialPropertyValues |
# Let's create some siblings, both in source and target, to check ordering
Expand Down Expand Up @@ -225,6 +227,7 @@ Feature: Test cases for node variation edge cases
| nodeTypeName | "Neos.Neos:Site" |
| parentNodeAggregateId | "lady-eleonode-rootford" |
| originDimensionSpacePoint | {"example":"source"} |
| nodeName | "site" |
And the following CreateNodeAggregateWithNode commands are executed:
| nodeAggregateId | nodeName | parentNodeAggregateId | succeedingSiblingNodeAggregateId | nodeTypeName | initialPropertyValues |
# Let's create our test subject...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Feature: Test cases for partial publish to live and uri path generation
| nodeTypeName | "Neos.Neos:Site" |
| parentNodeAggregateId | "lady-eleonode-rootford" |
| originDimensionSpacePoint | {"example":"source"} |
| nodeName | "site" |
And the command CreateWorkspace is executed with payload:
| Key | Value |
| workspaceName | "myworkspace" |
Expand All @@ -49,7 +50,7 @@ Feature: Test cases for partial publish to live and uri path generation
| nodeTypeName | "Neos.Neos:Document" |
| parentNodeAggregateId | "shernode-homes" |
| originDimensionSpacePoint | {"example":"source"} |
| properties | {"uriPathSegment": "just"}|
| initialPropertyValues | {"uriPathSegment": "just"}|
| workspaceName | "myworkspace" |
And the command PublishIndividualNodesFromWorkspace is executed with payload:
| Key | Value |
Expand All @@ -65,4 +66,4 @@ Feature: Test cases for partial publish to live and uri path generation
| "65901ded4f068dac14ad0dce4f459b29" | "" | "lady-eleonode-rootford" | "lady-eleonode-rootford" | null | null | null | "Neos.Neos:Sites" |
| "fbe53ddc3305685fbb4dbf529f283a0e" | "" | "lady-eleonode-rootford" | "lady-eleonode-rootford" | null | null | null | "Neos.Neos:Sites" |
| "65901ded4f068dac14ad0dce4f459b29" | "" | "lady-eleonode-rootford/shernode-homes" | "shernode-homes" | "lady-eleonode-rootford" | null | null | "Neos.Neos:Site" |
| "65901ded4f068dac14ad0dce4f459b29" | "" | "lady-eleonode-rootford/shernode-homes/justsomepage" | "justsomepage" | "shernode-homes" | null | null | "Neos.Neos:Document" |
| "65901ded4f068dac14ad0dce4f459b29" | "just" | "lady-eleonode-rootford/shernode-homes/justsomepage" | "justsomepage" | "shernode-homes" | null | null | "Neos.Neos:Document" |
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Feature: Basic routing functionality (match & resolve nodes with unknown types)
| nodeTypeName | "Neos.Neos:Test.Routing.Page" |
| parentNodeAggregateId | "lady-eleonode-rootford" |
| nodeAggregateClassification | "regular" |
| nodeName | "site" |
And the event NodeAggregateWithNodeWasCreated was published with payload:
| Key | Value |
| workspaceName | "live" |
Expand Down
Loading