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

!!! TASK: Followup #4520 Introduce NodeType::tetheredNodeTypeDefinitions #4906

Merged
merged 13 commits into from May 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -175,10 +175,9 @@ protected function requireRootNodeTypeToBeUnoccupied(
*/
protected function requireTetheredDescendantNodeTypesToExist(NodeType $nodeType): void
{
// this getter throws if any of the child nodeTypes doesnt exist!
$tetheredNodeTypes = $this->getNodeTypeManager()->getTetheredNodesConfigurationForNodeType($nodeType);
foreach ($tetheredNodeTypes as $tetheredNodeType) {
$this->requireTetheredDescendantNodeTypesToExist($tetheredNodeType);
foreach ($nodeType->tetheredNodeTypeDefinitions as $tetheredNodeTypeDefinition) {
$nodeType = $this->requireNodeType($tetheredNodeTypeDefinition->nodeTypeName);
$this->requireTetheredDescendantNodeTypesToExist($nodeType);
}
}

Expand All @@ -188,7 +187,8 @@ protected function requireTetheredDescendantNodeTypesToExist(NodeType $nodeType)
*/
protected function requireTetheredDescendantNodeTypesToNotBeOfTypeRoot(NodeType $nodeType): void
{
foreach ($this->getNodeTypeManager()->getTetheredNodesConfigurationForNodeType($nodeType) as $tetheredChildNodeType) {
foreach ($nodeType->tetheredNodeTypeDefinitions as $tetheredNodeTypeDefinition) {
$tetheredChildNodeType = $this->requireNodeType($tetheredNodeTypeDefinition->nodeTypeName);
if ($tetheredChildNodeType->isOfType(NodeTypeName::ROOT_NODE_TYPE_NAME)) {
throw new NodeTypeIsOfTypeRoot(
'Node type "' . $nodeType->name->value . '" for tethered descendant is of type root.',
Expand Down Expand Up @@ -222,7 +222,7 @@ protected function requireNodeTypeToDeclareReference(NodeTypeName $nodeTypeName,
protected function requireNodeTypeNotToDeclareTetheredChildNodeName(NodeTypeName $nodeTypeName, NodeName $nodeName): void
{
$nodeType = $this->requireNodeType($nodeTypeName);
if ($nodeType->hasTetheredNode($nodeName)) {
if ($nodeType->tetheredNodeTypeDefinitions->contain($nodeName)) {
throw new NodeNameIsAlreadyCovered(
'Node name "' . $nodeName->value . '" is reserved for a tethered child of parent node aggregate of type "'
. $nodeTypeName->value . '".'
Expand Down Expand Up @@ -368,8 +368,8 @@ protected function areNodeTypeConstraintsImposedByGrandparentValid(
NodeType $nodeType
): bool {
return !($parentNodeName
&& $grandParentsNodeType->hasTetheredNode($parentNodeName)
&& !$this->getNodeTypeManager()->isNodeTypeAllowedAsChildToTetheredNode($grandParentsNodeType, $parentNodeName, $nodeType));
&& $grandParentsNodeType->tetheredNodeTypeDefinitions->contain($parentNodeName)
&& !$this->getNodeTypeManager()->isNodeTypeAllowedAsChildToTetheredNode($grandParentsNodeType->name, $parentNodeName, $nodeType->name));
}

/**
Expand Down
Expand Up @@ -20,15 +20,13 @@
use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValues;
use Neos\ContentRepository\Core\Feature\NodeVariation\Event\NodePeerVariantWasCreated;
use Neos\ContentRepository\Core\Infrastructure\Property\PropertyConverter;
use Neos\ContentRepository\Core\NodeType\NodeType;
use Neos\ContentRepository\Core\NodeType\NodeTypeName;
use Neos\ContentRepository\Core\NodeType\TetheredNodeTypeDefinition;
use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphInterface;
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate;
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\SharedModel\Workspace\ContentStreamId;

/**
* @internal implementation details of command handlers
Expand Down Expand Up @@ -58,19 +56,23 @@ protected function createEventsForMissingTetheredNode(
ContentGraphInterface $contentGraph,
NodeAggregate $parentNodeAggregate,
OriginDimensionSpacePoint $originDimensionSpacePoint,
NodeName $tetheredNodeName,
?NodeAggregateId $tetheredNodeAggregateId,
NodeType $expectedTetheredNodeType
TetheredNodeTypeDefinition $tetheredNodeTypeDefinition,
?NodeAggregateId $tetheredNodeAggregateId
): Events {
$childNodeAggregate = $contentGraph->findChildNodeAggregateByName(
$parentNodeAggregate->nodeAggregateId,
$tetheredNodeName
$tetheredNodeTypeDefinition->name
);

$expectedTetheredNodeType = $this->nodeTypeManager->getNodeType($tetheredNodeTypeDefinition->nodeTypeName);
$defaultProperties = $expectedTetheredNodeType
? SerializedPropertyValues::defaultFromNodeType($expectedTetheredNodeType, $this->getPropertyConverter())
: SerializedPropertyValues::createEmpty();

if ($childNodeAggregate === null) {
// there is no tethered child node aggregate already; let's create it!
$nodeType = $this->nodeTypeManager->requireNodeType($parentNodeAggregate->nodeTypeName);
if ($nodeType->isOfType(NodeTypeName::ROOT_NODE_TYPE_NAME)) {
$nodeType = $this->nodeTypeManager->getNodeType($parentNodeAggregate->nodeTypeName);
if ($nodeType?->isOfType(NodeTypeName::ROOT_NODE_TYPE_NAME)) {
$events = [];
$tetheredNodeAggregateId = $tetheredNodeAggregateId ?: NodeAggregateId::create();
// we create in one origin DSP and vary in the others
Expand All @@ -91,14 +93,14 @@ protected function createEventsForMissingTetheredNode(
$events[] = new NodeAggregateWithNodeWasCreated(
$parentNodeAggregate->contentStreamId,
$tetheredNodeAggregateId,
$expectedTetheredNodeType->name,
$tetheredNodeTypeDefinition->nodeTypeName,
$rootGeneralizationOrigin,
InterdimensionalSiblings::fromDimensionSpacePointSetWithoutSucceedingSiblings(
$this->getInterDimensionalVariationGraph()->getSpecializationSet($rootGeneralization)
),
$parentNodeAggregate->nodeAggregateId,
$tetheredNodeName,
SerializedPropertyValues::defaultFromNodeType($expectedTetheredNodeType, $this->getPropertyConverter()),
$tetheredNodeTypeDefinition->name,
$defaultProperties,
NodeAggregateClassification::CLASSIFICATION_TETHERED,
);
$creationOriginDimensionSpacePoint = $rootGeneralizationOrigin;
Expand All @@ -110,14 +112,14 @@ protected function createEventsForMissingTetheredNode(
new NodeAggregateWithNodeWasCreated(
$parentNodeAggregate->contentStreamId,
$tetheredNodeAggregateId ?: NodeAggregateId::create(),
$expectedTetheredNodeType->name,
$tetheredNodeTypeDefinition->nodeTypeName,
$originDimensionSpacePoint,
InterdimensionalSiblings::fromDimensionSpacePointSetWithoutSucceedingSiblings(
$parentNodeAggregate->getCoverageByOccupant($originDimensionSpacePoint)
),
$parentNodeAggregate->nodeAggregateId,
$tetheredNodeName,
SerializedPropertyValues::defaultFromNodeType($expectedTetheredNodeType, $this->getPropertyConverter()),
$tetheredNodeTypeDefinition->name,
$defaultProperties,
NodeAggregateClassification::CLASSIFICATION_TETHERED,
)
);
Expand Down
Expand Up @@ -18,6 +18,7 @@
use Neos\ContentRepository\Core\NodeType\NodeTypeManager;
use Neos\ContentRepository\Core\NodeType\NodeTypeName;
use Neos\ContentRepository\Core\Projection\ContentGraph\NodePath;
use Neos\ContentRepository\Core\SharedModel\Exception\NodeTypeNotFound;
use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId;

/**
Expand Down Expand Up @@ -128,12 +129,16 @@ private static function createNodeAggregateIdsForNodeType(
?string $pathPrefix = null
): array {
$nodeAggregateIds = [];
foreach ($nodeTypeManager->getTetheredNodesConfigurationForNodeType($nodeTypeManager->requireNodeType($nodeTypeName)) as $nodeName => $childNodeType) {
$path = $pathPrefix ? $pathPrefix . '/' . $nodeName : $nodeName;
$nodeType = $nodeTypeManager->getNodeType($nodeTypeName);
if (!$nodeType) {
throw new NodeTypeNotFound(sprintf('Cannot build NodeAggregateIdsByNodePaths because NodeType %s does not exist.', $nodeTypeName->value), 1715711379);
}
foreach ($nodeType->tetheredNodeTypeDefinitions as $tetheredNodeTypeDefinition) {
$path = $pathPrefix ? $pathPrefix . '/' . $tetheredNodeTypeDefinition->name->value : $tetheredNodeTypeDefinition->name->value;
$nodeAggregateIds[$path] = NodeAggregateId::create();
$nodeAggregateIds = array_merge(
$nodeAggregateIds,
self::createNodeAggregateIdsForNodeType($childNodeType->name, $nodeTypeManager, $path)
self::createNodeAggregateIdsForNodeType($tetheredNodeTypeDefinition->nodeTypeName, $nodeTypeManager, $path)
);
}

Expand Down
Expand Up @@ -264,24 +264,26 @@ private function handleTetheredChildNodes(
?NodePath $nodePath
): Events {
$events = [];
foreach ($this->getNodeTypeManager()->getTetheredNodesConfigurationForNodeType($nodeType) as $rawNodeName => $childNodeType) {
assert($childNodeType instanceof NodeType);
$nodeName = NodeName::fromString($rawNodeName);
foreach ($nodeType->tetheredNodeTypeDefinitions as $tetheredNodeTypeDefinition) {
$childNodeType = $this->requireNodeType($tetheredNodeTypeDefinition->nodeTypeName);
$childNodePath = $nodePath
? $nodePath->appendPathSegment($nodeName)
: NodePath::fromString($nodeName->value);
? $nodePath->appendPathSegment($tetheredNodeTypeDefinition->name)
: NodePath::fromString($tetheredNodeTypeDefinition->name->value);
$childNodeAggregateId = $nodeAggregateIds->getNodeAggregateId($childNodePath)
?? NodeAggregateId::create();
$initialPropertyValues = SerializedPropertyValues::defaultFromNodeType($childNodeType, $this->getPropertyConverter());
$initialPropertyValues = SerializedPropertyValues::defaultFromNodeType(
$childNodeType,
$this->getPropertyConverter()
);

$events[] = new NodeAggregateWithNodeWasCreated(
$contentGraph->getContentStreamId(),
$childNodeAggregateId,
$childNodeType->name,
$tetheredNodeTypeDefinition->nodeTypeName,
$command->originDimensionSpacePoint,
InterdimensionalSiblings::fromDimensionSpacePointSetWithoutSucceedingSiblings($coveredDimensionSpacePoints),
$parentNodeAggregateId,
$nodeName,
$tetheredNodeTypeDefinition->name,
$initialPropertyValues,
NodeAggregateClassification::CLASSIFICATION_TETHERED,
);
Expand Down
Expand Up @@ -28,6 +28,7 @@
use Neos\ContentRepository\Core\Feature\NodeTypeChange\Event\NodeAggregateTypeWasChanged;
use Neos\ContentRepository\Core\NodeType\NodeType;
use Neos\ContentRepository\Core\NodeType\NodeTypeManager;
use Neos\ContentRepository\Core\NodeType\TetheredNodeTypeDefinition;
use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphInterface;
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate;
Expand Down Expand Up @@ -88,9 +89,8 @@ abstract protected function createEventsForMissingTetheredNode(
ContentGraphInterface $contentGraph,
NodeAggregate $parentNodeAggregate,
OriginDimensionSpacePoint $originDimensionSpacePoint,
NodeName $tetheredNodeName,
NodeAggregateId $tetheredNodeAggregateId,
NodeType $expectedTetheredNodeType
TetheredNodeTypeDefinition $tetheredNodeTypeDefinition,
NodeAggregateId $tetheredNodeAggregateId
): Events;

/**
Expand Down Expand Up @@ -147,7 +147,7 @@ private function handleChangeNodeAggregateType(
* Preparation - make the command fully deterministic in case of rebase
**************/
$descendantNodeAggregateIds = $command->tetheredDescendantNodeAggregateIds->completeForNodeOfType(
$newNodeType->name,
$command->newNodeTypeName,
$this->nodeTypeManager
);
// Write the auto-created descendant node aggregate ids back to the command;
Expand Down Expand Up @@ -180,31 +180,27 @@ private function handleChangeNodeAggregateType(
}

// new tethered child nodes
$expectedTetheredNodes = $this->getNodeTypeManager()->getTetheredNodesConfigurationForNodeType($newNodeType);
foreach ($nodeAggregate->getNodes() as $node) {
assert($node instanceof Node);
foreach ($expectedTetheredNodes as $serializedTetheredNodeName => $expectedTetheredNodeType) {
$tetheredNodeName = NodeName::fromString($serializedTetheredNodeName);

foreach ($newNodeType->tetheredNodeTypeDefinitions as $tetheredNodeTypeDefinition) {
$tetheredNode = $contentGraph->getSubgraph(
$node->originDimensionSpacePoint->toDimensionSpacePoint(),
VisibilityConstraints::withoutRestrictions()
)->findNodeByPath(
$tetheredNodeName,
$tetheredNodeTypeDefinition->name,
$node->nodeAggregateId,
);

if ($tetheredNode === null) {
$tetheredNodeAggregateId = $command->tetheredDescendantNodeAggregateIds
->getNodeAggregateId(NodePath::fromString($tetheredNodeName->value))
->getNodeAggregateId(NodePath::fromNodeNames($tetheredNodeTypeDefinition->name))
?: NodeAggregateId::create();
array_push($events, ...iterator_to_array($this->createEventsForMissingTetheredNode(
$contentGraph,
$nodeAggregate,
$node->originDimensionSpacePoint,
$tetheredNodeName,
$tetheredNodeAggregateId,
$expectedTetheredNodeType
$tetheredNodeTypeDefinition,
$tetheredNodeAggregateId
)));
}
}
Expand Down Expand Up @@ -348,15 +344,13 @@ private function deleteObsoleteTetheredNodesWhenChangingNodeType(
NodeAggregate $nodeAggregate,
NodeType $newNodeType
): Events {
$expectedTetheredNodes = $this->getNodeTypeManager()->getTetheredNodesConfigurationForNodeType($newNodeType);

$events = [];
// find disallowed tethered nodes
$tetheredNodeAggregates = $contentGraph->findTetheredChildNodeAggregates($nodeAggregate->nodeAggregateId);

foreach ($tetheredNodeAggregates as $tetheredNodeAggregate) {
/* @var $tetheredNodeAggregate NodeAggregate */
if ($tetheredNodeAggregate->nodeName !== null && !isset($expectedTetheredNodes[$tetheredNodeAggregate->nodeName->value])) {
if ($tetheredNodeAggregate->nodeName !== null && !$newNodeType->tetheredNodeTypeDefinitions->contain($tetheredNodeAggregate->nodeName)) {
// this aggregate (or parts thereof) are DISALLOWED according to constraints.
// We now need to find out which edges we need to remove,
$dimensionSpacePointsToBeRemoved = $this->findDimensionSpacePointsConnectingParentAndChildAggregate(
Expand Down
Expand Up @@ -191,24 +191,23 @@ private function handleTetheredRootChildNodes(
?NodePath $nodePath
): Events {
$events = [];
foreach ($this->getNodeTypeManager()->getTetheredNodesConfigurationForNodeType($nodeType) as $rawNodeName => $childNodeType) {
assert($childNodeType instanceof NodeType);
$nodeName = NodeName::fromString($rawNodeName);
foreach ($nodeType->tetheredNodeTypeDefinitions as $tetheredNodeTypeDefinition) {
$childNodeType = $this->requireNodeType($tetheredNodeTypeDefinition->nodeTypeName);
$childNodePath = $nodePath
? $nodePath->appendPathSegment($nodeName)
: NodePath::fromString($nodeName->value);
? $nodePath->appendPathSegment($tetheredNodeTypeDefinition->name)
: NodePath::fromNodeNames($tetheredNodeTypeDefinition->name);
$childNodeAggregateId = $nodeAggregateIdsByNodePath->getNodeAggregateId($childNodePath)
?? NodeAggregateId::create();
$initialPropertyValues = SerializedPropertyValues::defaultFromNodeType($childNodeType, $this->getPropertyConverter());

$events[] = $this->createTetheredWithNodeForRoot(
$contentStreamId,
$childNodeAggregateId,
$childNodeType->name,
$tetheredNodeTypeDefinition->nodeTypeName,
$originDimensionSpacePoint,
$coveredDimensionSpacePoints,
$parentNodeAggregateId,
$nodeName,
$tetheredNodeTypeDefinition->name,
$initialPropertyValues
);

Expand Down

This file was deleted.