Skip to content

Commit

Permalink
BUGFIX: #4351 only check grandchild node constraints for tethered par…
Browse files Browse the repository at this point in the history
…ent-nodes
  • Loading branch information
mhsdesign committed Feb 1, 2024
1 parent bbe5504 commit c708d9a
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
@contentrepository @adapters=DoctrineDBAL,Postgres
Feature: Create node aggregate with node

As a user of the CR I want to define NodeType constraints which will restrict the allowed child nodes
in a specific dimension space point.

Background:
Given using no content dimensions
And using the following node types:
"""yaml
'Neos.ContentRepository.Testing:RestrictedCollection':
constraints:
nodeTypes:
# deny all
'*': false
'Neos.ContentRepository.Testing.ConstrainedChildNodes':
childNodes:
collection:
type: 'Neos.ContentRepository.Testing:RestrictedCollection'
constraints:
nodeTypes:
# only allow this type
'Neos.ContentRepository.Testing:Node': true
'Neos.ContentRepository.Testing:Node': {}
'Neos.ContentRepository.Testing:UglyNode': {}
"""
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"
And the command CreateRootWorkspace is executed with payload:
| Key | Value |
| workspaceName | "live" |
| workspaceTitle | "Live" |
| workspaceDescription | "The live workspace" |
| newContentStreamId | "cs-identifier" |
And the graph projection is fully up to date
And I am in content stream "cs-identifier"
And I am in dimension space point {}
And the command CreateRootNodeAggregateWithNode is executed with payload:
| Key | Value |
| nodeAggregateId | "lady-eleonode-rootford" |
| nodeTypeName | "Neos.ContentRepository:Root" |
And the graph projection is fully up to date

Scenario: Direct allowance of grandchild NodeType constraints overrule deny all on NodeType
# issue https://github.com/neos/neos-development-collection/issues/4351
Given the command CreateNodeAggregateWithNode is executed with payload:
| Key | Value |
| nodeAggregateId | "sir-david-nodenborough" |
| nodeTypeName | "Neos.ContentRepository.Testing.ConstrainedChildNodes" |
| parentNodeAggregateId | "lady-eleonode-rootford" |
| tetheredDescendantNodeAggregateIds | { "collection": "collection-node-id"} |
And the graph projection is fully up to date
When the command CreateNodeAggregateWithNode is executed with payload:
| Key | Value |
| nodeAggregateId | "nody-mc-nodeface" |
| nodeTypeName | "Neos.ContentRepository.Testing:Node" |
| parentNodeAggregateId | "collection-node-id" |
And the graph projection is fully up to date
And I expect the node aggregate "sir-david-nodenborough" to exist
And I expect the node aggregate "collection-node-id" to exist
And I expect this node aggregate to have the child node aggregates ["nody-mc-nodeface"]
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
use Neos\ContentRepository\Core\Infrastructure\Property\PropertyType;
use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate;
use Neos\ContentRepository\Core\SharedModel\Exception\RootNodeAggregateTypeIsAlreadyOccupied;
use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateClassification;
use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId;
use Neos\ContentRepository\Core\SharedModel\Node\NodeName;
use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint;
Expand Down Expand Up @@ -245,40 +246,55 @@ protected function requireConstraintsImposedByAncestorsAreMet(
array $parentNodeAggregateIds,
ContentRepository $contentRepository
): void {
foreach ($parentNodeAggregateIds as $parentNodeAggregateId) {
$parentAggregate = $this->requireProjectedNodeAggregate(
$contentStreamId,
$parentNodeAggregateId,
$contentRepository
);
try {
$parentsNodeType = $this->requireNodeType($parentAggregate->nodeTypeName);
$this->requireNodeTypeConstraintsImposedByParentToBeMet($parentsNodeType, $nodeName, $nodeType);
} catch (NodeTypeNotFound $e) {
// skip constraint check; Once the parent is changed to be of an available type,
// the constraint checks are executed again. See handleChangeNodeAggregateType
}
/** @var array<string, bool> $parentNodeAggregateClassificationsById */
$parentNodeAggregateClassificationsById = [];

foreach ($parentNodeAggregateIds as $parentNodeAggregateId) {
foreach (
$contentRepository->getContentGraph()->findParentNodeAggregates(
$contentStreamId,
$parentNodeAggregateId
) as $grandParentNodeAggregate
) {
/* @var $grandParentNodeAggregate NodeAggregate */
$parentAggregate = $this->requireProjectedNodeAggregate(
$contentStreamId,
$parentNodeAggregateId,
$contentRepository
);
try {
$grandParentsNodeType = $this->requireNodeType($grandParentNodeAggregate->nodeTypeName);
$parentNodeAggregateClassificationsById[$parentNodeAggregateId->value] = $parentAggregate->classification;
$this->requireNodeTypeConstraintsImposedByGrandparentToBeMet(
$grandParentsNodeType,
$parentAggregate->nodeName,
$nodeType
);
} catch (NodeTypeNotFound $e) {
// skip constraint check; Once the grand parent is changed to be of an available type,
// skip constraint check; Once the grandparent is changed to be of an available type,
// the constraint checks are executed again. See handleChangeNodeAggregateType
}
}
}

if (!in_array(NodeAggregateClassification::CLASSIFICATION_REGULAR, $parentNodeAggregateClassificationsById, true)) {
// all parent node aggregates are tethered, so we don't run the direct constraint checks
return;
}

foreach ($parentNodeAggregateIds as $parentNodeAggregateId) {
$parentAggregate = $this->requireProjectedNodeAggregate(
$contentStreamId,
$parentNodeAggregateId,
$contentRepository
);
try {
$parentsNodeType = $this->requireNodeType($parentAggregate->nodeTypeName);
$this->requireNodeTypeConstraintsImposedByParentToBeMet($parentsNodeType, $nodeName, $nodeType);
} catch (NodeTypeNotFound $e) {
// skip constraint check; Once the parent is changed to be of an available type,
// the constraint checks are executed again. See handleChangeNodeAggregateType
}
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ final class NodeAggregateCommandHandler implements CommandHandlerInterface
protected PropertyConverter $propertyConverter;

/**
* can be disabled in {@see NodeAggregateCommandHandler::withoutAnchestorNodeTypeConstraintChecks()}
* can be disabled in {@see NodeAggregateCommandHandler::withoutAncestorNodeTypeConstraintChecks()}
*/
private bool $ancestorNodeTypeConstraintChecksEnabled = true;

Expand Down

0 comments on commit c708d9a

Please sign in to comment.