From dbab533d99737ba9a01177b425ec96ee4123d3c2 Mon Sep 17 00:00:00 2001 From: bwaidelich Date: Fri, 8 Sep 2023 11:05:14 +0200 Subject: [PATCH 1/5] WIP: FEATURE: Overhaul command constructors Related: #4375 --- .../Command/CreateNodeAggregateWithNode.php | 79 +++++++++--------- ...gregateWithNodeAndSerializedProperties.php | 83 ++++++++----------- .../Dto/NodeAggregateIdsByNodePaths.php | 5 ++ Classes/Feature/NodeCreation/NodeCreation.php | 8 +- .../Dto/PropertyValuesToWrite.php | 5 ++ .../Dto/SerializedPropertyValues.php | 5 ++ .../NodeMove/Command/MoveNodeAggregate.php | 60 ++++++-------- .../ContentGraph/PropertyCollectionTest.php | 6 +- 8 files changed, 118 insertions(+), 133 deletions(-) diff --git a/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNode.php b/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNode.php index 081b877b..afd60352 100644 --- a/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNode.php +++ b/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNode.php @@ -36,53 +36,33 @@ final class CreateNodeAggregateWithNode implements CommandInterface { /** - * Node aggregate id of the node's succeeding sibling (optional) - * If not given, the node will be added as the parent's first child + * @param OriginDimensionSpacePoint $originDimensionSpacePoint Origin of the new node in the dimension space. Will also be used to calculate a set of dimension points where the new node will cover from the configured specializations. + * @param PropertyValuesToWrite $initialPropertyValues The node's initial property values. Will be merged over the node type's default property values + * @param NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds Predefined aggregate ids of tethered child nodes per path. For any tethered node that has no matching entry in this set, the node aggregate id is generated randomly. Since tethered nodes may have tethered child nodes themselves, this works for multiple levels + * @param NodeAggregateId|null $succeedingSiblingNodeAggregateId Node aggregate id of the node's succeeding sibling (optional). If not given, the node will be added as the parent's first child + * @param NodeName|null $nodeName The node's optional name. Set if there is a meaningful relation to its parent that should be named. */ - public readonly ?NodeAggregateId $succeedingSiblingNodeAggregateId; - - /** - * The node's optional name. Set if there is a meaningful relation to its parent that should be named. - */ - public readonly ?NodeName $nodeName; - - /** - * The node's initial property values. Will be merged over the node type's default property values - */ - public readonly PropertyValuesToWrite $initialPropertyValues; - - /** - * NodeAggregateIds for tethered descendants (optional). - * - * If the given node type declares tethered child nodes, you may predefine their node aggregate ids - * using this assignment registry. - * Since tethered child nodes may have tethered child nodes themselves, - * this registry is indexed using relative node paths to the node to create in the first place. - */ - public readonly NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds; - - // TODO: CREATE METHODS FÜR ALLE COMMANDS - public function __construct( + private function __construct( public readonly ContentStreamId $contentStreamId, public readonly NodeAggregateId $nodeAggregateId, public readonly NodeTypeName $nodeTypeName, - /** - * Origin of the new node in the dimension space. - * Will also be used to calculate a set of dimension points where the new node will cover - * from the configured specializations. - */ public readonly OriginDimensionSpacePoint $originDimensionSpacePoint, public readonly NodeAggregateId $parentNodeAggregateId, - ?NodeAggregateId $succeedingSiblingNodeAggregateId = null, - ?NodeName $nodeName = null, - ?PropertyValuesToWrite $initialPropertyValues = null, - ?NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds = null + public readonly PropertyValuesToWrite $initialPropertyValues, + public readonly NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds, + public readonly ?NodeAggregateId $succeedingSiblingNodeAggregateId, + public readonly ?NodeName $nodeName, ) { - $this->succeedingSiblingNodeAggregateId = $succeedingSiblingNodeAggregateId; - $this->nodeName = $nodeName; - $this->initialPropertyValues = $initialPropertyValues ?: PropertyValuesToWrite::fromArray([]); - $this->tetheredDescendantNodeAggregateIds = $tetheredDescendantNodeAggregateIds - ?: new NodeAggregateIdsByNodePaths([]); + } + + /** + * @param OriginDimensionSpacePoint $originDimensionSpacePoint Origin of the new node in the dimension space. Will also be used to calculate a set of dimension points where the new node will cover from the configured specializations. + * @param NodeAggregateId|null $succeedingSiblingNodeAggregateId Node aggregate id of the node's succeeding sibling (optional). If not given, the node will be added as the parent's first child + * @param NodeName|null $nodeName The node's optional name. Set if there is a meaningful relation to its parent that should be named. + * @param PropertyValuesToWrite|null $initialPropertyValues The node's initial property values. Will be merged over the node type's default property values + */ + public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, NodeTypeName $nodeTypeName, OriginDimensionSpacePoint $originDimensionSpacePoint, NodeAggregateId $parentNodeAggregateId, ?NodeAggregateId $succeedingSiblingNodeAggregateId = null, ?NodeName $nodeName = null, ?PropertyValuesToWrite $initialPropertyValues = null) { + return new self($contentStreamId, $nodeAggregateId, $nodeTypeName, $originDimensionSpacePoint, $parentNodeAggregateId, $initialPropertyValues ?: PropertyValuesToWrite::createEmpty(), NodeAggregateIdsByNodePaths::createEmpty(), $succeedingSiblingNodeAggregateId, $nodeName); } public function withInitialPropertyValues(PropertyValuesToWrite $newInitialPropertyValues): self @@ -93,10 +73,25 @@ public function withInitialPropertyValues(PropertyValuesToWrite $newInitialPrope $this->nodeTypeName, $this->originDimensionSpacePoint, $this->parentNodeAggregateId, + $newInitialPropertyValues, + $this->tetheredDescendantNodeAggregateIds, + $this->succeedingSiblingNodeAggregateId, + $this->nodeName, + ); + } + + public function withTetheredDescendantNodeAggregateIds(NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds): self + { + return new self( + $this->contentStreamId, + $this->nodeAggregateId, + $this->nodeTypeName, + $this->originDimensionSpacePoint, + $this->parentNodeAggregateId, + $this->initialPropertyValues, + $tetheredDescendantNodeAggregateIds, $this->succeedingSiblingNodeAggregateId, $this->nodeName, - $newInitialPropertyValues, - $this->tetheredDescendantNodeAggregateIds ); } } diff --git a/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php b/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php index cf88f165..c692f53a 100644 --- a/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php +++ b/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php @@ -38,53 +38,36 @@ final class CreateNodeAggregateWithNodeAndSerializedProperties implements RebasableToOtherContentStreamsInterface, MatchableWithNodeIdToPublishOrDiscardInterface { - /** - * The node's optional name. Set if there is a meaningful relation to its parent that should be named. - */ - public readonly ?NodeName $nodeName; - - /** - * Node aggregate identifier of the node's succeeding sibling (optional) - * If not given, the node will be added as the parent's first child - */ - public readonly ?NodeAggregateId $succeedingSiblingNodeAggregateId; /** - * The node's initial property values. Will be merged over the node type's default property values + * @param OriginDimensionSpacePoint $originDimensionSpacePoint Origin of the new node in the dimension space. Will also be used to calculate a set of dimension points where the new node will cover from the configured specializations. + * @param SerializedPropertyValues $initialPropertyValues The node's initial property values (serialized). Will be merged over the node type's default property values + * @param NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds Predefined aggregate ids of tethered child nodes per path. For any tethered node that has no matching entry in this set, the node aggregate id is generated randomly. Since tethered nodes may have tethered child nodes themselves, this works for multiple levels + * @param NodeAggregateId|null $succeedingSiblingNodeAggregateId Node aggregate id of the node's succeeding sibling (optional). If not given, the node will be added as the parent's first child + * @param NodeName|null $nodeName The node's optional name. Set if there is a meaningful relation to its parent that should be named. */ - public readonly SerializedPropertyValues $initialPropertyValues; - - /** - * NodeAggregateIds for tethered descendants (optional). - * - * If the given node type declares tethered child nodes, you may predefine their node aggregate ids - * using this assignment registry. - * Since tethered child nodes may have tethered child nodes themselves, - * this registry is indexed using relative node paths to the node to create in the first place. - */ - public readonly NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds; - - public function __construct( + private function __construct( public readonly ContentStreamId $contentStreamId, public readonly NodeAggregateId $nodeAggregateId, public readonly NodeTypeName $nodeTypeName, - /** - * Origin of the new node in the dimension space. - * Will also be used to calculate a set of dimension points where the new node will cover - * from the configured specializations. - */ public readonly OriginDimensionSpacePoint $originDimensionSpacePoint, public readonly NodeAggregateId $parentNodeAggregateId, - ?NodeAggregateId $succeedingSiblingNodeAggregateId = null, - ?NodeName $nodeName = null, - ?SerializedPropertyValues $initialPropertyValues = null, - ?NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds = null + public readonly SerializedPropertyValues $initialPropertyValues, + public readonly NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds, + public readonly ?NodeAggregateId $succeedingSiblingNodeAggregateId, + public readonly ?NodeName $nodeName ) { - $this->succeedingSiblingNodeAggregateId = $succeedingSiblingNodeAggregateId; - $this->nodeName = $nodeName; - $this->initialPropertyValues = $initialPropertyValues ?: SerializedPropertyValues::fromArray([]); - $this->tetheredDescendantNodeAggregateIds = $tetheredDescendantNodeAggregateIds - ?: new NodeAggregateIdsByNodePaths([]); + } + + /** + * @param OriginDimensionSpacePoint $originDimensionSpacePoint Origin of the new node in the dimension space. Will also be used to calculate a set of dimension points where the new node will cover from the configured specializations. + * @param NodeAggregateId|null $succeedingSiblingNodeAggregateId Node aggregate id of the node's succeeding sibling (optional). If not given, the node will be added as the parent's first child + * @param NodeName|null $nodeName The node's optional name. Set if there is a meaningful relation to its parent that should be named. + * @param SerializedPropertyValues|null $initialPropertyValues The node's initial property values (serialized). Will be merged over the node type's default property values + */ + public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, NodeTypeName $nodeTypeName, OriginDimensionSpacePoint $originDimensionSpacePoint, NodeAggregateId $parentNodeAggregateId, NodeAggregateId $succeedingSiblingNodeAggregateId = null, NodeName $nodeName = null, SerializedPropertyValues $initialPropertyValues = null): self + { + return new self($contentStreamId, $nodeAggregateId, $nodeTypeName, $originDimensionSpacePoint, $parentNodeAggregateId, $initialPropertyValues ?? SerializedPropertyValues::createEmpty(), NodeAggregateIdsByNodePaths::createEmpty(), $succeedingSiblingNodeAggregateId, $nodeName); } /** @@ -98,17 +81,17 @@ public static function fromArray(array $array): self NodeTypeName::fromString($array['nodeTypeName']), OriginDimensionSpacePoint::fromArray($array['originDimensionSpacePoint']), NodeAggregateId::fromString($array['parentNodeAggregateId']), + isset($array['initialPropertyValues']) + ? SerializedPropertyValues::fromArray($array['initialPropertyValues']) + : SerializedPropertyValues::createEmpty(), + isset($array['tetheredDescendantNodeAggregateIds']) + ? NodeAggregateIdsByNodePaths::fromArray($array['tetheredDescendantNodeAggregateIds']) + : NodeAggregateIdsByNodePaths::createEmpty(), isset($array['succeedingSiblingNodeAggregateId']) ? NodeAggregateId::fromString($array['succeedingSiblingNodeAggregateId']) : null, isset($array['nodeName']) ? NodeName::fromString($array['nodeName']) - : null, - isset($array['initialPropertyValues']) - ? SerializedPropertyValues::fromArray($array['initialPropertyValues']) - : null, - isset($array['tetheredDescendantNodeAggregateIds']) - ? NodeAggregateIdsByNodePaths::fromArray($array['tetheredDescendantNodeAggregateIds']) : null ); } @@ -129,10 +112,10 @@ public function withTetheredDescendantNodeAggregateIds( $this->nodeTypeName, $this->originDimensionSpacePoint, $this->parentNodeAggregateId, - $this->succeedingSiblingNodeAggregateId, - $this->nodeName, $this->initialPropertyValues, - $tetheredDescendantNodeAggregateIds + $tetheredDescendantNodeAggregateIds, + $this->succeedingSiblingNodeAggregateId, + $this->nodeName ); } @@ -152,10 +135,10 @@ public function createCopyForContentStream(ContentStreamId $target): self $this->nodeTypeName, $this->originDimensionSpacePoint, $this->parentNodeAggregateId, - $this->succeedingSiblingNodeAggregateId, - $this->nodeName, $this->initialPropertyValues, - $this->tetheredDescendantNodeAggregateIds + $this->tetheredDescendantNodeAggregateIds, + $this->succeedingSiblingNodeAggregateId, + $this->nodeName ); } diff --git a/Classes/Feature/NodeCreation/Dto/NodeAggregateIdsByNodePaths.php b/Classes/Feature/NodeCreation/Dto/NodeAggregateIdsByNodePaths.php index f35eb3a1..1eba8ab7 100644 --- a/Classes/Feature/NodeCreation/Dto/NodeAggregateIdsByNodePaths.php +++ b/Classes/Feature/NodeCreation/Dto/NodeAggregateIdsByNodePaths.php @@ -119,6 +119,11 @@ public function getNodeAggregateIds(): array return $this->nodeAggregateIds; } + public function isEmpty(): bool + { + return $this->nodeAggregateIds === []; + } + /** * @return array */ diff --git a/Classes/Feature/NodeCreation/NodeCreation.php b/Classes/Feature/NodeCreation/NodeCreation.php index 10cc11bc..46c15fd4 100644 --- a/Classes/Feature/NodeCreation/NodeCreation.php +++ b/Classes/Feature/NodeCreation/NodeCreation.php @@ -72,7 +72,7 @@ private function handleCreateNodeAggregateWithNode( ); $this->validateProperties($command->initialPropertyValues, $command->nodeTypeName); - $lowLevelCommand = new CreateNodeAggregateWithNodeAndSerializedProperties( + $lowLevelCommand = CreateNodeAggregateWithNodeAndSerializedProperties::create( $command->contentStreamId, $command->nodeAggregateId, $command->nodeTypeName, @@ -83,9 +83,11 @@ private function handleCreateNodeAggregateWithNode( $this->getPropertyConverter()->serializePropertyValues( $command->initialPropertyValues, $this->requireNodeType($command->nodeTypeName) - ), - $command->tetheredDescendantNodeAggregateIds + ) ); + if (!$command->tetheredDescendantNodeAggregateIds->isEmpty()) { + $command = $command->withTetheredDescendantNodeAggregateIds($command->tetheredDescendantNodeAggregateIds); + } return $this->handleCreateNodeAggregateWithNodeAndSerializedProperties($lowLevelCommand, $contentRepository); } diff --git a/Classes/Feature/NodeModification/Dto/PropertyValuesToWrite.php b/Classes/Feature/NodeModification/Dto/PropertyValuesToWrite.php index 3e2d6802..7befff99 100644 --- a/Classes/Feature/NodeModification/Dto/PropertyValuesToWrite.php +++ b/Classes/Feature/NodeModification/Dto/PropertyValuesToWrite.php @@ -33,6 +33,11 @@ private function __construct(public readonly array $values) { } + public static function createEmpty(): self + { + return new self([]); + } + /** * @param array $values */ diff --git a/Classes/Feature/NodeModification/Dto/SerializedPropertyValues.php b/Classes/Feature/NodeModification/Dto/SerializedPropertyValues.php index 41fe1408..5345f0bf 100644 --- a/Classes/Feature/NodeModification/Dto/SerializedPropertyValues.php +++ b/Classes/Feature/NodeModification/Dto/SerializedPropertyValues.php @@ -43,6 +43,11 @@ private function __construct( $this->iterator = new \ArrayIterator($this->values); } + public static function createEmpty(): self + { + return new self([]); + } + /** * @param array $propertyValues */ diff --git a/Classes/Feature/NodeMove/Command/MoveNodeAggregate.php b/Classes/Feature/NodeMove/Command/MoveNodeAggregate.php index 9de86e0c..7cf4f2f4 100644 --- a/Classes/Feature/NodeMove/Command/MoveNodeAggregate.php +++ b/Classes/Feature/NodeMove/Command/MoveNodeAggregate.php @@ -47,48 +47,38 @@ final class MoveNodeAggregate implements RebasableToOtherContentStreamsInterface, MatchableWithNodeIdToPublishOrDiscardInterface { - public function __construct( - /** - * The content stream in which the move operation is to be performed - */ + /** + * @param ContentStreamId $contentStreamId The content stream in which the move operation is to be performed + * @param DimensionSpacePoint $dimensionSpacePoint This is one of the *covered* dimension space points of the node aggregate and not necessarily one of the occupied ones. This allows us to move virtual specializations only when using the scatter strategy + * @param NodeAggregateId $nodeAggregateId Aggregate id of the node to move + * @param RelationDistributionStrategy $relationDistributionStrategy The relation distribution strategy to be used ({@see RelationDistributionStrategy}) + * @param NodeAggregateId|null $newParentNodeAggregateId The id of the new preceding sibling node aggregate. If given and no successor found, it is attempted to insert the moved nodes right after nodes of this aggregate. In dimension space points this aggregate does not cover, other siblings, in order of proximity, are tried to be used instead + * @param NodeAggregateId|null $newPrecedingSiblingNodeAggregateId The id of the new succeeding sibling node aggregate. If given, it is attempted to insert the moved nodes right before nodes of this aggregate. In dimension space points this aggregate does not cover, the preceding sibling is tried to be used instead + */ + private function __construct( public readonly ContentStreamId $contentStreamId, - /** - * This is one of the *covered* dimension space points of the node aggregate - * and not necessarily one of the occupied ones. - * This allows us to move virtual specializations only when using the scatter strategy. - */ public readonly DimensionSpacePoint $dimensionSpacePoint, - /** - * The node aggregate to be moved - */ public readonly NodeAggregateId $nodeAggregateId, - /** - * This is the id of the new parent node aggregate. - * If given, it enforces that all nodes in the given aggregate are moved into nodes of the parent aggregate, - * even if the given siblings belong to other parents. In latter case, those siblings are ignored. - */ + public readonly RelationDistributionStrategy $relationDistributionStrategy, public readonly ?NodeAggregateId $newParentNodeAggregateId, - /** - * This is the id of the new preceding sibling node aggregate. - * If given and no successor found, it is attempted to insert the moved nodes right after nodes of this - * aggregate. - * In dimension space points this aggregate does not cover, other siblings, - * in order of proximity, are tried to be used instead. - */ public readonly ?NodeAggregateId $newPrecedingSiblingNodeAggregateId, - /** - * This is the id of the new succeeding sibling node aggregate. - * If given, it is attempted to insert the moved nodes right before nodes of this aggregate. - * In dimension space points this aggregate does not cover, the preceding sibling is tried to be used instead. - */ public readonly ?NodeAggregateId $newSucceedingSiblingNodeAggregateId, - /** - * The relation distribution strategy to be used - */ - public readonly RelationDistributionStrategy $relationDistributionStrategy, ) { } + /** + * @param ContentStreamId $contentStreamId The content stream in which the move operation is to be performed + * @param DimensionSpacePoint $dimensionSpacePoint This is one of the *covered* dimension space points of the node aggregate and not necessarily one of the occupied ones. This allows us to move virtual specializations only when using the scatter strategy + * @param NodeAggregateId $nodeAggregateId Aggregate id of the node to move + * @param RelationDistributionStrategy $relationDistributionStrategy The relation distribution strategy to be used ({@see RelationDistributionStrategy}) + * @param NodeAggregateId|null $newParentNodeAggregateId The id of the new preceding sibling node aggregate. If given and no successor found, it is attempted to insert the moved nodes right after nodes of this aggregate. In dimension space points this aggregate does not cover, other siblings, in order of proximity, are tried to be used instead + * @param NodeAggregateId|null $newPrecedingSiblingNodeAggregateId The id of the new succeeding sibling node aggregate. If given, it is attempted to insert the moved nodes right before nodes of this aggregate. In dimension space points this aggregate does not cover, the preceding sibling is tried to be used instead + */ + public static function create(ContentStreamId $contentStreamId, DimensionSpacePoint $dimensionSpacePoint, NodeAggregateId $nodeAggregateId, RelationDistributionStrategy $relationDistributionStrategy, ?NodeAggregateId $newParentNodeAggregateId = null, ?NodeAggregateId $newPrecedingSiblingNodeAggregateId = null, ?NodeAggregateId $newSucceedingSiblingNodeAggregateId = null): self + { + return new self($contentStreamId, $dimensionSpacePoint, $nodeAggregateId, $relationDistributionStrategy, $newParentNodeAggregateId, $newPrecedingSiblingNodeAggregateId, $newSucceedingSiblingNodeAggregateId); + } + /** * @param array $array */ @@ -98,6 +88,7 @@ public static function fromArray(array $array): self ContentStreamId::fromString($array['contentStreamId']), DimensionSpacePoint::fromArray($array['dimensionSpacePoint']), NodeAggregateId::fromString($array['nodeAggregateId']), + RelationDistributionStrategy::fromString($array['relationDistributionStrategy']), isset($array['newParentNodeAggregateId']) ? NodeAggregateId::fromString($array['newParentNodeAggregateId']) : null, @@ -107,7 +98,6 @@ public static function fromArray(array $array): self isset($array['newSucceedingSiblingNodeAggregateId']) ? NodeAggregateId::fromString($array['newSucceedingSiblingNodeAggregateId']) : null, - RelationDistributionStrategy::fromString($array['relationDistributionStrategy']), ); } @@ -125,10 +115,10 @@ public function createCopyForContentStream(ContentStreamId $target): self $target, $this->dimensionSpacePoint, $this->nodeAggregateId, + $this->relationDistributionStrategy, $this->newParentNodeAggregateId, $this->newPrecedingSiblingNodeAggregateId, $this->newSucceedingSiblingNodeAggregateId, - $this->relationDistributionStrategy, ); } diff --git a/Tests/Unit/Projection/ContentGraph/PropertyCollectionTest.php b/Tests/Unit/Projection/ContentGraph/PropertyCollectionTest.php index 60d32c7e..ec3fb6f6 100644 --- a/Tests/Unit/Projection/ContentGraph/PropertyCollectionTest.php +++ b/Tests/Unit/Projection/ContentGraph/PropertyCollectionTest.php @@ -36,7 +36,7 @@ public function setUp(): void public function emptyPropertyCollectionReturnsEmptyArray(): void { $this->mockSerializer->expects($this->never())->method($this->anything()); - $collection = new PropertyCollection(SerializedPropertyValues::fromArray([]), $this->mockPropertyConverter); + $collection = new PropertyCollection(SerializedPropertyValues::createEmpty(), $this->mockPropertyConverter); self::assertSame([], iterator_to_array($collection)); } @@ -85,7 +85,7 @@ public function propertiesCanBeIterated(): void */ public function offsetSetThrowsAnException(): void { - $collection = new PropertyCollection(SerializedPropertyValues::fromArray([]), $this->mockPropertyConverter); + $collection = new PropertyCollection(SerializedPropertyValues::createEmpty(), $this->mockPropertyConverter); $this->expectException(\RuntimeException::class); $collection->offsetSet('foo', 'bar'); } @@ -95,7 +95,7 @@ public function offsetSetThrowsAnException(): void */ public function offsetUnsetThrowsAnException(): void { - $collection = new PropertyCollection(SerializedPropertyValues::fromArray([]), $this->mockPropertyConverter); + $collection = new PropertyCollection(SerializedPropertyValues::createEmpty(), $this->mockPropertyConverter); $this->expectException(\RuntimeException::class); $collection->offsetUnset('foo'); } From 4c7186ef41932c9621fcc28f4485d21ca99771b5 Mon Sep 17 00:00:00 2001 From: bwaidelich Date: Fri, 8 Sep 2023 11:14:09 +0200 Subject: [PATCH 2/5] Fix MoveNodeAggregate param comments --- .../Feature/NodeMove/Command/MoveNodeAggregate.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Classes/Feature/NodeMove/Command/MoveNodeAggregate.php b/Classes/Feature/NodeMove/Command/MoveNodeAggregate.php index 7cf4f2f4..cddcae97 100644 --- a/Classes/Feature/NodeMove/Command/MoveNodeAggregate.php +++ b/Classes/Feature/NodeMove/Command/MoveNodeAggregate.php @@ -50,10 +50,11 @@ final class MoveNodeAggregate implements /** * @param ContentStreamId $contentStreamId The content stream in which the move operation is to be performed * @param DimensionSpacePoint $dimensionSpacePoint This is one of the *covered* dimension space points of the node aggregate and not necessarily one of the occupied ones. This allows us to move virtual specializations only when using the scatter strategy - * @param NodeAggregateId $nodeAggregateId Aggregate id of the node to move + * @param NodeAggregateId $nodeAggregateId The id of the node aggregate to move * @param RelationDistributionStrategy $relationDistributionStrategy The relation distribution strategy to be used ({@see RelationDistributionStrategy}) - * @param NodeAggregateId|null $newParentNodeAggregateId The id of the new preceding sibling node aggregate. If given and no successor found, it is attempted to insert the moved nodes right after nodes of this aggregate. In dimension space points this aggregate does not cover, other siblings, in order of proximity, are tried to be used instead - * @param NodeAggregateId|null $newPrecedingSiblingNodeAggregateId The id of the new succeeding sibling node aggregate. If given, it is attempted to insert the moved nodes right before nodes of this aggregate. In dimension space points this aggregate does not cover, the preceding sibling is tried to be used instead + * @param NodeAggregateId|null $newParentNodeAggregateId The id of the new parent node aggregate. If given, it enforces that all nodes in the given aggregate are moved into nodes of the parent aggregate, even if the given siblings belong to other parents. In latter case, those siblings are ignored + * @param NodeAggregateId|null $newPrecedingSiblingNodeAggregateId The id of the new preceding sibling node aggregate. If given and no successor found, it is attempted to insert the moved nodes right after nodes of this aggregate. In dimension space points this aggregate does not cover, other siblings, in order of proximity, are tried to be used instead + * @param NodeAggregateId|null $newSucceedingSiblingNodeAggregateId The id of the new succeeding sibling node aggregate. If given, it is attempted to insert the moved nodes right before nodes of this aggregate. In dimension space points this aggregate does not cover, the preceding sibling is tried to be used instead */ private function __construct( public readonly ContentStreamId $contentStreamId, @@ -69,10 +70,11 @@ private function __construct( /** * @param ContentStreamId $contentStreamId The content stream in which the move operation is to be performed * @param DimensionSpacePoint $dimensionSpacePoint This is one of the *covered* dimension space points of the node aggregate and not necessarily one of the occupied ones. This allows us to move virtual specializations only when using the scatter strategy - * @param NodeAggregateId $nodeAggregateId Aggregate id of the node to move + * @param NodeAggregateId $nodeAggregateId The id of the node aggregate to move * @param RelationDistributionStrategy $relationDistributionStrategy The relation distribution strategy to be used ({@see RelationDistributionStrategy}) - * @param NodeAggregateId|null $newParentNodeAggregateId The id of the new preceding sibling node aggregate. If given and no successor found, it is attempted to insert the moved nodes right after nodes of this aggregate. In dimension space points this aggregate does not cover, other siblings, in order of proximity, are tried to be used instead - * @param NodeAggregateId|null $newPrecedingSiblingNodeAggregateId The id of the new succeeding sibling node aggregate. If given, it is attempted to insert the moved nodes right before nodes of this aggregate. In dimension space points this aggregate does not cover, the preceding sibling is tried to be used instead + * @param NodeAggregateId|null $newParentNodeAggregateId The id of the new parent node aggregate. If given, it enforces that all nodes in the given aggregate are moved into nodes of the parent aggregate, even if the given siblings belong to other parents. In latter case, those siblings are ignored + * @param NodeAggregateId|null $newPrecedingSiblingNodeAggregateId The id of the new preceding sibling node aggregate. If given and no successor found, it is attempted to insert the moved nodes right after nodes of this aggregate. In dimension space points this aggregate does not cover, other siblings, in order of proximity, are tried to be used instead + * @param NodeAggregateId|null $newSucceedingSiblingNodeAggregateId The id of the new succeeding sibling node aggregate. If given, it is attempted to insert the moved nodes right before nodes of this aggregate. In dimension space points this aggregate does not cover, the preceding sibling is tried to be used instead */ public static function create(ContentStreamId $contentStreamId, DimensionSpacePoint $dimensionSpacePoint, NodeAggregateId $nodeAggregateId, RelationDistributionStrategy $relationDistributionStrategy, ?NodeAggregateId $newParentNodeAggregateId = null, ?NodeAggregateId $newPrecedingSiblingNodeAggregateId = null, ?NodeAggregateId $newSucceedingSiblingNodeAggregateId = null): self { From 728498319964d53326be72b8d8e10dd1cc8c0205 Mon Sep 17 00:00:00 2001 From: bwaidelich Date: Fri, 8 Sep 2023 18:47:00 +0200 Subject: [PATCH 3/5] Overhaul remaining command constructors --- .../Command/CreateContentStream.php | 13 ++++- .../Command/ForkContentStream.php | 21 ++++--- .../Command/RemoveContentStream.php | 13 ++++- .../Command/AddDimensionShineThrough.php | 18 +++++- .../Command/MoveDimensionSpacePoint.php | 18 +++++- .../Command/CreateNodeAggregateWithNode.php | 21 +++++-- ...gregateWithNodeAndSerializedProperties.php | 32 +++++++---- .../Command/DisableNodeAggregate.php | 22 ++++++- .../Command/EnableNodeAggregate.php | 22 ++++++- .../Command/CopyNodesRecursively.php | 57 ++++++++----------- .../Command/SetNodeProperties.php | 19 ++++++- .../Command/SetSerializedNodeProperties.php | 20 ++++++- .../NodeModification/NodeModification.php | 2 +- .../Command/SetNodeReferences.php | 20 +++++++ .../Command/SetSerializedNodeReferences.php | 21 ++++++- .../NodeReferencing/NodeReferencing.php | 2 +- .../Command/RemoveNodeAggregate.php | 20 ++++++- .../Command/ChangeNodeAggregateName.php | 18 +++++- .../Command/ChangeNodeAggregateType.php | 38 ++++++++----- .../Feature/NodeTypeChange/NodeTypeChange.php | 2 +- .../Command/CreateNodeVariant.php | 19 ++++++- .../CreateRootNodeAggregateWithNode.php | 19 ++++++- .../UpdateRootNodeAggregateDimensions.php | 18 +++++- Classes/Feature/WorkspaceCommandHandler.php | 22 +++---- .../Command/CreateRootWorkspace.php | 19 ++++++- .../Command/CreateWorkspace.php | 29 ++++++++-- .../Command/ChangeBaseWorkspace.php | 16 +++++- .../Command/ChangeWorkspaceOwner.php | 15 ++++- .../Command/DeleteWorkspace.php | 13 ++++- .../Command/RenameWorkspace.php | 17 +++++- .../DiscardIndividualNodesFromWorkspace.php | 23 ++++---- .../Command/DiscardWorkspace.php | 19 ++++--- .../PublishIndividualNodesFromWorkspace.php | 38 ++++++------- .../Command/PublishWorkspace.php | 17 +++++- .../Command/RebaseWorkspace.php | 20 +++---- .../Service/ContentRepositoryBootstrapper.php | 4 +- Classes/Service/ContentStreamPruner.php | 4 +- 37 files changed, 538 insertions(+), 173 deletions(-) diff --git a/Classes/Feature/ContentStreamCreation/Command/CreateContentStream.php b/Classes/Feature/ContentStreamCreation/Command/CreateContentStream.php index 929ed6b5..aeeee0ab 100644 --- a/Classes/Feature/ContentStreamCreation/Command/CreateContentStream.php +++ b/Classes/Feature/ContentStreamCreation/Command/CreateContentStream.php @@ -25,8 +25,19 @@ */ final class CreateContentStream implements CommandInterface { - public function __construct( + /** + * @param ContentStreamId $contentStreamId The id of the content stream to create + */ + private function __construct( public readonly ContentStreamId $contentStreamId, ) { } + + /** + * @param ContentStreamId $contentStreamId The id of the content stream to create + */ + public static function create(ContentStreamId $contentStreamId): self + { + return new self($contentStreamId); + } } diff --git a/Classes/Feature/ContentStreamForking/Command/ForkContentStream.php b/Classes/Feature/ContentStreamForking/Command/ForkContentStream.php index b96ef0b6..d8d104a2 100644 --- a/Classes/Feature/ContentStreamForking/Command/ForkContentStream.php +++ b/Classes/Feature/ContentStreamForking/Command/ForkContentStream.php @@ -16,7 +16,6 @@ use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; -use Neos\ContentRepository\Core\SharedModel\User\UserId; /** * ForkContentStream for creating a new fork of a content stream. @@ -25,17 +24,25 @@ */ final class ForkContentStream implements CommandInterface { - public function __construct( - /** - * Content stream id for the new content stream - * - * @var ContentStreamId - */ + /** + * @param ContentStreamId $newContentStreamId The id of the new content stream + * @param ContentStreamId $sourceContentStreamId The id of the content stream to fork + */ + private function __construct( public readonly ContentStreamId $newContentStreamId, public readonly ContentStreamId $sourceContentStreamId, ) { } + /** + * @param ContentStreamId $newContentStreamId The id of the new content stream + * @param ContentStreamId $sourceContentStreamId The id of the content stream to fork + */ + public static function create(ContentStreamId $newContentStreamId, ContentStreamId $sourceContentStreamId): self + { + return new self($newContentStreamId, $sourceContentStreamId); + } + /** * @param array $array * @internal only used for testcases diff --git a/Classes/Feature/ContentStreamRemoval/Command/RemoveContentStream.php b/Classes/Feature/ContentStreamRemoval/Command/RemoveContentStream.php index 832ebac0..42f8c179 100644 --- a/Classes/Feature/ContentStreamRemoval/Command/RemoveContentStream.php +++ b/Classes/Feature/ContentStreamRemoval/Command/RemoveContentStream.php @@ -24,8 +24,19 @@ */ final class RemoveContentStream implements CommandInterface { - public function __construct( + /** + * @param ContentStreamId $contentStreamId The id of the content stream to remove + */ + private function __construct( public readonly ContentStreamId $contentStreamId, ) { } + + /** + * @param ContentStreamId $contentStreamId The id of the content stream to remove + */ + public static function create(ContentStreamId $contentStreamId): self + { + return new self($contentStreamId); + } } diff --git a/Classes/Feature/DimensionSpaceAdjustment/Command/AddDimensionShineThrough.php b/Classes/Feature/DimensionSpaceAdjustment/Command/AddDimensionShineThrough.php index f1ff20f5..cd4d3073 100644 --- a/Classes/Feature/DimensionSpaceAdjustment/Command/AddDimensionShineThrough.php +++ b/Classes/Feature/DimensionSpaceAdjustment/Command/AddDimensionShineThrough.php @@ -37,13 +37,29 @@ final class AddDimensionShineThrough implements \JsonSerializable, RebasableToOtherContentStreamsInterface { - public function __construct( + + /** + * @param ContentStreamId $contentStreamId The id of the content stream to perform the operation in + * @param DimensionSpacePoint $source source dimension space point + * @param DimensionSpacePoint $target target dimension space point + */ + private function __construct( public readonly ContentStreamId $contentStreamId, public readonly DimensionSpacePoint $source, public readonly DimensionSpacePoint $target ) { } + /** + * @param ContentStreamId $contentStreamId The id of the content stream to perform the operation in + * @param DimensionSpacePoint $source source dimension space point + * @param DimensionSpacePoint $target target dimension space point + */ + public static function create(ContentStreamId $contentStreamId, DimensionSpacePoint $source, DimensionSpacePoint $target): self + { + return new self($contentStreamId, $source, $target); + } + /** * @param array $array */ diff --git a/Classes/Feature/DimensionSpaceAdjustment/Command/MoveDimensionSpacePoint.php b/Classes/Feature/DimensionSpaceAdjustment/Command/MoveDimensionSpacePoint.php index 9165e804..02cea4f6 100644 --- a/Classes/Feature/DimensionSpaceAdjustment/Command/MoveDimensionSpacePoint.php +++ b/Classes/Feature/DimensionSpaceAdjustment/Command/MoveDimensionSpacePoint.php @@ -33,13 +33,29 @@ final class MoveDimensionSpacePoint implements CommandInterface, RebasableToOtherContentStreamsInterface { - public function __construct( + + /** + * @param ContentStreamId $contentStreamId The id of the content stream to perform the operation in + * @param DimensionSpacePoint $source source dimension space point + * @param DimensionSpacePoint $target target dimension space point + */ + private function __construct( public readonly ContentStreamId $contentStreamId, public readonly DimensionSpacePoint $source, public readonly DimensionSpacePoint $target ) { } + /** + * @param ContentStreamId $contentStreamId The id of the content stream to perform the operation in + * @param DimensionSpacePoint $source source dimension space point + * @param DimensionSpacePoint $target target dimension space point + */ + public static function create(ContentStreamId $contentStreamId, DimensionSpacePoint $source, DimensionSpacePoint $target): self + { + return new self($contentStreamId, $source, $target); + } + /** * @param array $array */ diff --git a/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNode.php b/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNode.php index afd60352..545efc0d 100644 --- a/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNode.php +++ b/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNode.php @@ -36,11 +36,15 @@ final class CreateNodeAggregateWithNode implements CommandInterface { /** + * @param ContentStreamId $contentStreamId The content stream in which the create operation is to be performed + * @param NodeAggregateId $nodeAggregateId The unique identifier of the node aggregate to create + * @param NodeTypeName $nodeTypeName Name of the node type of the new node * @param OriginDimensionSpacePoint $originDimensionSpacePoint Origin of the new node in the dimension space. Will also be used to calculate a set of dimension points where the new node will cover from the configured specializations. + * @param NodeAggregateId $parentNodeAggregateId The id of the node aggregate underneath which the new node is added * @param PropertyValuesToWrite $initialPropertyValues The node's initial property values. Will be merged over the node type's default property values - * @param NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds Predefined aggregate ids of tethered child nodes per path. For any tethered node that has no matching entry in this set, the node aggregate id is generated randomly. Since tethered nodes may have tethered child nodes themselves, this works for multiple levels * @param NodeAggregateId|null $succeedingSiblingNodeAggregateId Node aggregate id of the node's succeeding sibling (optional). If not given, the node will be added as the parent's first child * @param NodeName|null $nodeName The node's optional name. Set if there is a meaningful relation to its parent that should be named. + * @param NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds Predefined aggregate ids of tethered child nodes per path. For any tethered node that has no matching entry in this set, the node aggregate id is generated randomly. Since tethered nodes may have tethered child nodes themselves, this works for multiple levels ({@see self::withTetheredDescendantNodeAggregateIds()}) */ private function __construct( public readonly ContentStreamId $contentStreamId, @@ -49,20 +53,25 @@ private function __construct( public readonly OriginDimensionSpacePoint $originDimensionSpacePoint, public readonly NodeAggregateId $parentNodeAggregateId, public readonly PropertyValuesToWrite $initialPropertyValues, - public readonly NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds, public readonly ?NodeAggregateId $succeedingSiblingNodeAggregateId, public readonly ?NodeName $nodeName, + public readonly NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds, ) { } /** + * @param ContentStreamId $contentStreamId The content stream in which the create operation is to be performed + * @param NodeAggregateId $nodeAggregateId The unique identifier of the node aggregate to create + * @param NodeTypeName $nodeTypeName Name of the node type of the new node * @param OriginDimensionSpacePoint $originDimensionSpacePoint Origin of the new node in the dimension space. Will also be used to calculate a set of dimension points where the new node will cover from the configured specializations. + * @param NodeAggregateId $parentNodeAggregateId The id of the node aggregate underneath which the new node is added * @param NodeAggregateId|null $succeedingSiblingNodeAggregateId Node aggregate id of the node's succeeding sibling (optional). If not given, the node will be added as the parent's first child * @param NodeName|null $nodeName The node's optional name. Set if there is a meaningful relation to its parent that should be named. * @param PropertyValuesToWrite|null $initialPropertyValues The node's initial property values. Will be merged over the node type's default property values */ - public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, NodeTypeName $nodeTypeName, OriginDimensionSpacePoint $originDimensionSpacePoint, NodeAggregateId $parentNodeAggregateId, ?NodeAggregateId $succeedingSiblingNodeAggregateId = null, ?NodeName $nodeName = null, ?PropertyValuesToWrite $initialPropertyValues = null) { - return new self($contentStreamId, $nodeAggregateId, $nodeTypeName, $originDimensionSpacePoint, $parentNodeAggregateId, $initialPropertyValues ?: PropertyValuesToWrite::createEmpty(), NodeAggregateIdsByNodePaths::createEmpty(), $succeedingSiblingNodeAggregateId, $nodeName); + public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, NodeTypeName $nodeTypeName, OriginDimensionSpacePoint $originDimensionSpacePoint, NodeAggregateId $parentNodeAggregateId, ?NodeAggregateId $succeedingSiblingNodeAggregateId = null, ?NodeName $nodeName = null, ?PropertyValuesToWrite $initialPropertyValues = null): self + { + return new self($contentStreamId, $nodeAggregateId, $nodeTypeName, $originDimensionSpacePoint, $parentNodeAggregateId, $initialPropertyValues ?: PropertyValuesToWrite::createEmpty(), $succeedingSiblingNodeAggregateId, $nodeName, NodeAggregateIdsByNodePaths::createEmpty()); } public function withInitialPropertyValues(PropertyValuesToWrite $newInitialPropertyValues): self @@ -74,9 +83,9 @@ public function withInitialPropertyValues(PropertyValuesToWrite $newInitialPrope $this->originDimensionSpacePoint, $this->parentNodeAggregateId, $newInitialPropertyValues, - $this->tetheredDescendantNodeAggregateIds, $this->succeedingSiblingNodeAggregateId, $this->nodeName, + $this->tetheredDescendantNodeAggregateIds, ); } @@ -89,9 +98,9 @@ public function withTetheredDescendantNodeAggregateIds(NodeAggregateIdsByNodePat $this->originDimensionSpacePoint, $this->parentNodeAggregateId, $this->initialPropertyValues, - $tetheredDescendantNodeAggregateIds, $this->succeedingSiblingNodeAggregateId, $this->nodeName, + $tetheredDescendantNodeAggregateIds, ); } } diff --git a/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php b/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php index c692f53a..14e8cb2e 100644 --- a/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php +++ b/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php @@ -40,11 +40,15 @@ final class CreateNodeAggregateWithNodeAndSerializedProperties implements { /** + * @param ContentStreamId $contentStreamId The content stream in which the create operation is to be performed + * @param NodeAggregateId $nodeAggregateId The unique identifier of the node aggregate to create + * @param NodeTypeName $nodeTypeName Name of the node type of the new node * @param OriginDimensionSpacePoint $originDimensionSpacePoint Origin of the new node in the dimension space. Will also be used to calculate a set of dimension points where the new node will cover from the configured specializations. + * @param NodeAggregateId $parentNodeAggregateId The id of the node aggregate underneath which the new node is added * @param SerializedPropertyValues $initialPropertyValues The node's initial property values (serialized). Will be merged over the node type's default property values - * @param NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds Predefined aggregate ids of tethered child nodes per path. For any tethered node that has no matching entry in this set, the node aggregate id is generated randomly. Since tethered nodes may have tethered child nodes themselves, this works for multiple levels * @param NodeAggregateId|null $succeedingSiblingNodeAggregateId Node aggregate id of the node's succeeding sibling (optional). If not given, the node will be added as the parent's first child * @param NodeName|null $nodeName The node's optional name. Set if there is a meaningful relation to its parent that should be named. + * @param NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds Predefined aggregate ids of tethered child nodes per path. For any tethered node that has no matching entry in this set, the node aggregate id is generated randomly. Since tethered nodes may have tethered child nodes themselves, this works for multiple levels ({@see self::withTetheredDescendantNodeAggregateIds()}) */ private function __construct( public readonly ContentStreamId $contentStreamId, @@ -53,21 +57,25 @@ private function __construct( public readonly OriginDimensionSpacePoint $originDimensionSpacePoint, public readonly NodeAggregateId $parentNodeAggregateId, public readonly SerializedPropertyValues $initialPropertyValues, - public readonly NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds, public readonly ?NodeAggregateId $succeedingSiblingNodeAggregateId, - public readonly ?NodeName $nodeName + public readonly ?NodeName $nodeName, + public readonly NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds ) { } /** + * @param ContentStreamId $contentStreamId The content stream in which the create operation is to be performed + * @param NodeAggregateId $nodeAggregateId The unique identifier of the node aggregate to create + * @param NodeTypeName $nodeTypeName Name of the node type of the new node * @param OriginDimensionSpacePoint $originDimensionSpacePoint Origin of the new node in the dimension space. Will also be used to calculate a set of dimension points where the new node will cover from the configured specializations. + * @param NodeAggregateId $parentNodeAggregateId The id of the node aggregate underneath which the new node is added * @param NodeAggregateId|null $succeedingSiblingNodeAggregateId Node aggregate id of the node's succeeding sibling (optional). If not given, the node will be added as the parent's first child * @param NodeName|null $nodeName The node's optional name. Set if there is a meaningful relation to its parent that should be named. * @param SerializedPropertyValues|null $initialPropertyValues The node's initial property values (serialized). Will be merged over the node type's default property values */ public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, NodeTypeName $nodeTypeName, OriginDimensionSpacePoint $originDimensionSpacePoint, NodeAggregateId $parentNodeAggregateId, NodeAggregateId $succeedingSiblingNodeAggregateId = null, NodeName $nodeName = null, SerializedPropertyValues $initialPropertyValues = null): self { - return new self($contentStreamId, $nodeAggregateId, $nodeTypeName, $originDimensionSpacePoint, $parentNodeAggregateId, $initialPropertyValues ?? SerializedPropertyValues::createEmpty(), NodeAggregateIdsByNodePaths::createEmpty(), $succeedingSiblingNodeAggregateId, $nodeName); + return new self($contentStreamId, $nodeAggregateId, $nodeTypeName, $originDimensionSpacePoint, $parentNodeAggregateId, $initialPropertyValues ?? SerializedPropertyValues::createEmpty(), $succeedingSiblingNodeAggregateId, $nodeName, NodeAggregateIdsByNodePaths::createEmpty()); } /** @@ -84,15 +92,15 @@ public static function fromArray(array $array): self isset($array['initialPropertyValues']) ? SerializedPropertyValues::fromArray($array['initialPropertyValues']) : SerializedPropertyValues::createEmpty(), - isset($array['tetheredDescendantNodeAggregateIds']) - ? NodeAggregateIdsByNodePaths::fromArray($array['tetheredDescendantNodeAggregateIds']) - : NodeAggregateIdsByNodePaths::createEmpty(), isset($array['succeedingSiblingNodeAggregateId']) ? NodeAggregateId::fromString($array['succeedingSiblingNodeAggregateId']) : null, isset($array['nodeName']) ? NodeName::fromString($array['nodeName']) - : null + : null, + isset($array['tetheredDescendantNodeAggregateIds']) + ? NodeAggregateIdsByNodePaths::fromArray($array['tetheredDescendantNodeAggregateIds']) + : NodeAggregateIdsByNodePaths::createEmpty() ); } @@ -113,9 +121,9 @@ public function withTetheredDescendantNodeAggregateIds( $this->originDimensionSpacePoint, $this->parentNodeAggregateId, $this->initialPropertyValues, - $tetheredDescendantNodeAggregateIds, $this->succeedingSiblingNodeAggregateId, - $this->nodeName + $this->nodeName, + $tetheredDescendantNodeAggregateIds ); } @@ -136,9 +144,9 @@ public function createCopyForContentStream(ContentStreamId $target): self $this->originDimensionSpacePoint, $this->parentNodeAggregateId, $this->initialPropertyValues, - $this->tetheredDescendantNodeAggregateIds, $this->succeedingSiblingNodeAggregateId, - $this->nodeName + $this->nodeName, + $this->tetheredDescendantNodeAggregateIds ); } diff --git a/Classes/Feature/NodeDisabling/Command/DisableNodeAggregate.php b/Classes/Feature/NodeDisabling/Command/DisableNodeAggregate.php index 1aa895f1..05ab0422 100644 --- a/Classes/Feature/NodeDisabling/Command/DisableNodeAggregate.php +++ b/Classes/Feature/NodeDisabling/Command/DisableNodeAggregate.php @@ -34,16 +34,32 @@ final class DisableNodeAggregate implements RebasableToOtherContentStreamsInterface, MatchableWithNodeIdToPublishOrDiscardInterface { - public function __construct( + + /** + * @param ContentStreamId $contentStreamId The content stream in which the disable operation is to be performed + * @param NodeAggregateId $nodeAggregateId The identifier of the node aggregate to disable + * @param DimensionSpacePoint $coveredDimensionSpacePoint The covered dimension space point of the node aggregate in which the user intends to disable it + * @param NodeVariantSelectionStrategy $nodeVariantSelectionStrategy The strategy the user chose to determine which specialization variants will also be disabled + */ + private function __construct( public readonly ContentStreamId $contentStreamId, public readonly NodeAggregateId $nodeAggregateId, - /** One of the dimension space points covered by the node aggregate in which the user intends to disable it */ public readonly DimensionSpacePoint $coveredDimensionSpacePoint, - /** The strategy the user chose to determine which specialization variants will also be disabled */ public readonly NodeVariantSelectionStrategy $nodeVariantSelectionStrategy, ) { } + /** + * @param ContentStreamId $contentStreamId The content stream in which the disable operation is to be performed + * @param NodeAggregateId $nodeAggregateId The identifier of the node aggregate to disable + * @param DimensionSpacePoint $coveredDimensionSpacePoint The covered dimension space point of the node aggregate in which the user intends to disable it + * @param NodeVariantSelectionStrategy $nodeVariantSelectionStrategy The strategy the user chose to determine which specialization variants will also be disabled + */ + public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, DimensionSpacePoint $coveredDimensionSpacePoint, NodeVariantSelectionStrategy $nodeVariantSelectionStrategy): self + { + return new self($contentStreamId, $nodeAggregateId, $coveredDimensionSpacePoint, $nodeVariantSelectionStrategy); + } + /** * @param array $array */ diff --git a/Classes/Feature/NodeDisabling/Command/EnableNodeAggregate.php b/Classes/Feature/NodeDisabling/Command/EnableNodeAggregate.php index ca7a11e7..e4d36521 100644 --- a/Classes/Feature/NodeDisabling/Command/EnableNodeAggregate.php +++ b/Classes/Feature/NodeDisabling/Command/EnableNodeAggregate.php @@ -34,16 +34,32 @@ final class EnableNodeAggregate implements RebasableToOtherContentStreamsInterface, MatchableWithNodeIdToPublishOrDiscardInterface { - public function __construct( + + /** + * @param ContentStreamId $contentStreamId The content stream in which the enable operation is to be performed + * @param NodeAggregateId $nodeAggregateId The identifier of the node aggregate to enable + * @param DimensionSpacePoint $coveredDimensionSpacePoint The covered dimension space point of the node aggregate in which the user intends to enable it + * @param NodeVariantSelectionStrategy $nodeVariantSelectionStrategy The strategy the user chose to determine which specialization variants will also be enabled + */ + private function __construct( public readonly ContentStreamId $contentStreamId, public readonly NodeAggregateId $nodeAggregateId, - /** The covered dimension space point of the node aggregate in which the user intends to enable it */ public readonly DimensionSpacePoint $coveredDimensionSpacePoint, - /** The strategy the user chose to determine which specialization variants will also be disabled */ public readonly NodeVariantSelectionStrategy $nodeVariantSelectionStrategy, ) { } + /** + * @param ContentStreamId $contentStreamId The content stream in which the enable operation is to be performed + * @param NodeAggregateId $nodeAggregateId The identifier of the node aggregate to enable + * @param DimensionSpacePoint $coveredDimensionSpacePoint The covered dimension space point of the node aggregate in which the user intends to enable it + * @param NodeVariantSelectionStrategy $nodeVariantSelectionStrategy The strategy the user chose to determine which specialization variants will also be enabled + */ + public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, DimensionSpacePoint $coveredDimensionSpacePoint, NodeVariantSelectionStrategy $nodeVariantSelectionStrategy): self + { + return new self($contentStreamId, $nodeAggregateId, $coveredDimensionSpacePoint, $nodeVariantSelectionStrategy); + } + /** * @param array $array */ diff --git a/Classes/Feature/NodeDuplication/Command/CopyNodesRecursively.php b/Classes/Feature/NodeDuplication/Command/CopyNodesRecursively.php index 2102ca61..6fbefbce 100644 --- a/Classes/Feature/NodeDuplication/Command/CopyNodesRecursively.php +++ b/Classes/Feature/NodeDuplication/Command/CopyNodesRecursively.php @@ -42,51 +42,40 @@ final class CopyNodesRecursively implements MatchableWithNodeIdToPublishOrDiscardInterface, RebasableToOtherContentStreamsInterface { + /** + * @param ContentStreamId $contentStreamId The id of the content stream this command is to be handled in + * @param NodeSubtreeSnapshot $nodeTreeToInsert The snapshot of nodes to copy {@see CopyNodesRecursively::createFromSubgraphAndStartNode()} + * @param OriginDimensionSpacePoint $targetDimensionSpacePoint the dimension space point which is the target of the copy + * @param NodeAggregateId $targetParentNodeAggregateId Node aggregate id of the target node's parent. If not given, the node will be added as the parent's first child + * @param NodeAggregateId|null $targetSucceedingSiblingNodeAggregateId Node aggregate id of the target node's succeeding sibling (optional) + * @param NodeName|null $targetNodeName the root node name of the root-inserted-node + * @param NodeAggregateIdMapping $nodeAggregateIdMapping An assignment of "old" to "new" NodeAggregateIds ({@see NodeAggregateIdMapping}) + */ private function __construct( - /** - * The id of the content stream this command is to be handled in - * - * @var ContentStreamId - */ public readonly ContentStreamId $contentStreamId, - /** - * The to be copied node's node aggregate id - * - * @var NodeSubtreeSnapshot - */ public readonly NodeSubtreeSnapshot $nodeTreeToInsert, - /** - * the dimension space point which is the target of the copy - * - * @var OriginDimensionSpacePoint - */ public readonly OriginDimensionSpacePoint $targetDimensionSpacePoint, - /** - * Node aggregate id of the target node's parent (optional) - * - * If not given, the node will be added as a root node - * - * @var NodeAggregateId - */ public readonly NodeAggregateId $targetParentNodeAggregateId, - /** - * Node aggregate id of the target node's succeeding sibling (optional) - * - * If not given, the node will be added as the parent's first child - * - * @var NodeAggregateId|null - */ public readonly ?NodeAggregateId $targetSucceedingSiblingNodeAggregateId, - /** - * the root node name of the root-inserted-node - * - * @var NodeName|null - */ public readonly ?NodeName $targetNodeName, public readonly NodeAggregateIdMapping $nodeAggregateIdMapping ) { } + /** + * @param ContentStreamId $contentStreamId The id of the content stream this command is to be handled in + * @param NodeSubtreeSnapshot $nodeTreeToInsert The snapshot of nodes to copy {@see CopyNodesRecursively::createFromSubgraphAndStartNode()} + * @param OriginDimensionSpacePoint $targetDimensionSpacePoint the dimension space point which is the target of the copy + * @param NodeAggregateId $targetParentNodeAggregateId Node aggregate id of the target node's parent. If not given, the node will be added as the parent's first child + * @param NodeAggregateId|null $targetSucceedingSiblingNodeAggregateId Node aggregate id of the target node's succeeding sibling (optional) + * @param NodeName|null $targetNodeName the root node name of the root-inserted-node + * @param NodeAggregateIdMapping $nodeAggregateIdMapping An assignment of "old" to "new" NodeAggregateIds ({@see NodeAggregateIdMapping}) + */ + public static function create(ContentStreamId $contentStreamId, NodeSubtreeSnapshot $nodeTreeToInsert, OriginDimensionSpacePoint $targetDimensionSpacePoint, NodeAggregateId $targetParentNodeAggregateId, ?NodeAggregateId $targetSucceedingSiblingNodeAggregateId, ?NodeName $targetNodeName, NodeAggregateIdMapping $nodeAggregateIdMapping): self + { + return new self($contentStreamId, $nodeTreeToInsert, $targetDimensionSpacePoint, $targetParentNodeAggregateId, $targetSucceedingSiblingNodeAggregateId, $targetNodeName, $nodeAggregateIdMapping); + } + /** * @todo (could be an extra method) reference start node by address instead of passing it */ diff --git a/Classes/Feature/NodeModification/Command/SetNodeProperties.php b/Classes/Feature/NodeModification/Command/SetNodeProperties.php index 16a7dfaa..6950e7d0 100644 --- a/Classes/Feature/NodeModification/Command/SetNodeProperties.php +++ b/Classes/Feature/NodeModification/Command/SetNodeProperties.php @@ -33,11 +33,28 @@ */ final class SetNodeProperties implements CommandInterface { - public function __construct( + /** + * @param ContentStreamId $contentStreamId The content stream in which the set properties operation is to be performed + * @param NodeAggregateId $nodeAggregateId The id of the node aggregate to set the properties for + * @param OriginDimensionSpacePoint $originDimensionSpacePoint The dimension space point the properties should be changed in + * @param PropertyValuesToWrite $propertyValues Names and (unserialized) values of properties to set + */ + private function __construct( public readonly ContentStreamId $contentStreamId, public readonly NodeAggregateId $nodeAggregateId, public readonly OriginDimensionSpacePoint $originDimensionSpacePoint, public readonly PropertyValuesToWrite $propertyValues, ) { } + + /** + * @param ContentStreamId $contentStreamId The content stream in which the set properties operation is to be performed + * @param NodeAggregateId $nodeAggregateId The id of the node aggregate to set the properties for + * @param OriginDimensionSpacePoint $originDimensionSpacePoint The dimension space point the properties should be changed in + * @param PropertyValuesToWrite $propertyValues Names and (unserialized) values of properties to set + */ + public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, OriginDimensionSpacePoint $originDimensionSpacePoint, PropertyValuesToWrite $propertyValues): self + { + return new self($contentStreamId, $nodeAggregateId, $originDimensionSpacePoint, $propertyValues); + } } diff --git a/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php b/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php index 7f541669..91c58ac4 100644 --- a/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php +++ b/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php @@ -36,7 +36,14 @@ final class SetSerializedNodeProperties implements RebasableToOtherContentStreamsInterface, MatchableWithNodeIdToPublishOrDiscardInterface { - public function __construct( + + /** + * @param ContentStreamId $contentStreamId The content stream in which the set properties operation is to be performed + * @param NodeAggregateId $nodeAggregateId The id of the node aggregate to set the properties for + * @param OriginDimensionSpacePoint $originDimensionSpacePoint The dimension space point the properties should be changed in + * @param SerializedPropertyValues $propertyValues Names and (serialized) values of properties to set + */ + private function __construct( public readonly ContentStreamId $contentStreamId, public readonly NodeAggregateId $nodeAggregateId, public readonly OriginDimensionSpacePoint $originDimensionSpacePoint, @@ -44,6 +51,17 @@ public function __construct( ) { } + /** + * @param ContentStreamId $contentStreamId The content stream in which the set properties operation is to be performed + * @param NodeAggregateId $nodeAggregateId The id of the node aggregate to set the properties for + * @param OriginDimensionSpacePoint $originDimensionSpacePoint The dimension space point the properties should be changed in + * @param SerializedPropertyValues $propertyValues Names and (serialized) values of properties to set + */ + public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, OriginDimensionSpacePoint $originDimensionSpacePoint, SerializedPropertyValues $propertyValues): self + { + return new self($contentStreamId, $nodeAggregateId, $originDimensionSpacePoint, $propertyValues); + } + /** * @param array $array */ diff --git a/Classes/Feature/NodeModification/NodeModification.php b/Classes/Feature/NodeModification/NodeModification.php index 5784bf8a..93f87cb0 100644 --- a/Classes/Feature/NodeModification/NodeModification.php +++ b/Classes/Feature/NodeModification/NodeModification.php @@ -59,7 +59,7 @@ private function handleSetNodeProperties( $this->validateProperties($command->propertyValues, $nodeTypeName); - $lowLevelCommand = new SetSerializedNodeProperties( + $lowLevelCommand = SetSerializedNodeProperties::create( $command->contentStreamId, $command->nodeAggregateId, $command->originDimensionSpacePoint, diff --git a/Classes/Feature/NodeReferencing/Command/SetNodeReferences.php b/Classes/Feature/NodeReferencing/Command/SetNodeReferences.php index 4d3b0561..6a1c4f0b 100644 --- a/Classes/Feature/NodeReferencing/Command/SetNodeReferences.php +++ b/Classes/Feature/NodeReferencing/Command/SetNodeReferences.php @@ -18,6 +18,14 @@ */ final class SetNodeReferences implements CommandInterface { + + /** + * @param ContentStreamId $contentStreamId The content stream in which the create operation is to be performed + * @param NodeAggregateId $sourceNodeAggregateId The identifier of the node aggregate to set references + * @param OriginDimensionSpacePoint $sourceOriginDimensionSpacePoint The dimension space for which the references should be set + * @param ReferenceName $referenceName Name of the reference to set + * @param NodeReferencesToWrite $references Unserialized reference(s) to set + */ public function __construct( public readonly ContentStreamId $contentStreamId, public readonly NodeAggregateId $sourceNodeAggregateId, @@ -26,4 +34,16 @@ public function __construct( public readonly NodeReferencesToWrite $references, ) { } + + /** + * @param ContentStreamId $contentStreamId The content stream in which the create operation is to be performed + * @param NodeAggregateId $sourceNodeAggregateId The identifier of the node aggregate to set references + * @param OriginDimensionSpacePoint $sourceOriginDimensionSpacePoint The dimension space for which the references should be set + * @param ReferenceName $referenceName Name of the reference to set + * @param NodeReferencesToWrite $references Unserialized reference(s) to set + */ + public static function create(ContentStreamId $contentStreamId, NodeAggregateId $sourceNodeAggregateId, OriginDimensionSpacePoint $sourceOriginDimensionSpacePoint, ReferenceName $referenceName, NodeReferencesToWrite $references): self + { + return new self($contentStreamId, $sourceNodeAggregateId, $sourceOriginDimensionSpacePoint, $referenceName, $references); + } } diff --git a/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php b/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php index b711b9bd..9404160a 100644 --- a/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php +++ b/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php @@ -37,7 +37,14 @@ final class SetSerializedNodeReferences implements RebasableToOtherContentStreamsInterface, MatchableWithNodeIdToPublishOrDiscardInterface { - public function __construct( + /** + * @param ContentStreamId $contentStreamId The content stream in which the create operation is to be performed + * @param NodeAggregateId $sourceNodeAggregateId The identifier of the node aggregate to set references + * @param OriginDimensionSpacePoint $sourceOriginDimensionSpacePoint The dimension space for which the references should be set + * @param ReferenceName $referenceName Name of the reference to set + * @param SerializedNodeReferences $references Serialized reference(s) to set + */ + private function __construct( public readonly ContentStreamId $contentStreamId, public readonly NodeAggregateId $sourceNodeAggregateId, public readonly OriginDimensionSpacePoint $sourceOriginDimensionSpacePoint, @@ -46,6 +53,18 @@ public function __construct( ) { } + /** + * @param ContentStreamId $contentStreamId The content stream in which the create operation is to be performed + * @param NodeAggregateId $sourceNodeAggregateId The identifier of the node aggregate to set references + * @param OriginDimensionSpacePoint $sourceOriginDimensionSpacePoint The dimension space for which the references should be set + * @param ReferenceName $referenceName Name of the reference to set + * @param SerializedNodeReferences $references Serialized reference(s) to set + */ + public static function create(ContentStreamId $contentStreamId, NodeAggregateId $sourceNodeAggregateId, OriginDimensionSpacePoint $sourceOriginDimensionSpacePoint, ReferenceName $referenceName, SerializedNodeReferences $references): self + { + return new self($contentStreamId, $sourceNodeAggregateId, $sourceOriginDimensionSpacePoint, $referenceName, $references); + } + /** * @param array $array */ diff --git a/Classes/Feature/NodeReferencing/NodeReferencing.php b/Classes/Feature/NodeReferencing/NodeReferencing.php index 8b22aa5c..e74797f6 100644 --- a/Classes/Feature/NodeReferencing/NodeReferencing.php +++ b/Classes/Feature/NodeReferencing/NodeReferencing.php @@ -70,7 +70,7 @@ private function handleSetNodeReferences( } } - $lowLevelCommand = new SetSerializedNodeReferences( + $lowLevelCommand = SetSerializedNodeReferences::create( $command->contentStreamId, $command->sourceNodeAggregateId, $command->sourceOriginDimensionSpacePoint, diff --git a/Classes/Feature/NodeRemoval/Command/RemoveNodeAggregate.php b/Classes/Feature/NodeRemoval/Command/RemoveNodeAggregate.php index b1540c02..8016beda 100644 --- a/Classes/Feature/NodeRemoval/Command/RemoveNodeAggregate.php +++ b/Classes/Feature/NodeRemoval/Command/RemoveNodeAggregate.php @@ -32,6 +32,10 @@ final class RemoveNodeAggregate implements RebasableToOtherContentStreamsInterface, MatchableWithNodeIdToPublishOrDiscardInterface { + + /** + * @param ContentStreamId $contentStreamId + */ public function __construct( public readonly ContentStreamId $contentStreamId, public readonly NodeAggregateId $nodeAggregateId, @@ -51,10 +55,15 @@ public function __construct( * That's why we need this field: For the Neos UI, it stores the document node of the removed node * (see Remove.php), as that is what the UI needs lateron for the change display. */ - public readonly ?NodeAggregateId $removalAttachmentPoint = null + public readonly ?NodeAggregateId $removalAttachmentPoint ) { } + public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, DimensionSpacePoint $coveredDimensionSpacePoint, NodeVariantSelectionStrategy $nodeVariantSelectionStrategy): self + { + return new self($contentStreamId, $nodeAggregateId, $coveredDimensionSpacePoint, $nodeVariantSelectionStrategy, null); + } + /** * @param array $array */ @@ -71,6 +80,15 @@ public static function fromArray(array $array): self ); } + /** + * @param NodeAggregateId $removalAttachmentPoint + * @internal + */ + public function withRemovalAttachmentPoint(NodeAggregateId $removalAttachmentPoint): self + { + return new self($this->contentStreamId, $this->nodeAggregateId, $this->coveredDimensionSpacePoint, $this->nodeVariantSelectionStrategy, $removalAttachmentPoint); + } + /** * @return array */ diff --git a/Classes/Feature/NodeRenaming/Command/ChangeNodeAggregateName.php b/Classes/Feature/NodeRenaming/Command/ChangeNodeAggregateName.php index 23d611a4..45ca5336 100644 --- a/Classes/Feature/NodeRenaming/Command/ChangeNodeAggregateName.php +++ b/Classes/Feature/NodeRenaming/Command/ChangeNodeAggregateName.php @@ -35,13 +35,29 @@ final class ChangeNodeAggregateName implements RebasableToOtherContentStreamsInterface, MatchableWithNodeIdToPublishOrDiscardInterface { - public function __construct( + + /** + * @param ContentStreamId $contentStreamId The content stream in which the operation is to be performed + * @param NodeAggregateId $nodeAggregateId The identifier of the node aggregate to rename + * @param NodeName $newNodeName The new name of the node aggregate + */ + private function __construct( public readonly ContentStreamId $contentStreamId, public readonly NodeAggregateId $nodeAggregateId, public readonly NodeName $newNodeName, ) { } + /** + * @param ContentStreamId $contentStreamId The content stream in which the operation is to be performed + * @param NodeAggregateId $nodeAggregateId The identifier of the node aggregate to rename + * @param NodeName $newNodeName The new name of the node aggregate + */ + public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, NodeName $newNodeName): self + { + return new self($contentStreamId, $nodeAggregateId, $newNodeName); + } + /** * @param array $array */ diff --git a/Classes/Feature/NodeTypeChange/Command/ChangeNodeAggregateType.php b/Classes/Feature/NodeTypeChange/Command/ChangeNodeAggregateType.php index eab3b53f..48d8d262 100644 --- a/Classes/Feature/NodeTypeChange/Command/ChangeNodeAggregateType.php +++ b/Classes/Feature/NodeTypeChange/Command/ChangeNodeAggregateType.php @@ -37,23 +37,34 @@ final class ChangeNodeAggregateType implements RebasableToOtherContentStreamsInterface, MatchableWithNodeIdToPublishOrDiscardInterface { - public function __construct( + + /** + * @param ContentStreamId $contentStreamId The content stream in which the operation is to be performed + * @param NodeAggregateId $nodeAggregateId The unique identifier of the node aggregate to change + * @param NodeTypeName $newNodeTypeName Name of the new node type + * @param NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy $strategy Strategy for conflicts on affected child nodes ({@see NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy}) + * @param NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds Predefined aggregate ids of any tethered child nodes for the new node type per path. For any tethered node that has no matching entry in this set, the node aggregate id is generated randomly. Since tethered nodes may have tethered child nodes themselves, this works for multiple levels ({@see self::withTetheredDescendantNodeAggregateIds()}) + */ + private function __construct( public readonly ContentStreamId $contentStreamId, public readonly NodeAggregateId $nodeAggregateId, public readonly NodeTypeName $newNodeTypeName, public readonly NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy $strategy, - /** - * NodeAggregateIds for tethered descendants (optional). - * - * If the given node type declares tethered child nodes, you may predefine their node aggregate ids - * using this assignment registry. - * Since tethered child nodes may have tethered child nodes themselves, - * this registry is indexed using relative node paths to the node to create in the first place. - */ - public readonly ?NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds = null + public readonly NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds, ) { } + /** + * @param ContentStreamId $contentStreamId The content stream in which the operation is to be performed + * @param NodeAggregateId $nodeAggregateId The unique identifier of the node aggregate to change + * @param NodeTypeName $newNodeTypeName Name of the new node type + * @param NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy $strategy Strategy for conflicts on affected child nodes ({@see NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy}) + */ + public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, NodeTypeName $newNodeTypeName, NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy $strategy): self + { + return new self($contentStreamId, $nodeAggregateId, $newNodeTypeName, $strategy, NodeAggregateIdsByNodePaths::createEmpty()); + } + /** * @param array $array */ @@ -66,7 +77,7 @@ public static function fromArray(array $array): self NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy::from($array['strategy']), isset($array['tetheredDescendantNodeAggregateIds']) ? NodeAggregateIdsByNodePaths::fromArray($array['tetheredDescendantNodeAggregateIds']) - : null + : NodeAggregateIdsByNodePaths::createEmpty() ); } @@ -106,9 +117,8 @@ public function jsonSerialize(): array * * Is needed to make this command fully deterministic before storing it at the events. */ - public function withTetheredDescendantNodeAggregateIds( - NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds - ): self { + public function withTetheredDescendantNodeAggregateIds(NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds): self + { return new self( $this->contentStreamId, $this->nodeAggregateId, diff --git a/Classes/Feature/NodeTypeChange/NodeTypeChange.php b/Classes/Feature/NodeTypeChange/NodeTypeChange.php index 6db1e898..f1740925 100644 --- a/Classes/Feature/NodeTypeChange/NodeTypeChange.php +++ b/Classes/Feature/NodeTypeChange/NodeTypeChange.php @@ -207,7 +207,7 @@ private function handleChangeNodeAggregateType( ); if ($tetheredNode === null) { $tetheredNodeAggregateId = $command->tetheredDescendantNodeAggregateIds - ?->getNodeAggregateId(NodePath::fromString($tetheredNodeName->value)) + ->getNodeAggregateId(NodePath::fromString($tetheredNodeName->value)) ?: NodeAggregateId::create(); array_push($events, ...iterator_to_array($this->createEventsForMissingTetheredNode( $nodeAggregate, diff --git a/Classes/Feature/NodeVariation/Command/CreateNodeVariant.php b/Classes/Feature/NodeVariation/Command/CreateNodeVariant.php index a31a1d65..d9660530 100644 --- a/Classes/Feature/NodeVariation/Command/CreateNodeVariant.php +++ b/Classes/Feature/NodeVariation/Command/CreateNodeVariant.php @@ -35,7 +35,13 @@ final class CreateNodeVariant implements RebasableToOtherContentStreamsInterface, MatchableWithNodeIdToPublishOrDiscardInterface { - public function __construct( + /** + * @param ContentStreamId $contentStreamId The content stream in which the create operation is to be performed + * @param NodeAggregateId $nodeAggregateId The identifier of the affected node aggregate + * @param OriginDimensionSpacePoint $sourceOrigin Dimension Space Point from which the node is to be copied from + * @param OriginDimensionSpacePoint $targetOrigin Dimension Space Point to which the node is to be copied to + */ + private function __construct( public readonly ContentStreamId $contentStreamId, public readonly NodeAggregateId $nodeAggregateId, public readonly OriginDimensionSpacePoint $sourceOrigin, @@ -43,6 +49,17 @@ public function __construct( ) { } + /** + * @param ContentStreamId $contentStreamId The content stream in which the create operation is to be performed + * @param NodeAggregateId $nodeAggregateId The identifier of the affected node aggregate + * @param OriginDimensionSpacePoint $sourceOrigin Dimension Space Point from which the node is to be copied from + * @param OriginDimensionSpacePoint $targetOrigin Dimension Space Point to which the node is to be copied to + */ + public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, OriginDimensionSpacePoint $sourceOrigin, OriginDimensionSpacePoint $targetOrigin): self + { + return new self($contentStreamId, $nodeAggregateId, $sourceOrigin, $targetOrigin); + } + /** * @param array $array */ diff --git a/Classes/Feature/RootNodeCreation/Command/CreateRootNodeAggregateWithNode.php b/Classes/Feature/RootNodeCreation/Command/CreateRootNodeAggregateWithNode.php index 0cd4720d..6ca25891 100644 --- a/Classes/Feature/RootNodeCreation/Command/CreateRootNodeAggregateWithNode.php +++ b/Classes/Feature/RootNodeCreation/Command/CreateRootNodeAggregateWithNode.php @@ -33,13 +33,30 @@ final class CreateRootNodeAggregateWithNode implements \JsonSerializable, RebasableToOtherContentStreamsInterface { - public function __construct( + + /** + * @param ContentStreamId $contentStreamId The content stream in which the root node should be created in + * @param NodeAggregateId $nodeAggregateId The id of the root node aggregate to create + * @param NodeTypeName $nodeTypeName Name of type of the new node to create + */ + private function __construct( public readonly ContentStreamId $contentStreamId, public readonly NodeAggregateId $nodeAggregateId, public readonly NodeTypeName $nodeTypeName, ) { } + /** + * @param ContentStreamId $contentStreamId The content stream in which the root node should be created in + * @param NodeAggregateId $nodeAggregateId The id of the root node aggregate to create + * @param NodeTypeName $nodeTypeName Name of type of the new node to create + */ + public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, NodeTypeName $nodeTypeName): self + { + return new self($contentStreamId, $nodeAggregateId, $nodeTypeName); + } + + /** * @param array $array */ diff --git a/Classes/Feature/RootNodeCreation/Command/UpdateRootNodeAggregateDimensions.php b/Classes/Feature/RootNodeCreation/Command/UpdateRootNodeAggregateDimensions.php index 1c743b08..4aa92c3e 100644 --- a/Classes/Feature/RootNodeCreation/Command/UpdateRootNodeAggregateDimensions.php +++ b/Classes/Feature/RootNodeCreation/Command/UpdateRootNodeAggregateDimensions.php @@ -31,12 +31,26 @@ final class UpdateRootNodeAggregateDimensions implements \JsonSerializable, RebasableToOtherContentStreamsInterface { - public function __construct( + + /** + * @param ContentStreamId $contentStreamId The content stream which the dimensions should be updated in + * @param NodeAggregateId $nodeAggregateId The id of the node aggregate that should be updated + */ + private function __construct( public readonly ContentStreamId $contentStreamId, - public readonly NodeAggregateId $nodeAggregateId + public readonly NodeAggregateId $nodeAggregateId, ) { } + /** + * @param ContentStreamId $contentStreamId The content stream which the dimensions should be updated in + * @param NodeAggregateId $nodeAggregateId The id of the node aggregate that should be updated + */ + public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId): self + { + return new self($contentStreamId, $nodeAggregateId); + } + /** * @param array $array */ diff --git a/Classes/Feature/WorkspaceCommandHandler.php b/Classes/Feature/WorkspaceCommandHandler.php index 9e059f91..d3bd1557 100644 --- a/Classes/Feature/WorkspaceCommandHandler.php +++ b/Classes/Feature/WorkspaceCommandHandler.php @@ -139,7 +139,7 @@ private function handleCreateWorkspace( // When the workspace is created, we first have to fork the content stream $contentRepository->handle( - new ForkContentStream( + ForkContentStream::create( $command->newContentStreamId, $baseWorkspace->currentContentStreamId, ) @@ -205,7 +205,7 @@ private function handleCreateRootWorkspace( $newContentStreamId = $command->newContentStreamId; $contentRepository->handle( - new CreateContentStream( + CreateContentStream::create( $newContentStreamId, ) )->block(); @@ -250,7 +250,7 @@ private function handlePublishWorkspace( // After publishing a workspace, we need to again fork from Base. $newContentStream = ContentStreamId::create(); $contentRepository->handle( - new ForkContentStream( + ForkContentStream::create( $newContentStream, $baseWorkspace->currentContentStreamId, ) @@ -367,7 +367,7 @@ private function handleRebaseWorkspace( // - extract the commands from the to-be-rebased content stream; and applies them on the new content stream $rebasedContentStream = $command->rebasedContentStreamId; $contentRepository->handle( - new ForkContentStream( + ForkContentStream::create( $rebasedContentStream, $baseWorkspace->currentContentStreamId, ) @@ -529,7 +529,7 @@ private function handlePublishIndividualNodesFromWorkspace( // 2) fork a new contentStream, based on the base WS, and apply MATCHING $matchingContentStream = $command->contentStreamIdForMatchingPart; $contentRepository->handle( - new ForkContentStream( + ForkContentStream::create( $matchingContentStream, $baseWorkspace->currentContentStreamId, ) @@ -549,7 +549,7 @@ private function handlePublishIndividualNodesFromWorkspace( // 3) fork a new contentStream, based on the matching content stream, and apply REST $remainingContentStream = $command->contentStreamIdForRemainingPart; $contentRepository->handle( - new ForkContentStream( + ForkContentStream::create( $remainingContentStream, $matchingContentStream, ) @@ -590,7 +590,7 @@ private function handlePublishIndividualNodesFromWorkspace( // to avoid dangling content streams, we need to remove our temporary content stream (whose events // have already been published) - $contentRepository->handle(new RemoveContentStream( + $contentRepository->handle(RemoveContentStream::create( $matchingContentStream )); @@ -645,7 +645,7 @@ private function handleDiscardIndividualNodesFromWorkspace( // 2) fork a new contentStream, based on the base WS, and apply the commands to keep $newContentStream = $command->newContentStreamId; $contentRepository->handle( - new ForkContentStream( + ForkContentStream::create( $newContentStream, $baseWorkspace->currentContentStreamId, ) @@ -711,7 +711,7 @@ private function handleDiscardWorkspace( $newContentStream = $command->newContentStreamId; $contentRepository->handle( - new ForkContentStream( + ForkContentStream::create( $newContentStream, $baseWorkspace->currentContentStreamId, ) @@ -757,7 +757,7 @@ private function handleChangeBaseWorkspace( $this->requireNonCircularRelationBetweenWorkspaces($workspace, $baseWorkspace, $contentRepository); $contentRepository->handle( - new ForkContentStream( + ForkContentStream::create( $command->newContentStreamId, $baseWorkspace->currentContentStreamId, ) @@ -789,7 +789,7 @@ private function handleDeleteWorkspace( $workspace = $this->requireWorkspace($command->workspaceName, $contentRepository); $contentRepository->handle( - new RemoveContentStream( + RemoveContentStream::create( $workspace->currentContentStreamId ) )->block(); diff --git a/Classes/Feature/WorkspaceCreation/Command/CreateRootWorkspace.php b/Classes/Feature/WorkspaceCreation/Command/CreateRootWorkspace.php index 9187d3bc..82b6adaf 100644 --- a/Classes/Feature/WorkspaceCreation/Command/CreateRootWorkspace.php +++ b/Classes/Feature/WorkspaceCreation/Command/CreateRootWorkspace.php @@ -29,11 +29,28 @@ */ final class CreateRootWorkspace implements CommandInterface { - public function __construct( + /** + * @param WorkspaceName $workspaceName Unique name of the workspace to create + * @param WorkspaceTitle $workspaceTitle Human-readable title of the workspace to create (can be changed) + * @param WorkspaceDescription $workspaceDescription Description of the workspace to create (can be changed) + * @param ContentStreamId $newContentStreamId The id of the content stream the new workspace is assigned to initially + */ + private function __construct( public readonly WorkspaceName $workspaceName, public readonly WorkspaceTitle $workspaceTitle, public readonly WorkspaceDescription $workspaceDescription, public readonly ContentStreamId $newContentStreamId ) { } + + /** + * @param WorkspaceName $workspaceName Name of the workspace to create + * @param WorkspaceTitle $workspaceTitle Human-readable title of the workspace to create (can be changed) + * @param WorkspaceDescription $workspaceDescription Description of the workspace to create (can be changed) + * @param ContentStreamId $newContentStreamId The id of the content stream the new workspace is assigned to initially + */ + public static function create(WorkspaceName $workspaceName, WorkspaceTitle $workspaceTitle, WorkspaceDescription $workspaceDescription, ContentStreamId $newContentStreamId): self + { + return new self($workspaceName, $workspaceTitle, $workspaceDescription, $newContentStreamId); + } } diff --git a/Classes/Feature/WorkspaceCreation/Command/CreateWorkspace.php b/Classes/Feature/WorkspaceCreation/Command/CreateWorkspace.php index 4bfb71c0..9971f046 100644 --- a/Classes/Feature/WorkspaceCreation/Command/CreateWorkspace.php +++ b/Classes/Feature/WorkspaceCreation/Command/CreateWorkspace.php @@ -28,17 +28,34 @@ */ final class CreateWorkspace implements CommandInterface { - public function __construct( + /** + * @param WorkspaceName $workspaceName Unique name of the workspace to create + * @param WorkspaceName $baseWorkspaceName Name of the base workspace + * @param WorkspaceTitle $workspaceTitle Human-readable title of the workspace to create (can be changed) + * @param WorkspaceDescription $workspaceDescription Description of the workspace to create (can be changed) + * @param ContentStreamId $newContentStreamId The id of the content stream the new workspace is assigned to initially + * @param UserId|null $workspaceOwner Owner of the new workspace (optional) + */ + private function __construct( public readonly WorkspaceName $workspaceName, public readonly WorkspaceName $baseWorkspaceName, public readonly WorkspaceTitle $workspaceTitle, public readonly WorkspaceDescription $workspaceDescription, - /** - * the content stream identifier for the content stream which is created together with the to-be-created - * workspace - */ public readonly ContentStreamId $newContentStreamId, - public readonly ?UserId $workspaceOwner = null + public readonly ?UserId $workspaceOwner, ) { } + + /** + * @param WorkspaceName $workspaceName Unique name of the workspace to create + * @param WorkspaceName $baseWorkspaceName Name of the base workspace + * @param WorkspaceTitle $workspaceTitle Human-readable title of the workspace to create (can be changed) + * @param WorkspaceDescription $workspaceDescription Description of the workspace to create (can be changed) + * @param ContentStreamId $newContentStreamId The id of the content stream the new workspace is assigned to initially + * @param UserId|null $workspaceOwner Owner of the new workspace (optional) + */ + public static function create(WorkspaceName $workspaceName, WorkspaceName $baseWorkspaceName, WorkspaceTitle $workspaceTitle, WorkspaceDescription $workspaceDescription, ContentStreamId $newContentStreamId, ?UserId $workspaceOwner = null): self + { + return new self($workspaceName, $baseWorkspaceName, $workspaceTitle, $workspaceDescription, $newContentStreamId, $workspaceOwner); + } } diff --git a/Classes/Feature/WorkspaceModification/Command/ChangeBaseWorkspace.php b/Classes/Feature/WorkspaceModification/Command/ChangeBaseWorkspace.php index c20569fb..16bf8773 100644 --- a/Classes/Feature/WorkspaceModification/Command/ChangeBaseWorkspace.php +++ b/Classes/Feature/WorkspaceModification/Command/ChangeBaseWorkspace.php @@ -15,10 +15,24 @@ */ final class ChangeBaseWorkspace implements CommandInterface { - public function __construct( + /** + * @param WorkspaceName $workspaceName Name of the affected workspace + * @param WorkspaceName $baseWorkspaceName Name of the new base workspace + * @param ContentStreamId $newContentStreamId The id of the new content stream id that will be assigned to the workspace + */ + private function __construct( public readonly WorkspaceName $workspaceName, public readonly WorkspaceName $baseWorkspaceName, public readonly ContentStreamId $newContentStreamId, ) { } + + /** + * @param WorkspaceName $workspaceName Name of the affected workspace + * @param WorkspaceName $baseWorkspaceName Name of the new base workspace + */ + public static function create(WorkspaceName $workspaceName, WorkspaceName $baseWorkspaceName): self + { + return new self($workspaceName, $baseWorkspaceName, ContentStreamId::create()); + } } diff --git a/Classes/Feature/WorkspaceModification/Command/ChangeWorkspaceOwner.php b/Classes/Feature/WorkspaceModification/Command/ChangeWorkspaceOwner.php index 9b018d25..228321c4 100644 --- a/Classes/Feature/WorkspaceModification/Command/ChangeWorkspaceOwner.php +++ b/Classes/Feature/WorkspaceModification/Command/ChangeWorkspaceOwner.php @@ -15,9 +15,22 @@ */ final class ChangeWorkspaceOwner implements CommandInterface { - public function __construct( + /** + * @param WorkspaceName $workspaceName Name of the workspace to change the owner for + * @param string|null $newWorkspaceOwner The id of the new workspace owner or NULL to remove the owner + */ + private function __construct( public readonly WorkspaceName $workspaceName, public readonly ?string $newWorkspaceOwner, ) { } + + /** + * @param WorkspaceName $workspaceName Name of the workspace to change the owner for + * @param string|null $newWorkspaceOwner The id of the new workspace owner or NULL to remove the owner + */ + public static function create(WorkspaceName $workspaceName, ?string $newWorkspaceOwner): self + { + return new self($workspaceName, $newWorkspaceOwner); + } } diff --git a/Classes/Feature/WorkspaceModification/Command/DeleteWorkspace.php b/Classes/Feature/WorkspaceModification/Command/DeleteWorkspace.php index 3def28f9..f685b459 100644 --- a/Classes/Feature/WorkspaceModification/Command/DeleteWorkspace.php +++ b/Classes/Feature/WorkspaceModification/Command/DeleteWorkspace.php @@ -14,8 +14,19 @@ */ final class DeleteWorkspace implements CommandInterface { - public function __construct( + /** + * @param WorkspaceName $workspaceName Name of the workspace to delete + */ + private function __construct( public readonly WorkspaceName $workspaceName, ) { } + + /** + * @param WorkspaceName $workspaceName Name of the workspace to delete + */ + public static function create(WorkspaceName $workspaceName): self + { + return new self($workspaceName); + } } diff --git a/Classes/Feature/WorkspaceModification/Command/RenameWorkspace.php b/Classes/Feature/WorkspaceModification/Command/RenameWorkspace.php index 6fec762b..4f2fc517 100644 --- a/Classes/Feature/WorkspaceModification/Command/RenameWorkspace.php +++ b/Classes/Feature/WorkspaceModification/Command/RenameWorkspace.php @@ -16,10 +16,25 @@ */ final class RenameWorkspace implements CommandInterface { - public function __construct( + /** + * @param WorkspaceName $workspaceName Name of the workspace to rename + * @param WorkspaceTitle $workspaceTitle New title of the workspace + * @param WorkspaceDescription $workspaceDescription New description of the workspace + */ + private function __construct( public readonly WorkspaceName $workspaceName, public readonly WorkspaceTitle $workspaceTitle, public readonly WorkspaceDescription $workspaceDescription, ) { } + + /** + * @param WorkspaceName $workspaceName Name of the workspace to rename + * @param WorkspaceTitle $workspaceTitle New title of the workspace + * @param WorkspaceDescription $workspaceDescription New description of the workspace + */ + public static function create(WorkspaceName $workspaceName, WorkspaceTitle $workspaceTitle, WorkspaceDescription $workspaceDescription): self + { + return new self($workspaceName, $workspaceTitle, $workspaceDescription); + } } diff --git a/Classes/Feature/WorkspacePublication/Command/DiscardIndividualNodesFromWorkspace.php b/Classes/Feature/WorkspacePublication/Command/DiscardIndividualNodesFromWorkspace.php index efb5e66e..44b3e6d4 100644 --- a/Classes/Feature/WorkspacePublication/Command/DiscardIndividualNodesFromWorkspace.php +++ b/Classes/Feature/WorkspacePublication/Command/DiscardIndividualNodesFromWorkspace.php @@ -17,7 +17,6 @@ use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Dto\NodeIdsToPublishOrDiscard; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; -use Neos\ContentRepository\Core\SharedModel\User\UserId; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** @@ -27,17 +26,22 @@ */ final class DiscardIndividualNodesFromWorkspace implements CommandInterface { + /** + * @param WorkspaceName $workspaceName Name of the affected workspace + * @param NodeIdsToPublishOrDiscard $nodesToDiscard Ids of the nodes to be discarded + * @param ContentStreamId $newContentStreamId The id of the new content stream, that will contain the remaining changes which were not discarded + */ private function __construct( public readonly WorkspaceName $workspaceName, public readonly NodeIdsToPublishOrDiscard $nodesToDiscard, - /** - * Content Stream Id of the newly created fork, which contains the remaining changes which were - * not removed - */ public readonly ContentStreamId $newContentStreamId ) { } + /** + * @param WorkspaceName $workspaceName Name of the affected workspace + * @param NodeIdsToPublishOrDiscard $nodesToDiscard Ids of the nodes to be discarded + */ public static function create( WorkspaceName $workspaceName, NodeIdsToPublishOrDiscard $nodesToDiscard, @@ -52,11 +56,8 @@ public static function create( /** * Call this method if you want to run this command fully deterministically, f.e. during test cases */ - public static function createFullyDeterministic( - WorkspaceName $workspaceName, - NodeIdsToPublishOrDiscard $nodesToDiscard, - ContentStreamId $newContentStreamId - ): self { - return new self($workspaceName, $nodesToDiscard, $newContentStreamId); + public function withNewContentStreamId(ContentStreamId $newContentStreamId): self + { + return new self($this->workspaceName, $this->nodesToDiscard, $newContentStreamId); } } diff --git a/Classes/Feature/WorkspacePublication/Command/DiscardWorkspace.php b/Classes/Feature/WorkspacePublication/Command/DiscardWorkspace.php index 465394ee..3e05fe90 100644 --- a/Classes/Feature/WorkspacePublication/Command/DiscardWorkspace.php +++ b/Classes/Feature/WorkspacePublication/Command/DiscardWorkspace.php @@ -25,16 +25,19 @@ */ final class DiscardWorkspace implements CommandInterface { + /** + * @param WorkspaceName $workspaceName Name of the affected workspace + * @param ContentStreamId $newContentStreamId The id of the newly created content stream that will contain the remaining changes that were not discarded + */ private function __construct( public readonly WorkspaceName $workspaceName, - /** - * Content Stream ID of the newly created fork, which contains the remaining changes - * which were not removed - */ public readonly ContentStreamId $newContentStreamId ) { } + /** + * @param WorkspaceName $workspaceName Name of the affected workspace + */ public static function create(WorkspaceName $workspaceName): self { return new self($workspaceName, ContentStreamId::create()); @@ -43,10 +46,8 @@ public static function create(WorkspaceName $workspaceName): self /** * Call this method if you want to run this command fully deterministically, f.e. during test cases */ - public static function createFullyDeterministic( - WorkspaceName $workspaceName, - ContentStreamId $newContentStreamId - ): self { - return new self($workspaceName, $newContentStreamId); + public function withNewContentStreamId(ContentStreamId $newContentStreamId): self + { + return new self($this->workspaceName, $newContentStreamId); } } diff --git a/Classes/Feature/WorkspacePublication/Command/PublishIndividualNodesFromWorkspace.php b/Classes/Feature/WorkspacePublication/Command/PublishIndividualNodesFromWorkspace.php index 6b26dd1a..dbc450bb 100644 --- a/Classes/Feature/WorkspacePublication/Command/PublishIndividualNodesFromWorkspace.php +++ b/Classes/Feature/WorkspacePublication/Command/PublishIndividualNodesFromWorkspace.php @@ -26,6 +26,12 @@ */ final class PublishIndividualNodesFromWorkspace implements CommandInterface { + /** + * @param WorkspaceName $workspaceName Name of the affected workspace + * @param NodeIdsToPublishOrDiscard $nodesToPublish Ids of the nodes to publish or discard + * @param ContentStreamId $contentStreamIdForMatchingPart The id of the new content stream that will contain all events to be published + * @param ContentStreamId $contentStreamIdForRemainingPart The id of the new content stream that will contain all remaining events + */ private function __construct( public readonly WorkspaceName $workspaceName, public readonly NodeIdsToPublishOrDiscard $nodesToPublish, @@ -50,10 +56,11 @@ private function __construct( ) { } - public static function create( - WorkspaceName $workspaceName, - NodeIdsToPublishOrDiscard $nodesToPublish, - ): self { + /** + * @param WorkspaceName $workspaceName Name of the affected workspace + * @param NodeIdsToPublishOrDiscard $nodesToPublish Ids of the nodes to publish or discard + */ + public static function create(WorkspaceName $workspaceName, NodeIdsToPublishOrDiscard $nodesToPublish): self { return new self( $workspaceName, $nodesToPublish, @@ -62,20 +69,13 @@ public static function create( ); } - /** - * Call this method if you want to run this command fully deterministically, f.e. during test cases - */ - public static function createFullyDeterministic( - WorkspaceName $workspaceName, - NodeIdsToPublishOrDiscard $nodesToPublish, - ContentStreamId $contentStreamIdForMatchingPart, - ContentStreamId $contentStreamIdForRemainingPart - ): self { - return new self( - $workspaceName, - $nodesToPublish, - $contentStreamIdForMatchingPart, - $contentStreamIdForRemainingPart - ); + public function withContentStreamIdForMatchingPart(ContentStreamId $contentStreamIdForMatchingPart): self + { + return new self($this->workspaceName, $this->nodesToPublish, $contentStreamIdForMatchingPart, $this->contentStreamIdForRemainingPart); + } + + public function withContentStreamIdForRemainingPart(ContentStreamId $contentStreamIdForRemainingPart): self + { + return new self($this->workspaceName, $this->nodesToPublish, $this->contentStreamIdForMatchingPart, $contentStreamIdForRemainingPart); } } diff --git a/Classes/Feature/WorkspacePublication/Command/PublishWorkspace.php b/Classes/Feature/WorkspacePublication/Command/PublishWorkspace.php index 74a070d3..7d72b392 100644 --- a/Classes/Feature/WorkspacePublication/Command/PublishWorkspace.php +++ b/Classes/Feature/WorkspacePublication/Command/PublishWorkspace.php @@ -24,8 +24,21 @@ */ final class PublishWorkspace implements CommandInterface { - public function __construct( + + /** + * @param WorkspaceName $workspaceName Name of the workspace to publish + */ + private function __construct( public readonly WorkspaceName $workspaceName, - ) { + ) + { + } + + /** + * @param WorkspaceName $workspaceName Name of the workspace to publish + */ + public static function create(WorkspaceName $workspaceName): self + { + return new self($workspaceName); } } diff --git a/Classes/Feature/WorkspaceRebase/Command/RebaseWorkspace.php b/Classes/Feature/WorkspaceRebase/Command/RebaseWorkspace.php index b7f673cc..6ba70221 100644 --- a/Classes/Feature/WorkspaceRebase/Command/RebaseWorkspace.php +++ b/Classes/Feature/WorkspaceRebase/Command/RebaseWorkspace.php @@ -25,13 +25,15 @@ */ final class RebaseWorkspace implements CommandInterface { - public function __construct( + /** + * @param WorkspaceName $workspaceName Name of the workspace that should be rebased + * @param ContentStreamId $rebasedContentStreamId The id of the new content stream which is created during the rebase + */ + private function __construct( public readonly WorkspaceName $workspaceName, - /** - * Name of the new content stream which is created during the rebase - */ public readonly ContentStreamId $rebasedContentStreamId - ) { + ) + { } public static function create(WorkspaceName $workspaceName): self @@ -42,10 +44,8 @@ public static function create(WorkspaceName $workspaceName): self /** * Call this method if you want to run this command fully deterministically, f.e. during test cases */ - public static function createFullyDeterministic( - WorkspaceName $workspaceName, - ContentStreamId $newContentStreamId - ): self { - return new self($workspaceName, $newContentStreamId); + public function withRebasedContentStreamId(ContentStreamId $newContentStreamId): self + { + return new self($this->workspaceName, $newContentStreamId); } } diff --git a/Classes/Service/ContentRepositoryBootstrapper.php b/Classes/Service/ContentRepositoryBootstrapper.php index 6ea64f0a..578fe1c1 100644 --- a/Classes/Service/ContentRepositoryBootstrapper.php +++ b/Classes/Service/ContentRepositoryBootstrapper.php @@ -46,7 +46,7 @@ public function getOrCreateLiveContentStream(): ContentStreamId } $liveContentStreamId = ContentStreamId::create(); $this->contentRepository->handle( - new CreateRootWorkspace( + CreateRootWorkspace::create( WorkspaceName::forLive(), WorkspaceTitle::fromString('Live'), WorkspaceDescription::fromString('Public live workspace'), @@ -73,7 +73,7 @@ public function getOrCreateRootNodeAggregate( // TODO make this case more explicit } catch (\Exception $exception) { $rootNodeAggregateId = NodeAggregateId::create(); - $this->contentRepository->handle(new CreateRootNodeAggregateWithNode( + $this->contentRepository->handle(CreateRootNodeAggregateWithNode::create( $contentStreamId, $rootNodeAggregateId, $rootNodeTypeName, diff --git a/Classes/Service/ContentStreamPruner.php b/Classes/Service/ContentStreamPruner.php index 8ae0894a..7868fbe0 100644 --- a/Classes/Service/ContentStreamPruner.php +++ b/Classes/Service/ContentStreamPruner.php @@ -52,9 +52,7 @@ public function prune(bool $removeTemporary = false): iterable foreach ($unusedContentStreams as $contentStream) { $this->lastCommandResult = $this->contentRepository->handle( - new RemoveContentStream( - $contentStream, - ) + RemoveContentStream::create($contentStream) ); } From fa65892caf329ec9984e1e90be089fb88d43e9c4 Mon Sep 17 00:00:00 2001 From: bwaidelich Date: Fri, 8 Sep 2023 20:05:25 +0200 Subject: [PATCH 4/5] Fix tethered descendant node ids in `NodeCreation::handleCreateNodeAggregateWithNode()` --- Classes/Feature/NodeCreation/NodeCreation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/Feature/NodeCreation/NodeCreation.php b/Classes/Feature/NodeCreation/NodeCreation.php index 46c15fd4..46ef4e6a 100644 --- a/Classes/Feature/NodeCreation/NodeCreation.php +++ b/Classes/Feature/NodeCreation/NodeCreation.php @@ -86,7 +86,7 @@ private function handleCreateNodeAggregateWithNode( ) ); if (!$command->tetheredDescendantNodeAggregateIds->isEmpty()) { - $command = $command->withTetheredDescendantNodeAggregateIds($command->tetheredDescendantNodeAggregateIds); + $lowLevelCommand = $lowLevelCommand->withTetheredDescendantNodeAggregateIds($command->tetheredDescendantNodeAggregateIds); } return $this->handleCreateNodeAggregateWithNodeAndSerializedProperties($lowLevelCommand, $contentRepository); From ae6645412ce9c641f4cb258980090d67f21d1d6c Mon Sep 17 00:00:00 2001 From: bwaidelich Date: Fri, 8 Sep 2023 21:43:35 +0200 Subject: [PATCH 5/5] Cosmetic tweaks to satisfy linter --- .../Command/AddDimensionShineThrough.php | 1 - .../Command/MoveDimensionSpacePoint.php | 1 - .../CreateNodeAggregateWithNodeAndSerializedProperties.php | 1 - .../Feature/NodeDisabling/Command/DisableNodeAggregate.php | 1 - Classes/Feature/NodeDisabling/Command/EnableNodeAggregate.php | 1 - .../NodeModification/Command/SetSerializedNodeProperties.php | 1 - Classes/Feature/NodeReferencing/Command/SetNodeReferences.php | 1 - Classes/Feature/NodeRemoval/Command/RemoveNodeAggregate.php | 1 - .../Feature/NodeRenaming/Command/ChangeNodeAggregateName.php | 1 - .../NodeTypeChange/Command/ChangeNodeAggregateType.php | 1 - .../Command/CreateRootNodeAggregateWithNode.php | 1 - .../Command/UpdateRootNodeAggregateDimensions.php | 1 - .../Command/PublishIndividualNodesFromWorkspace.php | 3 ++- .../Feature/WorkspacePublication/Command/PublishWorkspace.php | 4 +--- Classes/Feature/WorkspaceRebase/Command/RebaseWorkspace.php | 3 +-- 15 files changed, 4 insertions(+), 18 deletions(-) diff --git a/Classes/Feature/DimensionSpaceAdjustment/Command/AddDimensionShineThrough.php b/Classes/Feature/DimensionSpaceAdjustment/Command/AddDimensionShineThrough.php index cd4d3073..78097c5c 100644 --- a/Classes/Feature/DimensionSpaceAdjustment/Command/AddDimensionShineThrough.php +++ b/Classes/Feature/DimensionSpaceAdjustment/Command/AddDimensionShineThrough.php @@ -37,7 +37,6 @@ final class AddDimensionShineThrough implements \JsonSerializable, RebasableToOtherContentStreamsInterface { - /** * @param ContentStreamId $contentStreamId The id of the content stream to perform the operation in * @param DimensionSpacePoint $source source dimension space point diff --git a/Classes/Feature/DimensionSpaceAdjustment/Command/MoveDimensionSpacePoint.php b/Classes/Feature/DimensionSpaceAdjustment/Command/MoveDimensionSpacePoint.php index 02cea4f6..1cad2b90 100644 --- a/Classes/Feature/DimensionSpaceAdjustment/Command/MoveDimensionSpacePoint.php +++ b/Classes/Feature/DimensionSpaceAdjustment/Command/MoveDimensionSpacePoint.php @@ -33,7 +33,6 @@ final class MoveDimensionSpacePoint implements CommandInterface, RebasableToOtherContentStreamsInterface { - /** * @param ContentStreamId $contentStreamId The id of the content stream to perform the operation in * @param DimensionSpacePoint $source source dimension space point diff --git a/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php b/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php index 14e8cb2e..bd9edf3a 100644 --- a/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php +++ b/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php @@ -38,7 +38,6 @@ final class CreateNodeAggregateWithNodeAndSerializedProperties implements RebasableToOtherContentStreamsInterface, MatchableWithNodeIdToPublishOrDiscardInterface { - /** * @param ContentStreamId $contentStreamId The content stream in which the create operation is to be performed * @param NodeAggregateId $nodeAggregateId The unique identifier of the node aggregate to create diff --git a/Classes/Feature/NodeDisabling/Command/DisableNodeAggregate.php b/Classes/Feature/NodeDisabling/Command/DisableNodeAggregate.php index 05ab0422..1d65963c 100644 --- a/Classes/Feature/NodeDisabling/Command/DisableNodeAggregate.php +++ b/Classes/Feature/NodeDisabling/Command/DisableNodeAggregate.php @@ -34,7 +34,6 @@ final class DisableNodeAggregate implements RebasableToOtherContentStreamsInterface, MatchableWithNodeIdToPublishOrDiscardInterface { - /** * @param ContentStreamId $contentStreamId The content stream in which the disable operation is to be performed * @param NodeAggregateId $nodeAggregateId The identifier of the node aggregate to disable diff --git a/Classes/Feature/NodeDisabling/Command/EnableNodeAggregate.php b/Classes/Feature/NodeDisabling/Command/EnableNodeAggregate.php index e4d36521..5bce9711 100644 --- a/Classes/Feature/NodeDisabling/Command/EnableNodeAggregate.php +++ b/Classes/Feature/NodeDisabling/Command/EnableNodeAggregate.php @@ -34,7 +34,6 @@ final class EnableNodeAggregate implements RebasableToOtherContentStreamsInterface, MatchableWithNodeIdToPublishOrDiscardInterface { - /** * @param ContentStreamId $contentStreamId The content stream in which the enable operation is to be performed * @param NodeAggregateId $nodeAggregateId The identifier of the node aggregate to enable diff --git a/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php b/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php index 91c58ac4..03cd7bcf 100644 --- a/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php +++ b/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php @@ -36,7 +36,6 @@ final class SetSerializedNodeProperties implements RebasableToOtherContentStreamsInterface, MatchableWithNodeIdToPublishOrDiscardInterface { - /** * @param ContentStreamId $contentStreamId The content stream in which the set properties operation is to be performed * @param NodeAggregateId $nodeAggregateId The id of the node aggregate to set the properties for diff --git a/Classes/Feature/NodeReferencing/Command/SetNodeReferences.php b/Classes/Feature/NodeReferencing/Command/SetNodeReferences.php index 6a1c4f0b..d0ea7f49 100644 --- a/Classes/Feature/NodeReferencing/Command/SetNodeReferences.php +++ b/Classes/Feature/NodeReferencing/Command/SetNodeReferences.php @@ -18,7 +18,6 @@ */ final class SetNodeReferences implements CommandInterface { - /** * @param ContentStreamId $contentStreamId The content stream in which the create operation is to be performed * @param NodeAggregateId $sourceNodeAggregateId The identifier of the node aggregate to set references diff --git a/Classes/Feature/NodeRemoval/Command/RemoveNodeAggregate.php b/Classes/Feature/NodeRemoval/Command/RemoveNodeAggregate.php index 8016beda..060135a4 100644 --- a/Classes/Feature/NodeRemoval/Command/RemoveNodeAggregate.php +++ b/Classes/Feature/NodeRemoval/Command/RemoveNodeAggregate.php @@ -32,7 +32,6 @@ final class RemoveNodeAggregate implements RebasableToOtherContentStreamsInterface, MatchableWithNodeIdToPublishOrDiscardInterface { - /** * @param ContentStreamId $contentStreamId */ diff --git a/Classes/Feature/NodeRenaming/Command/ChangeNodeAggregateName.php b/Classes/Feature/NodeRenaming/Command/ChangeNodeAggregateName.php index 45ca5336..a0839e3c 100644 --- a/Classes/Feature/NodeRenaming/Command/ChangeNodeAggregateName.php +++ b/Classes/Feature/NodeRenaming/Command/ChangeNodeAggregateName.php @@ -35,7 +35,6 @@ final class ChangeNodeAggregateName implements RebasableToOtherContentStreamsInterface, MatchableWithNodeIdToPublishOrDiscardInterface { - /** * @param ContentStreamId $contentStreamId The content stream in which the operation is to be performed * @param NodeAggregateId $nodeAggregateId The identifier of the node aggregate to rename diff --git a/Classes/Feature/NodeTypeChange/Command/ChangeNodeAggregateType.php b/Classes/Feature/NodeTypeChange/Command/ChangeNodeAggregateType.php index 48d8d262..d4cd304a 100644 --- a/Classes/Feature/NodeTypeChange/Command/ChangeNodeAggregateType.php +++ b/Classes/Feature/NodeTypeChange/Command/ChangeNodeAggregateType.php @@ -37,7 +37,6 @@ final class ChangeNodeAggregateType implements RebasableToOtherContentStreamsInterface, MatchableWithNodeIdToPublishOrDiscardInterface { - /** * @param ContentStreamId $contentStreamId The content stream in which the operation is to be performed * @param NodeAggregateId $nodeAggregateId The unique identifier of the node aggregate to change diff --git a/Classes/Feature/RootNodeCreation/Command/CreateRootNodeAggregateWithNode.php b/Classes/Feature/RootNodeCreation/Command/CreateRootNodeAggregateWithNode.php index 6ca25891..ec57b718 100644 --- a/Classes/Feature/RootNodeCreation/Command/CreateRootNodeAggregateWithNode.php +++ b/Classes/Feature/RootNodeCreation/Command/CreateRootNodeAggregateWithNode.php @@ -33,7 +33,6 @@ final class CreateRootNodeAggregateWithNode implements \JsonSerializable, RebasableToOtherContentStreamsInterface { - /** * @param ContentStreamId $contentStreamId The content stream in which the root node should be created in * @param NodeAggregateId $nodeAggregateId The id of the root node aggregate to create diff --git a/Classes/Feature/RootNodeCreation/Command/UpdateRootNodeAggregateDimensions.php b/Classes/Feature/RootNodeCreation/Command/UpdateRootNodeAggregateDimensions.php index 4aa92c3e..5e149873 100644 --- a/Classes/Feature/RootNodeCreation/Command/UpdateRootNodeAggregateDimensions.php +++ b/Classes/Feature/RootNodeCreation/Command/UpdateRootNodeAggregateDimensions.php @@ -31,7 +31,6 @@ final class UpdateRootNodeAggregateDimensions implements \JsonSerializable, RebasableToOtherContentStreamsInterface { - /** * @param ContentStreamId $contentStreamId The content stream which the dimensions should be updated in * @param NodeAggregateId $nodeAggregateId The id of the node aggregate that should be updated diff --git a/Classes/Feature/WorkspacePublication/Command/PublishIndividualNodesFromWorkspace.php b/Classes/Feature/WorkspacePublication/Command/PublishIndividualNodesFromWorkspace.php index dbc450bb..873d00e5 100644 --- a/Classes/Feature/WorkspacePublication/Command/PublishIndividualNodesFromWorkspace.php +++ b/Classes/Feature/WorkspacePublication/Command/PublishIndividualNodesFromWorkspace.php @@ -60,7 +60,8 @@ private function __construct( * @param WorkspaceName $workspaceName Name of the affected workspace * @param NodeIdsToPublishOrDiscard $nodesToPublish Ids of the nodes to publish or discard */ - public static function create(WorkspaceName $workspaceName, NodeIdsToPublishOrDiscard $nodesToPublish): self { + public static function create(WorkspaceName $workspaceName, NodeIdsToPublishOrDiscard $nodesToPublish): self + { return new self( $workspaceName, $nodesToPublish, diff --git a/Classes/Feature/WorkspacePublication/Command/PublishWorkspace.php b/Classes/Feature/WorkspacePublication/Command/PublishWorkspace.php index 7d72b392..8d905ea5 100644 --- a/Classes/Feature/WorkspacePublication/Command/PublishWorkspace.php +++ b/Classes/Feature/WorkspacePublication/Command/PublishWorkspace.php @@ -24,14 +24,12 @@ */ final class PublishWorkspace implements CommandInterface { - /** * @param WorkspaceName $workspaceName Name of the workspace to publish */ private function __construct( public readonly WorkspaceName $workspaceName, - ) - { + ) { } /** diff --git a/Classes/Feature/WorkspaceRebase/Command/RebaseWorkspace.php b/Classes/Feature/WorkspaceRebase/Command/RebaseWorkspace.php index 6ba70221..dc3a6738 100644 --- a/Classes/Feature/WorkspaceRebase/Command/RebaseWorkspace.php +++ b/Classes/Feature/WorkspaceRebase/Command/RebaseWorkspace.php @@ -32,8 +32,7 @@ final class RebaseWorkspace implements CommandInterface private function __construct( public readonly WorkspaceName $workspaceName, public readonly ContentStreamId $rebasedContentStreamId - ) - { + ) { } public static function create(WorkspaceName $workspaceName): self