From 9714f472198370929947fcab08e12815640db201 Mon Sep 17 00:00:00 2001 From: Bastian Waidelich Date: Thu, 7 Nov 2024 18:46:39 +0100 Subject: [PATCH 01/15] WIP: PoC: Serializable Commands --- .../Classes/CommandHandler/CommandBus.php | 2 +- .../CommandHandler/CommandHandlerInterface.php | 4 ++-- .../CommandHandler/SerializedCommandInterface.php | 12 ++++++++++++ .../Common/RebasableToOtherWorkspaceInterface.php | 5 +++-- .../DimensionSpaceCommandHandler.php | 5 +++-- .../Classes/Feature/NodeAggregateCommandHandler.php | 5 +++-- ...eNodeAggregateWithNodeAndSerializedProperties.php | 4 ++-- .../NodeDuplicationCommandHandler.php | 5 +++-- .../Command/SetSerializedNodeProperties.php | 5 ++--- .../Command/SetSerializedNodeReferences.php | 4 ++-- .../Classes/Feature/RebaseableCommand.php | 6 ++++-- .../Classes/Feature/WorkspaceCommandHandler.php | 5 +++-- .../CommandThatFailedDuringRebase.php | 5 +++-- 13 files changed, 43 insertions(+), 24 deletions(-) create mode 100644 Neos.ContentRepository.Core/Classes/CommandHandler/SerializedCommandInterface.php diff --git a/Neos.ContentRepository.Core/Classes/CommandHandler/CommandBus.php b/Neos.ContentRepository.Core/Classes/CommandHandler/CommandBus.php index 92673a00c82..3cbdec086b7 100644 --- a/Neos.ContentRepository.Core/Classes/CommandHandler/CommandBus.php +++ b/Neos.ContentRepository.Core/Classes/CommandHandler/CommandBus.php @@ -31,7 +31,7 @@ public function __construct( /** * @return EventsToPublish|\Generator */ - public function handle(CommandInterface $command): EventsToPublish|\Generator + public function handle(CommandInterface|SerializedCommandInterface $command): EventsToPublish|\Generator { // multiple handlers must not handle the same command foreach ($this->handlers as $handler) { diff --git a/Neos.ContentRepository.Core/Classes/CommandHandler/CommandHandlerInterface.php b/Neos.ContentRepository.Core/Classes/CommandHandler/CommandHandlerInterface.php index b36d5d3ab75..4ad1e53919b 100644 --- a/Neos.ContentRepository.Core/Classes/CommandHandler/CommandHandlerInterface.php +++ b/Neos.ContentRepository.Core/Classes/CommandHandler/CommandHandlerInterface.php @@ -15,7 +15,7 @@ */ interface CommandHandlerInterface { - public function canHandle(CommandInterface $command): bool; + public function canHandle(CommandInterface|SerializedCommandInterface $command): bool; /** * "simple" command handlers return EventsToPublish directly @@ -25,5 +25,5 @@ public function canHandle(CommandInterface $command): bool; * * @return EventsToPublish|\Generator */ - public function handle(CommandInterface $command, CommandHandlingDependencies $commandHandlingDependencies): EventsToPublish|\Generator; + public function handle(CommandInterface|SerializedCommandInterface $command, CommandHandlingDependencies $commandHandlingDependencies): EventsToPublish|\Generator; } diff --git a/Neos.ContentRepository.Core/Classes/CommandHandler/SerializedCommandInterface.php b/Neos.ContentRepository.Core/Classes/CommandHandler/SerializedCommandInterface.php new file mode 100644 index 00000000000..342de7d5d5b --- /dev/null +++ b/Neos.ContentRepository.Core/Classes/CommandHandler/SerializedCommandInterface.php @@ -0,0 +1,12 @@ +getShortName()); } - public function handle(CommandInterface $command, CommandHandlingDependencies $commandHandlingDependencies): EventsToPublish + public function handle(CommandInterface|SerializedCommandInterface $command, CommandHandlingDependencies $commandHandlingDependencies): EventsToPublish { /** @phpstan-ignore-next-line */ return match ($command::class) { diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeAggregateCommandHandler.php b/Neos.ContentRepository.Core/Classes/Feature/NodeAggregateCommandHandler.php index eea2319dd3a..a54aefa9cae 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeAggregateCommandHandler.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeAggregateCommandHandler.php @@ -17,6 +17,7 @@ use Neos\ContentRepository\Core\CommandHandler\CommandHandlerInterface; use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\CommandHandler\CommandHandlingDependencies; +use Neos\ContentRepository\Core\CommandHandler\SerializedCommandInterface; use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\DimensionSpace; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet; @@ -86,12 +87,12 @@ public function __construct( ) { } - public function canHandle(CommandInterface $command): bool + public function canHandle(CommandInterface|SerializedCommandInterface $command): bool { return method_exists($this, 'handle' . (new \ReflectionClass($command))->getShortName()); } - public function handle(CommandInterface $command, CommandHandlingDependencies $commandHandlingDependencies): EventsToPublish + public function handle(CommandInterface|SerializedCommandInterface $command, CommandHandlingDependencies $commandHandlingDependencies): EventsToPublish { /** @phpstan-ignore-next-line */ return match ($command::class) { diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php b/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php index 958b1a30590..239120db1f0 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php @@ -14,7 +14,7 @@ namespace Neos\ContentRepository\Core\Feature\NodeCreation\Command; -use Neos\ContentRepository\Core\CommandHandler\CommandInterface; +use Neos\ContentRepository\Core\CommandHandler\SerializedCommandInterface; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\Feature\Common\MatchableWithNodeIdToPublishOrDiscardInterface; use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; @@ -34,7 +34,7 @@ * @internal implementation detail, use {@see CreateNodeAggregateWithNode} instead. */ final readonly class CreateNodeAggregateWithNodeAndSerializedProperties implements - CommandInterface, + SerializedCommandInterface, \JsonSerializable, MatchableWithNodeIdToPublishOrDiscardInterface, RebasableToOtherWorkspaceInterface diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/NodeDuplicationCommandHandler.php b/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/NodeDuplicationCommandHandler.php index edffe38ad5c..31a5a897af8 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/NodeDuplicationCommandHandler.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/NodeDuplicationCommandHandler.php @@ -15,6 +15,7 @@ namespace Neos\ContentRepository\Core\Feature\NodeDuplication; use Neos\ContentRepository\Core\CommandHandler\CommandHandlingDependencies; +use Neos\ContentRepository\Core\CommandHandler\SerializedCommandInterface; use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphInterface; use Neos\ContentRepository\Core\CommandHandler\CommandHandlerInterface; use Neos\ContentRepository\Core\CommandHandler\CommandInterface; @@ -64,12 +65,12 @@ protected function getAllowedDimensionSubspace(): DimensionSpacePointSet return $this->contentDimensionZookeeper->getAllowedDimensionSubspace(); } - public function canHandle(CommandInterface $command): bool + public function canHandle(CommandInterface|SerializedCommandInterface $command): bool { return method_exists($this, 'handle' . (new \ReflectionClass($command))->getShortName()); } - public function handle(CommandInterface $command, CommandHandlingDependencies $commandHandlingDependencies): EventsToPublish + public function handle(CommandInterface|SerializedCommandInterface $command, CommandHandlingDependencies $commandHandlingDependencies): EventsToPublish { /** @phpstan-ignore-next-line */ return match ($command::class) { diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php b/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php index a2d684f6035..f5d382f0387 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php @@ -14,7 +14,7 @@ namespace Neos\ContentRepository\Core\Feature\NodeModification\Command; -use Neos\ContentRepository\Core\CommandHandler\CommandInterface; +use Neos\ContentRepository\Core\CommandHandler\SerializedCommandInterface; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\Feature\Common\MatchableWithNodeIdToPublishOrDiscardInterface; use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; @@ -22,7 +22,6 @@ use Neos\ContentRepository\Core\Feature\WorkspacePublication\Dto\NodeIdToPublishOrDiscard; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\PropertyNames; -use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** @@ -33,7 +32,7 @@ * @internal implementation detail, use {@see SetNodeProperties} instead. */ final readonly class SetSerializedNodeProperties implements - CommandInterface, + SerializedCommandInterface, \JsonSerializable, MatchableWithNodeIdToPublishOrDiscardInterface, RebasableToOtherWorkspaceInterface diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php b/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php index ae96cc5af13..dd075e4e547 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php @@ -14,7 +14,7 @@ namespace Neos\ContentRepository\Core\Feature\NodeReferencing\Command; -use Neos\ContentRepository\Core\CommandHandler\CommandInterface; +use Neos\ContentRepository\Core\CommandHandler\SerializedCommandInterface; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\Feature\Common\MatchableWithNodeIdToPublishOrDiscardInterface; use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; @@ -31,7 +31,7 @@ * @internal implementation detail, use {@see SetNodeReferences} instead. */ final readonly class SetSerializedNodeReferences implements - CommandInterface, + SerializedCommandInterface, \JsonSerializable, MatchableWithNodeIdToPublishOrDiscardInterface, RebasableToOtherWorkspaceInterface diff --git a/Neos.ContentRepository.Core/Classes/Feature/RebaseableCommand.php b/Neos.ContentRepository.Core/Classes/Feature/RebaseableCommand.php index 210f91b8b8a..93aa84c89cc 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/RebaseableCommand.php +++ b/Neos.ContentRepository.Core/Classes/Feature/RebaseableCommand.php @@ -4,6 +4,8 @@ namespace Neos\ContentRepository\Core\Feature; +use Neos\ContentRepository\Core\CommandHandler\CommandInterface; +use Neos\ContentRepository\Core\CommandHandler\SerializedCommandInterface; use Neos\ContentRepository\Core\EventStore\DecoratedEvent; use Neos\ContentRepository\Core\EventStore\Events; use Neos\ContentRepository\Core\EventStore\InitiatingEventMetadata; @@ -19,7 +21,7 @@ final readonly class RebaseableCommand { public function __construct( - public RebasableToOtherWorkspaceInterface $originalCommand, + public (RebasableToOtherWorkspaceInterface&CommandInterface)|(RebasableToOtherWorkspaceInterface&SerializedCommandInterface) $originalCommand, public EventMetadata $initiatingMetaData, public SequenceNumber $originalSequenceNumber ) { @@ -42,7 +44,7 @@ public static function extractFromEventMetaData(EventMetadata $eventMetadata, Se ), 1547815341); } /** @var class-string $commandToRebaseClass */ - /** @var RebasableToOtherWorkspaceInterface $commandInstance */ + /** @var (RebasableToOtherWorkspaceInterface&CommandInterface)|(RebasableToOtherWorkspaceInterface&SerializedCommandInterface) $commandInstance */ $commandInstance = $commandToRebaseClass::fromArray($commandToRebasePayload); return new self( $commandInstance, diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php index 20143536272..dc8c12c7dca 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php @@ -18,6 +18,7 @@ use Neos\ContentRepository\Core\CommandHandler\CommandHandlingDependencies; use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\CommandHandler\CommandSimulatorFactory; +use Neos\ContentRepository\Core\CommandHandler\SerializedCommandInterface; use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\EventStore\DecoratedEvent; use Neos\ContentRepository\Core\EventStore\EventInterface; @@ -82,12 +83,12 @@ public function __construct( ) { } - public function canHandle(CommandInterface $command): bool + public function canHandle(CommandInterface|SerializedCommandInterface $command): bool { return method_exists($this, 'handle' . (new \ReflectionClass($command))->getShortName()); } - public function handle(CommandInterface $command, CommandHandlingDependencies $commandHandlingDependencies): \Generator + public function handle(CommandInterface|SerializedCommandInterface $command, CommandHandlingDependencies $commandHandlingDependencies): \Generator { /** @phpstan-ignore-next-line */ return match ($command::class) { diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/CommandThatFailedDuringRebase.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/CommandThatFailedDuringRebase.php index bcfd9627256..f8b4d579732 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/CommandThatFailedDuringRebase.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/CommandThatFailedDuringRebase.php @@ -15,6 +15,7 @@ namespace Neos\ContentRepository\Core\Feature\WorkspaceRebase; use Neos\ContentRepository\Core\CommandHandler\CommandInterface; +use Neos\ContentRepository\Core\CommandHandler\SerializedCommandInterface; use Neos\EventStore\Model\Event\SequenceNumber; /** @@ -23,12 +24,12 @@ final readonly class CommandThatFailedDuringRebase { /** - * @param CommandInterface $command the command that failed + * @param CommandInterface|SerializedCommandInterface $command the command that failed * @param \Throwable $exception how the command failed * @param SequenceNumber $sequenceNumber the event store sequence number of the event containing the command to be rebased */ public function __construct( - public CommandInterface $command, + public CommandInterface|SerializedCommandInterface $command, public \Throwable $exception, private SequenceNumber $sequenceNumber, ) { From 2ecfe5dc97b8946860e74de544c50e64e4303f8c Mon Sep 17 00:00:00 2001 From: Bastian Waidelich Date: Fri, 8 Nov 2024 15:05:31 +0100 Subject: [PATCH 02/15] Fix node migration transformations and tests by only using "official" commands --- .../AddNewProperty_NoDimensions.feature | 50 ++++++++++++++++-- .../RebasableToOtherWorkspaceInterface.php | 2 +- .../src/NodeMigrationServiceFactory.php | 2 +- ...nsionShineThroughTransformationFactory.php | 4 +- .../AddNewPropertyTransformationFactory.php | 25 +++++---- .../ChangeNodeTypeTransformationFactory.php | 4 +- ...angePropertyValueTransformationFactory.php | 26 ++++++---- ...mensionSpacePointTransformationFactory.php | 4 +- .../RemoveNodeTransformationFactory.php | 4 +- .../RemovePropertyTransformationFactory.php | 16 +++--- ...nameNodeAggregateTransformationFactory.php | 4 +- .../RenamePropertyTransformationFactory.php | 36 +++++++------ ...ripTagsOnPropertyTransformationFactory.php | 52 +++++++++---------- .../TransformationFactoryInterface.php | 4 +- .../Transformation/TransformationsFactory.php | 6 ++- ...gregateDimensionsTransformationFactory.php | 4 +- 16 files changed, 154 insertions(+), 89 deletions(-) diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/AddNewProperty_NoDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/AddNewProperty_NoDimensions.feature index 08f35b9c556..0f6d9270e71 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/AddNewProperty_NoDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/AddNewProperty_NoDimensions.feature @@ -13,6 +13,8 @@ Feature: Add New Property properties: text: type: string + dateTime: + type: DateTime """ And using identifier "default", I define a content repository And I am in content repository "default" @@ -64,7 +66,7 @@ Feature: Add New Property - type: 'AddNewProperty' settings: - newPropertyName: 'aDateOutsideSchema' + newPropertyName: 'dateTime' serializedValue: '2013-09-09T12:04:12+00:00' type: 'DateTime' """ @@ -82,6 +84,46 @@ Feature: Add New Property | text | "Original text" | Then I expect a node identified by migration-cs;other;{} to exist in the content graph And I expect this node to have the following properties: - | Key | Value | - | text | "fixed value" | - | aDateOutsideSchema | Date:2013-09-09T12:04:12+00:00 | + | Key | Value | + | text | "fixed value" | + | dateTime | Date:2013-09-09T12:04:12+00:00 | + + Scenario: Adding a property that is not defined in the node type schema + When I run the following node migration for workspace "live", creating target workspace "migration-workspace" on contentStreamId "migration-cs" and exceptions are caught: + """yaml + migration: + - + filters: + - + type: 'NodeType' + settings: + nodeType: 'Neos.ContentRepository.Testing:Document' + transformations: + - + type: 'AddNewProperty' + settings: + newPropertyName: 'aDateOutsideSchema' + serializedValue: '2013-09-09T12:04:12+00:00' + type: 'DateTime' + """ + Then the last command should have thrown an exception of type "PropertyCannotBeSet" + + Scenario: Adding a property with a different type than defined by the node type schema + When I run the following node migration for workspace "live", creating target workspace "migration-workspace" on contentStreamId "migration-cs" and exceptions are caught: + """yaml + migration: + - + filters: + - + type: 'NodeType' + settings: + nodeType: 'Neos.ContentRepository.Testing:Document' + transformations: + - + type: 'AddNewProperty' + settings: + newPropertyName: 'dateTime' + serializedValue: '2013-09-09T12:04:12+00:00' + type: 'string' + """ + Then the last command should have thrown an exception of type "PropertyCannotBeSet" diff --git a/Neos.ContentRepository.Core/Classes/Feature/Common/RebasableToOtherWorkspaceInterface.php b/Neos.ContentRepository.Core/Classes/Feature/Common/RebasableToOtherWorkspaceInterface.php index d1478c3cfd1..b0c643f6043 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/Common/RebasableToOtherWorkspaceInterface.php +++ b/Neos.ContentRepository.Core/Classes/Feature/Common/RebasableToOtherWorkspaceInterface.php @@ -30,7 +30,7 @@ interface RebasableToOtherWorkspaceInterface { public function createCopyForWorkspace( WorkspaceName $targetWorkspaceName, - ): (self&CommandInterface)|(self&SerializedCommandInterface); + ): (RebasableToOtherWorkspaceInterface&CommandInterface)|(RebasableToOtherWorkspaceInterface&SerializedCommandInterface); /** * called during deserialization from metadata diff --git a/Neos.ContentRepository.NodeMigration/src/NodeMigrationServiceFactory.php b/Neos.ContentRepository.NodeMigration/src/NodeMigrationServiceFactory.php index f6c3f5fee33..7a293ea5ae0 100644 --- a/Neos.ContentRepository.NodeMigration/src/NodeMigrationServiceFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/NodeMigrationServiceFactory.php @@ -39,7 +39,7 @@ public function build(ContentRepositoryServiceFactoryDependencies $serviceFactor $filtersFactory->registerFilter('PropertyNotEmpty', new PropertyNotEmptyFilterFactory()); $filtersFactory->registerFilter('PropertyValue', new PropertyValueFilterFactory()); - $transformationsFactory = new TransformationsFactory($serviceFactoryDependencies->contentRepository); + $transformationsFactory = new TransformationsFactory($serviceFactoryDependencies->contentRepository, $serviceFactoryDependencies->propertyConverter); $transformationsFactory->registerTransformation('AddDimensionShineThrough', new AddDimensionShineThroughTransformationFactory()); $transformationsFactory->registerTransformation('AddNewProperty', new AddNewPropertyTransformationFactory()); $transformationsFactory->registerTransformation('ChangeNodeType', new ChangeNodeTypeTransformationFactory()); diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/AddDimensionShineThroughTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/AddDimensionShineThroughTransformationFactory.php index f8decab4901..ea774b966c1 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/AddDimensionShineThroughTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/AddDimensionShineThroughTransformationFactory.php @@ -17,6 +17,7 @@ use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\Feature\DimensionSpaceAdjustment\Command\AddDimensionShineThrough; +use Neos\ContentRepository\Core\Infrastructure\Property\PropertyConverter; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** @@ -33,7 +34,8 @@ class AddDimensionShineThroughTransformationFactory implements TransformationFac */ public function build( array $settings, - ContentRepository $contentRepository + ContentRepository $contentRepository, + PropertyConverter $propertyConverter, ): GlobalTransformationInterface|NodeAggregateBasedTransformationInterface|NodeBasedTransformationInterface { return new class ( DimensionSpacePoint::fromArray($settings['from']), diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/AddNewPropertyTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/AddNewPropertyTransformationFactory.php index b6ad21e946a..b89e8aa63f3 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/AddNewPropertyTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/AddNewPropertyTransformationFactory.php @@ -16,9 +16,11 @@ use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet; -use Neos\ContentRepository\Core\Feature\NodeModification\Command\SetSerializedNodeProperties; +use Neos\ContentRepository\Core\Feature\NodeModification\Command\SetNodeProperties; +use Neos\ContentRepository\Core\Feature\NodeModification\Dto\PropertyValuesToWrite; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValue; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValues; +use Neos\ContentRepository\Core\Infrastructure\Property\PropertyConverter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\SharedModel\Node\PropertyNames; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; @@ -31,13 +33,15 @@ class AddNewPropertyTransformationFactory implements TransformationFactoryInterf */ public function build( array $settings, - ContentRepository $contentRepository + ContentRepository $contentRepository, + PropertyConverter $propertyConverter, ): GlobalTransformationInterface|NodeAggregateBasedTransformationInterface|NodeBasedTransformationInterface { return new class ( $settings['newPropertyName'], $settings['type'], $settings['serializedValue'], - $contentRepository + $contentRepository, + $propertyConverter, ) implements NodeBasedTransformationInterface { public function __construct( /** @@ -50,6 +54,7 @@ public function __construct( */ private readonly mixed $serializedValue, private readonly ContentRepository $contentRepository, + private readonly PropertyConverter $propertyConverter, ) { } @@ -63,20 +68,18 @@ public function execute( // we don't need to unset a non-existing property return; } + /** @phpstan-ignore-next-line */ + $deserializedPropertyValue = $this->propertyConverter->deserializePropertyValue(SerializedPropertyValue::create($this->serializedValue, $this->type)); if (!$node->hasProperty($this->newPropertyName)) { $this->contentRepository->handle( - SetSerializedNodeProperties::create( + SetNodeProperties::create( $workspaceNameForWriting, $node->aggregateId, $node->originDimensionSpacePoint, - SerializedPropertyValues::fromArray([ - $this->newPropertyName => SerializedPropertyValue::create( - $this->serializedValue, - $this->type - ) - ]), - PropertyNames::createEmpty() + PropertyValuesToWrite::fromArray([ + $this->newPropertyName => $deserializedPropertyValue, + ]) ) ); } diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/ChangeNodeTypeTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/ChangeNodeTypeTransformationFactory.php index 42ec7df2b4c..d6f8a0bb328 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/ChangeNodeTypeTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/ChangeNodeTypeTransformationFactory.php @@ -17,6 +17,7 @@ use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\Feature\NodeTypeChange\Command\ChangeNodeAggregateType; use Neos\ContentRepository\Core\Feature\NodeTypeChange\Dto\NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy; +use Neos\ContentRepository\Core\Infrastructure\Property\PropertyConverter; use Neos\ContentRepository\Core\NodeType\NodeTypeName; use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; @@ -35,7 +36,8 @@ class ChangeNodeTypeTransformationFactory implements TransformationFactoryInterf */ public function build( array $settings, - ContentRepository $contentRepository + ContentRepository $contentRepository, + PropertyConverter $propertyConverter, ): GlobalTransformationInterface|NodeAggregateBasedTransformationInterface|NodeBasedTransformationInterface { // by default, we won't delete anything. $nodeAggregateTypeChangeChildConstraintConflictResolutionStrategy diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/ChangePropertyValueTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/ChangePropertyValueTransformationFactory.php index c0b51852b6b..716aeb8830c 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/ChangePropertyValueTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/ChangePropertyValueTransformationFactory.php @@ -16,9 +16,12 @@ use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet; +use Neos\ContentRepository\Core\Feature\NodeModification\Command\SetNodeProperties; use Neos\ContentRepository\Core\Feature\NodeModification\Command\SetSerializedNodeProperties; +use Neos\ContentRepository\Core\Feature\NodeModification\Dto\PropertyValuesToWrite; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValue; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValues; +use Neos\ContentRepository\Core\Infrastructure\Property\PropertyConverter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\SharedModel\Node\PropertyNames; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; @@ -41,7 +44,8 @@ class ChangePropertyValueTransformationFactory implements TransformationFactoryI */ public function build( array $settings, - ContentRepository $contentRepository + ContentRepository $contentRepository, + PropertyConverter $propertyConverter, ): GlobalTransformationInterface|NodeAggregateBasedTransformationInterface|NodeBasedTransformationInterface { $newSerializedValue = '{current}'; if (isset($settings['newSerializedValue'])) { @@ -69,7 +73,8 @@ public function build( $search, $replace, $currentValuePlaceholder, - $contentRepository + $contentRepository, + $propertyConverter, ) implements NodeBasedTransformationInterface { public function __construct( /** @@ -96,7 +101,8 @@ public function __construct( * current property value into the new value. */ private readonly string $currentValuePlaceholder, - private readonly ContentRepository $contentRepository + private readonly ContentRepository $contentRepository, + private readonly PropertyConverter $propertyConverter, ) { } @@ -126,19 +132,17 @@ public function execute( $this->replace, $newValueWithReplacedCurrentValue ); + /** @phpstan-ignore-next-line */ + $deserializedPropertyValue = $this->propertyConverter->deserializePropertyValue(SerializedPropertyValue::create($newValueWithReplacedSearch, $currentProperty->type)); $this->contentRepository->handle( - SetSerializedNodeProperties::create( + SetNodeProperties::create( $workspaceNameForWriting, $node->aggregateId, $node->originDimensionSpacePoint, - SerializedPropertyValues::fromArray([ - $this->propertyName => SerializedPropertyValue::create( - $newValueWithReplacedSearch, - $currentProperty->type - ) - ]), - PropertyNames::createEmpty() + PropertyValuesToWrite::fromArray([ + $this->propertyName => $deserializedPropertyValue, + ]) ) ); } diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/MoveDimensionSpacePointTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/MoveDimensionSpacePointTransformationFactory.php index 0b7cc1b7679..47699871c57 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/MoveDimensionSpacePointTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/MoveDimensionSpacePointTransformationFactory.php @@ -17,6 +17,7 @@ use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\Feature\DimensionSpaceAdjustment\Command\MoveDimensionSpacePoint; +use Neos\ContentRepository\Core\Infrastructure\Property\PropertyConverter; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** @@ -29,7 +30,8 @@ class MoveDimensionSpacePointTransformationFactory implements TransformationFact */ public function build( array $settings, - ContentRepository $contentRepository + ContentRepository $contentRepository, + PropertyConverter $propertyConverter, ): GlobalTransformationInterface|NodeAggregateBasedTransformationInterface|NodeBasedTransformationInterface { $from = DimensionSpacePoint::fromArray($settings['from']); $to = DimensionSpacePoint::fromArray($settings['to']); diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/RemoveNodeTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/RemoveNodeTransformationFactory.php index fbd0a2b46fa..0dfca855a8e 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/RemoveNodeTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/RemoveNodeTransformationFactory.php @@ -18,6 +18,7 @@ use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet; use Neos\ContentRepository\Core\Feature\NodeRemoval\Command\RemoveNodeAggregate; +use Neos\ContentRepository\Core\Infrastructure\Property\PropertyConverter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\SharedModel\Node\NodeVariantSelectionStrategy; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; @@ -33,7 +34,8 @@ class RemoveNodeTransformationFactory implements TransformationFactoryInterface */ public function build( array $settings, - ContentRepository $contentRepository + ContentRepository $contentRepository, + PropertyConverter $propertyConverter, ): GlobalTransformationInterface|NodeAggregateBasedTransformationInterface|NodeBasedTransformationInterface { $strategy = null; if (isset($settings['strategy'])) { diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/RemovePropertyTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/RemovePropertyTransformationFactory.php index c0990547e2d..30e182e42bc 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/RemovePropertyTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/RemovePropertyTransformationFactory.php @@ -16,10 +16,10 @@ use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet; -use Neos\ContentRepository\Core\Feature\NodeModification\Command\SetSerializedNodeProperties; -use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValues; +use Neos\ContentRepository\Core\Feature\NodeModification\Command\SetNodeProperties; +use Neos\ContentRepository\Core\Feature\NodeModification\Dto\PropertyValuesToWrite; +use Neos\ContentRepository\Core\Infrastructure\Property\PropertyConverter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; -use Neos\ContentRepository\Core\SharedModel\Node\PropertyNames; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; @@ -33,7 +33,8 @@ class RemovePropertyTransformationFactory implements TransformationFactoryInterf */ public function build( array $settings, - ContentRepository $contentRepository + ContentRepository $contentRepository, + PropertyConverter $propertyConverter, ): GlobalTransformationInterface|NodeAggregateBasedTransformationInterface|NodeBasedTransformationInterface { $propertyName = $settings['property']; return new class ( @@ -56,12 +57,13 @@ public function execute( ): void { if ($node->hasProperty($this->propertyName)) { $this->contentRepository->handle( - SetSerializedNodeProperties::create( + SetNodeProperties::create( $workspaceNameForWriting, $node->aggregateId, $node->originDimensionSpacePoint, - SerializedPropertyValues::createEmpty(), - PropertyNames::fromArray([$this->propertyName]) + PropertyValuesToWrite::fromArray([ + $this->propertyName => null, + ]), ) ); } diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/RenameNodeAggregateTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/RenameNodeAggregateTransformationFactory.php index 3e05d002d1b..cd277a27641 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/RenameNodeAggregateTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/RenameNodeAggregateTransformationFactory.php @@ -16,6 +16,7 @@ use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\Feature\NodeRenaming\Command\ChangeNodeAggregateName; +use Neos\ContentRepository\Core\Infrastructure\Property\PropertyConverter; use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; @@ -28,7 +29,8 @@ class RenameNodeAggregateTransformationFactory implements TransformationFactoryI */ public function build( array $settings, - ContentRepository $contentRepository + ContentRepository $contentRepository, + PropertyConverter $propertyConverter, ): GlobalTransformationInterface|NodeAggregateBasedTransformationInterface|NodeBasedTransformationInterface { $newNodeName = $settings['newNodeName']; diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/RenamePropertyTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/RenamePropertyTransformationFactory.php index ff70a13bd7f..3d76ca3ba37 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/RenamePropertyTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/RenamePropertyTransformationFactory.php @@ -16,10 +16,10 @@ use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet; -use Neos\ContentRepository\Core\Feature\NodeModification\Command\SetSerializedNodeProperties; -use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValues; +use Neos\ContentRepository\Core\Feature\NodeModification\Command\SetNodeProperties; +use Neos\ContentRepository\Core\Feature\NodeModification\Dto\PropertyValuesToWrite; +use Neos\ContentRepository\Core\Infrastructure\Property\PropertyConverter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; -use Neos\ContentRepository\Core\SharedModel\Node\PropertyNames; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; @@ -33,7 +33,8 @@ class RenamePropertyTransformationFactory implements TransformationFactoryInterf */ public function build( array $settings, - ContentRepository $contentRepository + ContentRepository $contentRepository, + PropertyConverter $propertyConverter, ): GlobalTransformationInterface|NodeAggregateBasedTransformationInterface|NodeBasedTransformationInterface { return new class ( @@ -62,20 +63,21 @@ public function execute( ContentStreamId $contentStreamForWriting ): void { - $serializedPropertyValue = $node->properties->serialized()->getProperty($this->from); - if ($serializedPropertyValue !== null) { - $this->contentRepository->handle( - SetSerializedNodeProperties::create( - $workspaceNameForWriting, - $node->aggregateId, - $node->originDimensionSpacePoint, - SerializedPropertyValues::fromArray([ - $this->to => $serializedPropertyValue - ]), - PropertyNames::fromArray([$this->from]) - ) - ); + $propertyValue = $node->properties[$this->from]; + if ($propertyValue === null) { + return; } + $this->contentRepository->handle( + SetNodeProperties::create( + $workspaceNameForWriting, + $node->aggregateId, + $node->originDimensionSpacePoint, + PropertyValuesToWrite::fromArray([ + $this->to => $propertyValue, + $this->from => null, + ]), + ) + ); } }; } diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/StripTagsOnPropertyTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/StripTagsOnPropertyTransformationFactory.php index 9803c9509b2..6c372de3c3c 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/StripTagsOnPropertyTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/StripTagsOnPropertyTransformationFactory.php @@ -16,11 +16,10 @@ use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet; -use Neos\ContentRepository\Core\Feature\NodeModification\Command\SetSerializedNodeProperties; -use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValue; -use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValues; +use Neos\ContentRepository\Core\Feature\NodeModification\Command\SetNodeProperties; +use Neos\ContentRepository\Core\Feature\NodeModification\Dto\PropertyValuesToWrite; +use Neos\ContentRepository\Core\Infrastructure\Property\PropertyConverter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; -use Neos\ContentRepository\Core\SharedModel\Node\PropertyNames; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; @@ -34,7 +33,8 @@ class StripTagsOnPropertyTransformationFactory implements TransformationFactoryI */ public function build( array $settings, - ContentRepository $contentRepository + ContentRepository $contentRepository, + PropertyConverter $propertyConverter, ): GlobalTransformationInterface|NodeAggregateBasedTransformationInterface|NodeBasedTransformationInterface { return new class ( $settings['property'], @@ -55,31 +55,27 @@ public function execute( WorkspaceName $workspaceNameForWriting, ContentStreamId $contentStreamForWriting ): void { - $serializedPropertyValue = $node->properties->serialized()->getProperty($this->propertyName); - if ($serializedPropertyValue !== null) { - $propertyValue = $serializedPropertyValue->value; - if (!is_string($propertyValue)) { - throw new \Exception( - 'StripTagsOnProperty can only be applied to properties of type string.', - 1645391885 - ); - } - $newValue = strip_tags($propertyValue); - $this->contentRepository->handle( - SetSerializedNodeProperties::create( - $workspaceNameForWriting, - $node->aggregateId, - $node->originDimensionSpacePoint, - SerializedPropertyValues::fromArray([ - $this->propertyName => SerializedPropertyValue::create( - $newValue, - $serializedPropertyValue->type - ) - ]), - PropertyNames::createEmpty() - ) + $propertyValue = $node->properties[$this->propertyName]; + if ($propertyValue === null) { + return; + } + if (!is_string($propertyValue)) { + throw new \Exception( + sprintf('StripTagsOnProperty can only be applied to properties of type string. Property "%s" is of type %s', $this->propertyName, get_debug_type($propertyValue)), + 1645391885 ); } + $newValue = strip_tags($propertyValue); + $this->contentRepository->handle( + SetNodeProperties::create( + $workspaceNameForWriting, + $node->aggregateId, + $node->originDimensionSpacePoint, + PropertyValuesToWrite::fromArray([ + $this->propertyName => $newValue, + ]), + ) + ); } }; } diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/TransformationFactoryInterface.php b/Neos.ContentRepository.NodeMigration/src/Transformation/TransformationFactoryInterface.php index df0c2193ed7..ecaa105d733 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/TransformationFactoryInterface.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/TransformationFactoryInterface.php @@ -5,6 +5,7 @@ namespace Neos\ContentRepository\NodeMigration\Transformation; use Neos\ContentRepository\Core\ContentRepository; +use Neos\ContentRepository\Core\Infrastructure\Property\PropertyConverter; interface TransformationFactoryInterface { @@ -13,6 +14,7 @@ interface TransformationFactoryInterface */ public function build( array $settings, - ContentRepository $contentRepository + ContentRepository $contentRepository, + PropertyConverter $propertyConverter, ): GlobalTransformationInterface|NodeAggregateBasedTransformationInterface|NodeBasedTransformationInterface; } diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/TransformationsFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/TransformationsFactory.php index 915c05cc3fe..56d8d0eaa02 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/TransformationsFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/TransformationsFactory.php @@ -5,6 +5,7 @@ namespace Neos\ContentRepository\NodeMigration\Transformation; use Neos\ContentRepository\Core\ContentRepository; +use Neos\ContentRepository\Core\Infrastructure\Property\PropertyConverter; use Neos\ContentRepository\NodeMigration\MigrationException; use Neos\ContentRepository\NodeMigration\NodeMigrationService; @@ -19,7 +20,8 @@ class TransformationsFactory private array $transformationFactories = []; public function __construct( - private readonly ContentRepository $contentRepository + private readonly ContentRepository $contentRepository, + private readonly PropertyConverter $propertyConverter, ) { } @@ -58,7 +60,7 @@ protected function buildTransformationObject( ): GlobalTransformationInterface|NodeAggregateBasedTransformationInterface|NodeBasedTransformationInterface { $transformationFactory = $this->resolveTransformationFactory($transformationConfiguration['type']); - return $transformationFactory->build($transformationConfiguration['settings'] ?? [], $this->contentRepository); + return $transformationFactory->build($transformationConfiguration['settings'] ?? [], $this->contentRepository, $this->propertyConverter); } /** diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/UpdateRootNodeAggregateDimensionsTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/UpdateRootNodeAggregateDimensionsTransformationFactory.php index 3b4b47867bb..4e735ae7ad3 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/UpdateRootNodeAggregateDimensionsTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/UpdateRootNodeAggregateDimensionsTransformationFactory.php @@ -6,6 +6,7 @@ use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\Feature\RootNodeCreation\Command\UpdateRootNodeAggregateDimensions; +use Neos\ContentRepository\Core\Infrastructure\Property\PropertyConverter; use Neos\ContentRepository\Core\NodeType\NodeTypeName; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepository\NodeMigration\MigrationException; @@ -17,7 +18,8 @@ class UpdateRootNodeAggregateDimensionsTransformationFactory implements Transfor */ public function build( array $settings, - ContentRepository $contentRepository + ContentRepository $contentRepository, + PropertyConverter $propertyConverter, ): GlobalTransformationInterface|NodeAggregateBasedTransformationInterface|NodeBasedTransformationInterface { if (!isset($settings['nodeType'])) { throw new MigrationException( From bd60fb8e20c461f8ed5c210cbe153da3626dbfc6 Mon Sep 17 00:00:00 2001 From: Bastian Waidelich Date: Fri, 8 Nov 2024 16:10:49 +0100 Subject: [PATCH 03/15] Fine grained PHPStan ignores --- .../src/Transformation/AddNewPropertyTransformationFactory.php | 3 +-- .../ChangePropertyValueTransformationFactory.php | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/AddNewPropertyTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/AddNewPropertyTransformationFactory.php index b89e8aa63f3..1a3dd9cdbc7 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/AddNewPropertyTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/AddNewPropertyTransformationFactory.php @@ -68,8 +68,7 @@ public function execute( // we don't need to unset a non-existing property return; } - /** @phpstan-ignore-next-line */ - $deserializedPropertyValue = $this->propertyConverter->deserializePropertyValue(SerializedPropertyValue::create($this->serializedValue, $this->type)); + $deserializedPropertyValue = $this->propertyConverter->deserializePropertyValue(SerializedPropertyValue::create($this->serializedValue, $this->type)); // @phpstan-ignore neos.cr.internal if (!$node->hasProperty($this->newPropertyName)) { $this->contentRepository->handle( diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/ChangePropertyValueTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/ChangePropertyValueTransformationFactory.php index 716aeb8830c..bd3d31c915b 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/ChangePropertyValueTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/ChangePropertyValueTransformationFactory.php @@ -132,8 +132,7 @@ public function execute( $this->replace, $newValueWithReplacedCurrentValue ); - /** @phpstan-ignore-next-line */ - $deserializedPropertyValue = $this->propertyConverter->deserializePropertyValue(SerializedPropertyValue::create($newValueWithReplacedSearch, $currentProperty->type)); + $deserializedPropertyValue = $this->propertyConverter->deserializePropertyValue(SerializedPropertyValue::create($newValueWithReplacedSearch, $currentProperty->type)); // @phpstan-ignore neos.cr.internal $this->contentRepository->handle( SetNodeProperties::create( From 35b02dcbe3a78fa7807504f05a143147d6e6bd1f Mon Sep 17 00:00:00 2001 From: Bastian Waidelich Date: Fri, 8 Nov 2024 16:10:55 +0100 Subject: [PATCH 04/15] Fix tests --- ...AggregateWithNode_WithoutDimensions.feature | 8 ++++---- .../RemoveNodeAggregateAfterDisabling.feature | 2 +- .../RemoveNodeAggregateWithDimensions.feature | 4 ++-- .../DimensionMismatch.feature | 2 +- .../StructureAdjustment/Properties.feature | 2 +- .../TetheredNodesReordering.feature | 2 +- .../02-RebasingWithAutoCreatedNodes.feature | 18 +++++++++--------- .../04-AllFeaturePublication.feature | 4 ++-- .../Command/SetNodeProperties.php | 13 +++++++++++++ ...ericCommandExecutionAndEventPublication.php | 6 ++---- .../Features/Fusion/ContentCollection.feature | 2 +- 11 files changed, 37 insertions(+), 26 deletions(-) diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/03-CreateNodeAggregateWithNode_WithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/03-CreateNodeAggregateWithNode_WithoutDimensions.feature index 076f8d72e2e..d71d45460a1 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/03-CreateNodeAggregateWithNode_WithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/03-CreateNodeAggregateWithNode_WithoutDimensions.feature @@ -202,14 +202,14 @@ Feature: Create node aggregate with node | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | - Given the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: + Given the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:NodeWithoutTetheredChildNodes" | | originDimensionSpacePoint | {} | | parentNodeAggregateId | "lady-eleonode-rootford" | | nodeName | "node" | - And the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: + And the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "sir-nodeward-nodington-iii" | | nodeTypeName | "Neos.ContentRepository.Testing:NodeWithoutTetheredChildNodes" | @@ -280,7 +280,7 @@ Feature: Create node aggregate with node | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | - When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: + When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:NodeWithTetheredChildNodes" | @@ -459,7 +459,7 @@ Feature: Create node aggregate with node | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | - When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: + When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:NodeWithTetheredChildNodes" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateAfterDisabling.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateAfterDisabling.feature index 8652a6a8252..156576e5069 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateAfterDisabling.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateAfterDisabling.feature @@ -50,7 +50,7 @@ Feature: Disable a node aggregate | affectedOccupiedDimensionSpacePoints | [{}] | | affectedCoveredDimensionSpacePoints | [{}] | - When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: + When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateWithDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateWithDimensions.feature index 96e0ecaafb7..742b38d69b6 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateWithDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateWithDimensions.feature @@ -24,7 +24,7 @@ Feature: Remove NodeAggregate | nodeTypeName | "Neos.ContentRepository:Root" | # We have to add another node since root nodes are in all dimension space points and thus cannot be varied # Node /document - And the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: + And the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | @@ -32,7 +32,7 @@ Feature: Remove NodeAggregate | nodeName | "document" | # We also want to add a child node to make sure it is correctly removed when the parent is removed # Node /document/child-document - And the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: + And the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "nodimus-prime" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DimensionMismatch.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DimensionMismatch.feature index 6f10381a3cb..23347f92229 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DimensionMismatch.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DimensionMismatch.feature @@ -30,7 +30,7 @@ Feature: Dimension mismatch Scenario: Generalization detection # Node /document - When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: + When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/Properties.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/Properties.feature index bd29ba2e76e..aaf81876ec4 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/Properties.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/Properties.feature @@ -28,7 +28,7 @@ Feature: Properties | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | # Node /document - When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: + When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/TetheredNodesReordering.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/TetheredNodesReordering.feature index bb4974d7175..197a15e4989 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/TetheredNodesReordering.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/TetheredNodesReordering.feature @@ -28,7 +28,7 @@ Feature: Tethered Nodes Reordering Structure changes | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | - And the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: + And the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W6-WorkspaceRebasing/02-RebasingWithAutoCreatedNodes.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W6-WorkspaceRebasing/02-RebasingWithAutoCreatedNodes.feature index 39eca525c82..bbf470d1c17 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W6-WorkspaceRebasing/02-RebasingWithAutoCreatedNodes.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W6-WorkspaceRebasing/02-RebasingWithAutoCreatedNodes.feature @@ -61,13 +61,13 @@ Feature: Rebasing auto-created nodes works And I expect this node to be a child of node user-cs-identifier;nody-mc-nodeface;{} # - then, for the auto-created child node, set a property. - When the command "SetSerializedNodeProperties" is executed with payload: - | Key | Value | - | workspaceName | "user-test" | - | nodeAggregateId | $this->currentNodeAggregateId | - | originDimensionSpacePoint | {} | - | propertyValues | {"text": {"value":"Modified","type":"string"}} | - | propertiesToUnset | {} | + When the command "SetNodeProperties" is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + | nodeAggregateId | $this->currentNodeAggregateId | + | originDimensionSpacePoint | {} | + | propertyValues | {"text": "Modified"} | + | propertiesToUnset | {} | # ensure that live is outdated so the rebase is required: When the command CreateNodeAggregateWithNode is executed with payload: @@ -80,8 +80,8 @@ Feature: Rebasing auto-created nodes works # rebase of SetSerializedNodeProperties When the command RebaseWorkspace is executed with payload: - | Key | Value | - | workspaceName | "user-test" | + | Key | Value | + | workspaceName | "user-test" | | rebasedContentStreamId | "user-cs-rebased" | # This should properly work; no error. diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/04-AllFeaturePublication.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/04-AllFeaturePublication.feature index a5e32169667..37de2e73450 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/04-AllFeaturePublication.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/04-AllFeaturePublication.feature @@ -346,7 +346,7 @@ Feature: Publishing hide/show scenario of nodes | newContentStreamId | "user-cs-identifier" | # SETUP: set two new nodes in USER workspace - When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: + When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | | workspaceName | "user-test" | | nodeAggregateId | "new1-agg" | @@ -354,7 +354,7 @@ Feature: Publishing hide/show scenario of nodes | originDimensionSpacePoint | {} | | parentNodeAggregateId | "lady-eleonode-rootford" | | nodeName | "foo" | - When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: + When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | | workspaceName | "user-test" | | nodeAggregateId | "new2-agg" | diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetNodeProperties.php b/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetNodeProperties.php index e2a3d63f587..6e4bbb0aab9 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetNodeProperties.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetNodeProperties.php @@ -60,4 +60,17 @@ public static function create(WorkspaceName $workspaceName, NodeAggregateId $nod { return new self($workspaceName, $nodeAggregateId, $originDimensionSpacePoint, $propertyValues); } + + /** + * @param array $array + */ + public static function fromArray(array $array): self + { + return new self( + WorkspaceName::fromString($array['workspaceName']), + NodeAggregateId::fromString($array['nodeAggregateId']), + OriginDimensionSpacePoint::fromArray($array['originDimensionSpacePoint']), + PropertyValuesToWrite::fromArray($array['propertyValues']), + ); + } } diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/GenericCommandExecutionAndEventPublication.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/GenericCommandExecutionAndEventPublication.php index dd899ee4e24..d9d7f66def5 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/GenericCommandExecutionAndEventPublication.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/GenericCommandExecutionAndEventPublication.php @@ -20,10 +20,9 @@ use Neos\ContentRepository\Core\EventStore\EventPersister; use Neos\ContentRepository\Core\EventStore\Events; use Neos\ContentRepository\Core\EventStore\EventsToPublish; -use Neos\ContentRepository\Core\Feature\NodeCreation\Command\CreateNodeAggregateWithNodeAndSerializedProperties; use Neos\ContentRepository\Core\Feature\NodeDisabling\Command\DisableNodeAggregate; use Neos\ContentRepository\Core\Feature\NodeDisabling\Command\EnableNodeAggregate; -use Neos\ContentRepository\Core\Feature\NodeModification\Command\SetSerializedNodeProperties; +use Neos\ContentRepository\Core\Feature\NodeModification\Command\SetNodeProperties; use Neos\ContentRepository\Core\Feature\NodeMove\Command\MoveNodeAggregate; use Neos\ContentRepository\Core\Feature\NodeReferencing\Command\SetNodeReferences; use Neos\ContentRepository\Core\Feature\NodeRenaming\Command\ChangeNodeAggregateName; @@ -104,9 +103,8 @@ protected static function resolveShortCommandName(string $shortCommandName): str 'PublishWorkspace' => PublishWorkspace::class, 'PublishIndividualNodesFromWorkspace' => PublishIndividualNodesFromWorkspace::class, 'RebaseWorkspace' => RebaseWorkspace::class, - 'CreateNodeAggregateWithNodeAndSerializedProperties' => CreateNodeAggregateWithNodeAndSerializedProperties::class, 'ChangeNodeAggregateName' => ChangeNodeAggregateName::class, - 'SetSerializedNodeProperties' => SetSerializedNodeProperties::class, + 'SetNodeProperties' => SetNodeProperties::class, 'DisableNodeAggregate' => DisableNodeAggregate::class, 'EnableNodeAggregate' => EnableNodeAggregate::class, 'TagSubtree' => TagSubtree::class, diff --git a/Neos.Neos/Tests/Behavior/Features/Fusion/ContentCollection.feature b/Neos.Neos/Tests/Behavior/Features/Fusion/ContentCollection.feature index b1edf071af4..ab8a61b3e2b 100644 --- a/Neos.Neos/Tests/Behavior/Features/Fusion/ContentCollection.feature +++ b/Neos.Neos/Tests/Behavior/Features/Fusion/ContentCollection.feature @@ -109,7 +109,7 @@ Feature: Tests for the "Neos.Neos:ContentCollection" Fusion prototype """ Scenario: - When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: + When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "a1" | | nodeTypeName | "Neos.Neos:Test.DocumentType" | From c36073ea9cd80dae992b0fdceb5d671795ad5406 Mon Sep 17 00:00:00 2001 From: Bastian Waidelich Date: Fri, 8 Nov 2024 16:13:30 +0100 Subject: [PATCH 05/15] Avoid union type in `CommandThatFailedDuringRebase` --- .../Classes/Feature/RebaseableCommand.php | 2 +- .../WorkspaceRebase/CommandThatFailedDuringRebase.php | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Neos.ContentRepository.Core/Classes/Feature/RebaseableCommand.php b/Neos.ContentRepository.Core/Classes/Feature/RebaseableCommand.php index 93aa84c89cc..42a039167c3 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/RebaseableCommand.php +++ b/Neos.ContentRepository.Core/Classes/Feature/RebaseableCommand.php @@ -21,7 +21,7 @@ final readonly class RebaseableCommand { public function __construct( - public (RebasableToOtherWorkspaceInterface&CommandInterface)|(RebasableToOtherWorkspaceInterface&SerializedCommandInterface) $originalCommand, + public RebasableToOtherWorkspaceInterface $originalCommand, public EventMetadata $initiatingMetaData, public SequenceNumber $originalSequenceNumber ) { diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/CommandThatFailedDuringRebase.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/CommandThatFailedDuringRebase.php index f8b4d579732..96b6a433b11 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/CommandThatFailedDuringRebase.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/CommandThatFailedDuringRebase.php @@ -14,8 +14,7 @@ namespace Neos\ContentRepository\Core\Feature\WorkspaceRebase; -use Neos\ContentRepository\Core\CommandHandler\CommandInterface; -use Neos\ContentRepository\Core\CommandHandler\SerializedCommandInterface; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; use Neos\EventStore\Model\Event\SequenceNumber; /** @@ -24,12 +23,12 @@ final readonly class CommandThatFailedDuringRebase { /** - * @param CommandInterface|SerializedCommandInterface $command the command that failed + * @param RebasableToOtherWorkspaceInterface $command the command that failed * @param \Throwable $exception how the command failed * @param SequenceNumber $sequenceNumber the event store sequence number of the event containing the command to be rebased */ public function __construct( - public CommandInterface|SerializedCommandInterface $command, + public RebasableToOtherWorkspaceInterface $command, public \Throwable $exception, private SequenceNumber $sequenceNumber, ) { From 8e9b33337f180f7d9e653b1ff82f3c6163fe8984 Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Fri, 8 Nov 2024 17:00:46 +0100 Subject: [PATCH 06/15] TASK: Add docs for Serialized Command --- .../Classes/CommandHandler/CommandInterface.php | 4 ++-- .../CommandHandler/SerializedCommandInterface.php | 10 ++++++++++ .../Common/RebasableToOtherWorkspaceInterface.php | 3 +-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Neos.ContentRepository.Core/Classes/CommandHandler/CommandInterface.php b/Neos.ContentRepository.Core/Classes/CommandHandler/CommandInterface.php index 8264248a6f9..ba5d5f1c350 100644 --- a/Neos.ContentRepository.Core/Classes/CommandHandler/CommandInterface.php +++ b/Neos.ContentRepository.Core/Classes/CommandHandler/CommandInterface.php @@ -5,9 +5,9 @@ namespace Neos\ContentRepository\Core\CommandHandler; /** - * Common (marker) interface for all commands of the Content Repository + * Common (marker) interface for all commands of the content repository * - * @internal because extra commands are no extension point + * @internal sealed interface. Custom commands cannot be handled and are no extension point! */ interface CommandInterface { diff --git a/Neos.ContentRepository.Core/Classes/CommandHandler/SerializedCommandInterface.php b/Neos.ContentRepository.Core/Classes/CommandHandler/SerializedCommandInterface.php index 342de7d5d5b..24a948730db 100644 --- a/Neos.ContentRepository.Core/Classes/CommandHandler/SerializedCommandInterface.php +++ b/Neos.ContentRepository.Core/Classes/CommandHandler/SerializedCommandInterface.php @@ -5,8 +5,18 @@ namespace Neos\ContentRepository\Core\CommandHandler; /** + * Common (marker) interface for all commands that need to be serialized for rebasing + * + * During a rebase, the command (either {@see CommandInterface} or this serialized counterpart) will be deserialized + * from array {@see SerializedCommandInterface::fromArray()} and reapplied {@see CommandSimulator} + * * @internal */ interface SerializedCommandInterface { + /** + * called during deserialization from metadata + * @param array $array + */ + public static function fromArray(array $array): self; } diff --git a/Neos.ContentRepository.Core/Classes/Feature/Common/RebasableToOtherWorkspaceInterface.php b/Neos.ContentRepository.Core/Classes/Feature/Common/RebasableToOtherWorkspaceInterface.php index b0c643f6043..20320903a8a 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/Common/RebasableToOtherWorkspaceInterface.php +++ b/Neos.ContentRepository.Core/Classes/Feature/Common/RebasableToOtherWorkspaceInterface.php @@ -19,8 +19,7 @@ use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** - * This interface is implemented by **commands** which can be rebased to other Content Streams. This is basically all - * node-based commands. + * This interface is implemented by **commands** which can be rebased to other workspaces. * * Reminder: a rebase can fail, because the target content stream might contain conflicting changes. * From e9d576b3c345723b7832c1510b907fcbfee8b23b Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Fri, 8 Nov 2024 17:15:42 +0100 Subject: [PATCH 07/15] TASK: Remove `SerializedCommandInterface` again and use `RebasableToOtherWorkspaceInterface` directly --- .../Classes/CommandHandler/CommandBus.php | 3 ++- .../CommandHandlerInterface.php | 5 +++-- .../CommandHandler/CommandInterface.php | 2 +- .../SerializedCommandInterface.php | 22 ------------------- .../RebasableToOtherWorkspaceInterface.php | 14 +++++++----- .../DimensionSpaceCommandHandler.php | 10 ++++----- .../Feature/NodeAggregateCommandHandler.php | 8 +++---- ...gregateWithNodeAndSerializedProperties.php | 2 -- .../NodeDuplicationCommandHandler.php | 13 +++++------ .../Command/SetSerializedNodeProperties.php | 2 -- .../Command/SetSerializedNodeReferences.php | 2 -- .../Classes/Feature/RebaseableCommand.php | 4 +--- .../Feature/WorkspaceCommandHandler.php | 9 +++----- 13 files changed, 34 insertions(+), 62 deletions(-) delete mode 100644 Neos.ContentRepository.Core/Classes/CommandHandler/SerializedCommandInterface.php diff --git a/Neos.ContentRepository.Core/Classes/CommandHandler/CommandBus.php b/Neos.ContentRepository.Core/Classes/CommandHandler/CommandBus.php index 3cbdec086b7..5621e17fd2d 100644 --- a/Neos.ContentRepository.Core/Classes/CommandHandler/CommandBus.php +++ b/Neos.ContentRepository.Core/Classes/CommandHandler/CommandBus.php @@ -6,6 +6,7 @@ use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\EventStore\EventsToPublish; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; /** * Implementation Detail of {@see ContentRepository::handle}, which does the command dispatching to the different @@ -31,7 +32,7 @@ public function __construct( /** * @return EventsToPublish|\Generator */ - public function handle(CommandInterface|SerializedCommandInterface $command): EventsToPublish|\Generator + public function handle(CommandInterface|RebasableToOtherWorkspaceInterface $command): EventsToPublish|\Generator { // multiple handlers must not handle the same command foreach ($this->handlers as $handler) { diff --git a/Neos.ContentRepository.Core/Classes/CommandHandler/CommandHandlerInterface.php b/Neos.ContentRepository.Core/Classes/CommandHandler/CommandHandlerInterface.php index 4ad1e53919b..93cba7111ef 100644 --- a/Neos.ContentRepository.Core/Classes/CommandHandler/CommandHandlerInterface.php +++ b/Neos.ContentRepository.Core/Classes/CommandHandler/CommandHandlerInterface.php @@ -5,6 +5,7 @@ namespace Neos\ContentRepository\Core\CommandHandler; use Neos\ContentRepository\Core\EventStore\EventsToPublish; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; /** * Common interface for all Content Repository command handlers @@ -15,7 +16,7 @@ */ interface CommandHandlerInterface { - public function canHandle(CommandInterface|SerializedCommandInterface $command): bool; + public function canHandle(CommandInterface|RebasableToOtherWorkspaceInterface $command): bool; /** * "simple" command handlers return EventsToPublish directly @@ -25,5 +26,5 @@ public function canHandle(CommandInterface|SerializedCommandInterface $command): * * @return EventsToPublish|\Generator */ - public function handle(CommandInterface|SerializedCommandInterface $command, CommandHandlingDependencies $commandHandlingDependencies): EventsToPublish|\Generator; + public function handle(CommandInterface|RebasableToOtherWorkspaceInterface $command, CommandHandlingDependencies $commandHandlingDependencies): EventsToPublish|\Generator; } diff --git a/Neos.ContentRepository.Core/Classes/CommandHandler/CommandInterface.php b/Neos.ContentRepository.Core/Classes/CommandHandler/CommandInterface.php index ba5d5f1c350..dcd162afb10 100644 --- a/Neos.ContentRepository.Core/Classes/CommandHandler/CommandInterface.php +++ b/Neos.ContentRepository.Core/Classes/CommandHandler/CommandInterface.php @@ -5,7 +5,7 @@ namespace Neos\ContentRepository\Core\CommandHandler; /** - * Common (marker) interface for all commands of the content repository + * Common (marker) interface for all api commands of the content repository * * @internal sealed interface. Custom commands cannot be handled and are no extension point! */ diff --git a/Neos.ContentRepository.Core/Classes/CommandHandler/SerializedCommandInterface.php b/Neos.ContentRepository.Core/Classes/CommandHandler/SerializedCommandInterface.php deleted file mode 100644 index 24a948730db..00000000000 --- a/Neos.ContentRepository.Core/Classes/CommandHandler/SerializedCommandInterface.php +++ /dev/null @@ -1,22 +0,0 @@ - $array - */ - public static function fromArray(array $array): self; -} diff --git a/Neos.ContentRepository.Core/Classes/Feature/Common/RebasableToOtherWorkspaceInterface.php b/Neos.ContentRepository.Core/Classes/Feature/Common/RebasableToOtherWorkspaceInterface.php index 20320903a8a..7a33844a0ac 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/Common/RebasableToOtherWorkspaceInterface.php +++ b/Neos.ContentRepository.Core/Classes/Feature/Common/RebasableToOtherWorkspaceInterface.php @@ -14,22 +14,26 @@ namespace Neos\ContentRepository\Core\Feature\Common; -use Neos\ContentRepository\Core\CommandHandler\CommandInterface; -use Neos\ContentRepository\Core\CommandHandler\SerializedCommandInterface; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** - * This interface is implemented by **commands** which can be rebased to other workspaces. + * Common (marker) interface for all **commands** that need to be serialized for rebasing to other workspaces + * + * If the api command {@see CommandInterface} is serializable on its own it will directly implement this interface. + * For complex commands a serialized counterpart - which is not api - will be build which implements this interface. + * + * During a rebase, the command (either the original {@see CommandInterface} or its serialized counterpart) will be deserialized + * from array {@see SerializedCommandInterface::fromArray()} and reapplied via the {@see CommandSimulator} * * Reminder: a rebase can fail, because the target content stream might contain conflicting changes. * * @internal used internally for the rebasing mechanism of content streams */ -interface RebasableToOtherWorkspaceInterface +interface RebasableToOtherWorkspaceInterface extends \JsonSerializable { public function createCopyForWorkspace( WorkspaceName $targetWorkspaceName, - ): (RebasableToOtherWorkspaceInterface&CommandInterface)|(RebasableToOtherWorkspaceInterface&SerializedCommandInterface); + ): self; /** * called during deserialization from metadata diff --git a/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/DimensionSpaceCommandHandler.php b/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/DimensionSpaceCommandHandler.php index 411e9801dd9..72695af98c7 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/DimensionSpaceCommandHandler.php +++ b/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/DimensionSpaceCommandHandler.php @@ -15,9 +15,8 @@ */ use Neos\ContentRepository\Core\CommandHandler\CommandHandlerInterface; -use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\CommandHandler\CommandHandlingDependencies; -use Neos\ContentRepository\Core\CommandHandler\SerializedCommandInterface; +use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\DimensionSpace\ContentDimensionZookeeper; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; @@ -27,13 +26,14 @@ use Neos\ContentRepository\Core\DimensionSpace\VariantType; use Neos\ContentRepository\Core\EventStore\Events; use Neos\ContentRepository\Core\EventStore\EventsToPublish; -use Neos\ContentRepository\Core\Feature\RebaseableCommand; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; use Neos\ContentRepository\Core\Feature\ContentStreamEventStreamName; use Neos\ContentRepository\Core\Feature\DimensionSpaceAdjustment\Command\AddDimensionShineThrough; use Neos\ContentRepository\Core\Feature\DimensionSpaceAdjustment\Command\MoveDimensionSpacePoint; use Neos\ContentRepository\Core\Feature\DimensionSpaceAdjustment\Event\DimensionShineThroughWasAdded; use Neos\ContentRepository\Core\Feature\DimensionSpaceAdjustment\Event\DimensionSpacePointWasMoved; use Neos\ContentRepository\Core\Feature\DimensionSpaceAdjustment\Exception\DimensionSpacePointAlreadyExists; +use Neos\ContentRepository\Core\Feature\RebaseableCommand; use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphInterface; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; use Neos\EventStore\Model\EventStream\ExpectedVersion; @@ -49,12 +49,12 @@ public function __construct( ) { } - public function canHandle(CommandInterface|SerializedCommandInterface $command): bool + public function canHandle(CommandInterface|RebasableToOtherWorkspaceInterface $command): bool { return method_exists($this, 'handle' . (new \ReflectionClass($command))->getShortName()); } - public function handle(CommandInterface|SerializedCommandInterface $command, CommandHandlingDependencies $commandHandlingDependencies): EventsToPublish + public function handle(CommandInterface|RebasableToOtherWorkspaceInterface $command, CommandHandlingDependencies $commandHandlingDependencies): EventsToPublish { /** @phpstan-ignore-next-line */ return match ($command::class) { diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeAggregateCommandHandler.php b/Neos.ContentRepository.Core/Classes/Feature/NodeAggregateCommandHandler.php index a54aefa9cae..f014440718c 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeAggregateCommandHandler.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeAggregateCommandHandler.php @@ -15,14 +15,14 @@ namespace Neos\ContentRepository\Core\Feature; use Neos\ContentRepository\Core\CommandHandler\CommandHandlerInterface; -use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\CommandHandler\CommandHandlingDependencies; -use Neos\ContentRepository\Core\CommandHandler\SerializedCommandInterface; +use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\DimensionSpace; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet; use Neos\ContentRepository\Core\EventStore\EventsToPublish; use Neos\ContentRepository\Core\Feature\Common\ConstraintChecks; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; use Neos\ContentRepository\Core\Feature\Common\TetheredNodeInternals; use Neos\ContentRepository\Core\Feature\NodeCreation\Command\CreateNodeAggregateWithNode; use Neos\ContentRepository\Core\Feature\NodeCreation\Command\CreateNodeAggregateWithNodeAndSerializedProperties; @@ -87,12 +87,12 @@ public function __construct( ) { } - public function canHandle(CommandInterface|SerializedCommandInterface $command): bool + public function canHandle(CommandInterface|RebasableToOtherWorkspaceInterface $command): bool { return method_exists($this, 'handle' . (new \ReflectionClass($command))->getShortName()); } - public function handle(CommandInterface|SerializedCommandInterface $command, CommandHandlingDependencies $commandHandlingDependencies): EventsToPublish + public function handle(CommandInterface|RebasableToOtherWorkspaceInterface $command, CommandHandlingDependencies $commandHandlingDependencies): EventsToPublish { /** @phpstan-ignore-next-line */ return match ($command::class) { diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php b/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php index 239120db1f0..3aa8d471d0e 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php @@ -14,7 +14,6 @@ namespace Neos\ContentRepository\Core\Feature\NodeCreation\Command; -use Neos\ContentRepository\Core\CommandHandler\SerializedCommandInterface; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\Feature\Common\MatchableWithNodeIdToPublishOrDiscardInterface; use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; @@ -34,7 +33,6 @@ * @internal implementation detail, use {@see CreateNodeAggregateWithNode} instead. */ final readonly class CreateNodeAggregateWithNodeAndSerializedProperties implements - SerializedCommandInterface, \JsonSerializable, MatchableWithNodeIdToPublishOrDiscardInterface, RebasableToOtherWorkspaceInterface diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/NodeDuplicationCommandHandler.php b/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/NodeDuplicationCommandHandler.php index 31a5a897af8..cce5dd61e29 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/NodeDuplicationCommandHandler.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/NodeDuplicationCommandHandler.php @@ -14,10 +14,8 @@ namespace Neos\ContentRepository\Core\Feature\NodeDuplication; -use Neos\ContentRepository\Core\CommandHandler\CommandHandlingDependencies; -use Neos\ContentRepository\Core\CommandHandler\SerializedCommandInterface; -use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphInterface; use Neos\ContentRepository\Core\CommandHandler\CommandHandlerInterface; +use Neos\ContentRepository\Core\CommandHandler\CommandHandlingDependencies; use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\DimensionSpace\ContentDimensionZookeeper; @@ -28,17 +26,18 @@ use Neos\ContentRepository\Core\EventStore\EventsToPublish; use Neos\ContentRepository\Core\Feature\Common\ConstraintChecks; use Neos\ContentRepository\Core\Feature\Common\InterdimensionalSiblings; -use Neos\ContentRepository\Core\Feature\RebaseableCommand; use Neos\ContentRepository\Core\Feature\Common\NodeCreationInternals; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; use Neos\ContentRepository\Core\Feature\ContentStreamEventStreamName; use Neos\ContentRepository\Core\Feature\NodeCreation\Event\NodeAggregateWithNodeWasCreated; use Neos\ContentRepository\Core\Feature\NodeDuplication\Command\CopyNodesRecursively; use Neos\ContentRepository\Core\Feature\NodeDuplication\Dto\NodeSubtreeSnapshot; +use Neos\ContentRepository\Core\Feature\RebaseableCommand; use Neos\ContentRepository\Core\NodeType\NodeTypeManager; +use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphInterface; use Neos\ContentRepository\Core\SharedModel\Exception\NodeConstraintException; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; -use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * @internal from userland, you'll use ContentRepository::handle to dispatch commands @@ -65,12 +64,12 @@ protected function getAllowedDimensionSubspace(): DimensionSpacePointSet return $this->contentDimensionZookeeper->getAllowedDimensionSubspace(); } - public function canHandle(CommandInterface|SerializedCommandInterface $command): bool + public function canHandle(CommandInterface|RebasableToOtherWorkspaceInterface $command): bool { return method_exists($this, 'handle' . (new \ReflectionClass($command))->getShortName()); } - public function handle(CommandInterface|SerializedCommandInterface $command, CommandHandlingDependencies $commandHandlingDependencies): EventsToPublish + public function handle(CommandInterface|RebasableToOtherWorkspaceInterface $command, CommandHandlingDependencies $commandHandlingDependencies): EventsToPublish { /** @phpstan-ignore-next-line */ return match ($command::class) { diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php b/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php index f5d382f0387..b3d38bf88dc 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php @@ -14,7 +14,6 @@ namespace Neos\ContentRepository\Core\Feature\NodeModification\Command; -use Neos\ContentRepository\Core\CommandHandler\SerializedCommandInterface; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\Feature\Common\MatchableWithNodeIdToPublishOrDiscardInterface; use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; @@ -32,7 +31,6 @@ * @internal implementation detail, use {@see SetNodeProperties} instead. */ final readonly class SetSerializedNodeProperties implements - SerializedCommandInterface, \JsonSerializable, MatchableWithNodeIdToPublishOrDiscardInterface, RebasableToOtherWorkspaceInterface diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php b/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php index dd075e4e547..5e95099f806 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php @@ -14,7 +14,6 @@ namespace Neos\ContentRepository\Core\Feature\NodeReferencing\Command; -use Neos\ContentRepository\Core\CommandHandler\SerializedCommandInterface; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\Feature\Common\MatchableWithNodeIdToPublishOrDiscardInterface; use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; @@ -31,7 +30,6 @@ * @internal implementation detail, use {@see SetNodeReferences} instead. */ final readonly class SetSerializedNodeReferences implements - SerializedCommandInterface, \JsonSerializable, MatchableWithNodeIdToPublishOrDiscardInterface, RebasableToOtherWorkspaceInterface diff --git a/Neos.ContentRepository.Core/Classes/Feature/RebaseableCommand.php b/Neos.ContentRepository.Core/Classes/Feature/RebaseableCommand.php index 42a039167c3..210f91b8b8a 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/RebaseableCommand.php +++ b/Neos.ContentRepository.Core/Classes/Feature/RebaseableCommand.php @@ -4,8 +4,6 @@ namespace Neos\ContentRepository\Core\Feature; -use Neos\ContentRepository\Core\CommandHandler\CommandInterface; -use Neos\ContentRepository\Core\CommandHandler\SerializedCommandInterface; use Neos\ContentRepository\Core\EventStore\DecoratedEvent; use Neos\ContentRepository\Core\EventStore\Events; use Neos\ContentRepository\Core\EventStore\InitiatingEventMetadata; @@ -44,7 +42,7 @@ public static function extractFromEventMetaData(EventMetadata $eventMetadata, Se ), 1547815341); } /** @var class-string $commandToRebaseClass */ - /** @var (RebasableToOtherWorkspaceInterface&CommandInterface)|(RebasableToOtherWorkspaceInterface&SerializedCommandInterface) $commandInstance */ + /** @var RebasableToOtherWorkspaceInterface $commandInstance */ $commandInstance = $commandToRebaseClass::fromArray($commandToRebasePayload); return new self( $commandInstance, diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php index dc8c12c7dca..cbec3e0d8e0 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php @@ -18,17 +18,15 @@ use Neos\ContentRepository\Core\CommandHandler\CommandHandlingDependencies; use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\CommandHandler\CommandSimulatorFactory; -use Neos\ContentRepository\Core\CommandHandler\SerializedCommandInterface; use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\EventStore\DecoratedEvent; -use Neos\ContentRepository\Core\EventStore\EventInterface; use Neos\ContentRepository\Core\EventStore\EventNormalizer; use Neos\ContentRepository\Core\EventStore\Events; use Neos\ContentRepository\Core\EventStore\EventsToPublish; use Neos\ContentRepository\Core\Feature\Common\PublishableToWorkspaceInterface; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; use Neos\ContentRepository\Core\Feature\ContentStreamClosing\Event\ContentStreamWasClosed; use Neos\ContentRepository\Core\Feature\ContentStreamClosing\Event\ContentStreamWasReopened; -use Neos\ContentRepository\Core\Feature\ContentStreamForking\Event\ContentStreamWasForked; use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Command\CreateRootWorkspace; use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Command\CreateWorkspace; use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Event\RootWorkspaceWasCreated; @@ -63,7 +61,6 @@ use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceStatus; use Neos\EventStore\EventStoreInterface; -use Neos\EventStore\Model\Event\EventType; use Neos\EventStore\Model\Event\SequenceNumber; use Neos\EventStore\Model\Event\Version; use Neos\EventStore\Model\EventStream\EventStreamInterface; @@ -83,12 +80,12 @@ public function __construct( ) { } - public function canHandle(CommandInterface|SerializedCommandInterface $command): bool + public function canHandle(CommandInterface|RebasableToOtherWorkspaceInterface $command): bool { return method_exists($this, 'handle' . (new \ReflectionClass($command))->getShortName()); } - public function handle(CommandInterface|SerializedCommandInterface $command, CommandHandlingDependencies $commandHandlingDependencies): \Generator + public function handle(CommandInterface|RebasableToOtherWorkspaceInterface $command, CommandHandlingDependencies $commandHandlingDependencies): \Generator { /** @phpstan-ignore-next-line */ return match ($command::class) { From ddf2a5289187048b57daef3e550798f84dab5105 Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Fri, 8 Nov 2024 19:38:39 +0100 Subject: [PATCH 08/15] TASK: Adjust documentation of `CommandInterface` --- .../Classes/CommandHandler/CommandInterface.php | 7 ++++++- .../Feature/Common/RebasableToOtherWorkspaceInterface.php | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Neos.ContentRepository.Core/Classes/CommandHandler/CommandInterface.php b/Neos.ContentRepository.Core/Classes/CommandHandler/CommandInterface.php index dcd162afb10..a29d2c85a7a 100644 --- a/Neos.ContentRepository.Core/Classes/CommandHandler/CommandInterface.php +++ b/Neos.ContentRepository.Core/Classes/CommandHandler/CommandInterface.php @@ -4,8 +4,13 @@ namespace Neos\ContentRepository\Core\CommandHandler; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; + /** - * Common (marker) interface for all api commands of the content repository + * Common (marker) interface for all public api commands of the content repository + * + * Note that this interface does not mark all commands. + * Complex public commands will not be serializable on its own and are required to be serialized into a {@see RebasableToOtherWorkspaceInterface} * * @internal sealed interface. Custom commands cannot be handled and are no extension point! */ diff --git a/Neos.ContentRepository.Core/Classes/Feature/Common/RebasableToOtherWorkspaceInterface.php b/Neos.ContentRepository.Core/Classes/Feature/Common/RebasableToOtherWorkspaceInterface.php index 7a33844a0ac..f0f2a10a6c3 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/Common/RebasableToOtherWorkspaceInterface.php +++ b/Neos.ContentRepository.Core/Classes/Feature/Common/RebasableToOtherWorkspaceInterface.php @@ -14,6 +14,8 @@ namespace Neos\ContentRepository\Core\Feature\Common; +use Neos\ContentRepository\Core\CommandHandler\CommandInterface; +use Neos\ContentRepository\Core\CommandHandler\CommandSimulator; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** @@ -23,7 +25,7 @@ * For complex commands a serialized counterpart - which is not api - will be build which implements this interface. * * During a rebase, the command (either the original {@see CommandInterface} or its serialized counterpart) will be deserialized - * from array {@see SerializedCommandInterface::fromArray()} and reapplied via the {@see CommandSimulator} + * from array {@see RebasableToOtherWorkspaceInterface::fromArray()} and reapplied via the {@see CommandSimulator} * * Reminder: a rebase can fail, because the target content stream might contain conflicting changes. * From d79fe107f80ac4dbb779341aa28eebd70049628f Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Sat, 9 Nov 2024 11:27:01 +0100 Subject: [PATCH 09/15] TASK: Overhaul api of `CommandThatFailedDuringRebase` --- .../CommandThatFailedDuringRebase.php | 59 +++++++++++++++++-- .../Exception/WorkspaceRebaseFailed.php | 8 +-- ...ricCommandExecutionAndEventPublication.php | 4 +- 3 files changed, 60 insertions(+), 11 deletions(-) diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/CommandThatFailedDuringRebase.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/CommandThatFailedDuringRebase.php index 96b6a433b11..4f6fd46d615 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/CommandThatFailedDuringRebase.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/CommandThatFailedDuringRebase.php @@ -15,6 +15,18 @@ namespace Neos\ContentRepository\Core\Feature\WorkspaceRebase; use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; +use Neos\ContentRepository\Core\Feature\NodeCreation\Command\CreateNodeAggregateWithNodeAndSerializedProperties; +use Neos\ContentRepository\Core\Feature\NodeDisabling\Command\DisableNodeAggregate; +use Neos\ContentRepository\Core\Feature\NodeDisabling\Command\EnableNodeAggregate; +use Neos\ContentRepository\Core\Feature\NodeModification\Command\SetSerializedNodeProperties; +use Neos\ContentRepository\Core\Feature\NodeMove\Command\MoveNodeAggregate; +use Neos\ContentRepository\Core\Feature\NodeReferencing\Command\SetSerializedNodeReferences; +use Neos\ContentRepository\Core\Feature\NodeRemoval\Command\RemoveNodeAggregate; +use Neos\ContentRepository\Core\Feature\NodeTypeChange\Command\ChangeNodeAggregateType; +use Neos\ContentRepository\Core\Feature\NodeVariation\Command\CreateNodeVariant; +use Neos\ContentRepository\Core\Feature\SubtreeTagging\Command\TagSubtree; +use Neos\ContentRepository\Core\Feature\SubtreeTagging\Command\UntagSubtree; +use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\EventStore\Model\Event\SequenceNumber; /** @@ -23,17 +35,44 @@ final readonly class CommandThatFailedDuringRebase { /** - * @param RebasableToOtherWorkspaceInterface $command the command that failed - * @param \Throwable $exception how the command failed - * @param SequenceNumber $sequenceNumber the event store sequence number of the event containing the command to be rebased + * @internal */ public function __construct( - public RebasableToOtherWorkspaceInterface $command, - public \Throwable $exception, + private RebasableToOtherWorkspaceInterface $command, + private \Throwable $exception, private SequenceNumber $sequenceNumber, ) { } + /** + * The node aggregate id of the failed command + */ + public function getAffectedNodeAggregateId(): ?NodeAggregateId + { + return match ($this->command::class) { + MoveNodeAggregate::class, + SetSerializedNodeProperties::class, + CreateNodeAggregateWithNodeAndSerializedProperties::class, + TagSubtree::class, + DisableNodeAggregate::class, + UntagSubtree::class, + EnableNodeAggregate::class, + RemoveNodeAggregate::class, + ChangeNodeAggregateType::class, + CreateNodeVariant::class => $this->command->nodeAggregateId, + SetSerializedNodeReferences::class => $this->command->sourceNodeAggregateId, + default => null + }; + } + + /** + * How the command failed that was attempted to be rebased + */ + public function getException(): \Throwable + { + return $this->exception; + } + /** * The event store sequence number of the event containing the command to be rebased * @@ -43,4 +82,14 @@ public function getSequenceNumber(): SequenceNumber { return $this->sequenceNumber; } + + /** + * The command that failed + * + * @internal exposed for testing and experimental use cases + */ + public function getCommand(): RebasableToOtherWorkspaceInterface + { + return $this->command; + } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/Exception/WorkspaceRebaseFailed.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/Exception/WorkspaceRebaseFailed.php index b1bae671156..1ac611e412e 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/Exception/WorkspaceRebaseFailed.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/Exception/WorkspaceRebaseFailed.php @@ -36,7 +36,7 @@ public static function duringRebase(CommandsThatFailedDuringRebase $commandsThat $commandsThatFailedDuringRebase, sprintf('Rebase failed: %s', self::renderMessage($commandsThatFailedDuringRebase)), 1729974936, - $commandsThatFailedDuringRebase->first()?->exception + $commandsThatFailedDuringRebase->first()?->getException() ); } @@ -46,7 +46,7 @@ public static function duringPublish(CommandsThatFailedDuringRebase $commandsTha $commandsThatFailedDuringRebase, sprintf('Publication failed: %s', self::renderMessage($commandsThatFailedDuringRebase)), 1729974980, - $commandsThatFailedDuringRebase->first()?->exception + $commandsThatFailedDuringRebase->first()?->getException() ); } @@ -56,13 +56,13 @@ public static function duringDiscard(CommandsThatFailedDuringRebase $commandsTha $commandsThatFailedDuringRebase, sprintf('Discard failed: %s', self::renderMessage($commandsThatFailedDuringRebase)), 1729974982, - $commandsThatFailedDuringRebase->first()?->exception + $commandsThatFailedDuringRebase->first()?->getException() ); } private static function renderMessage(CommandsThatFailedDuringRebase $commandsThatFailedDuringRebase): string { $firstFailure = $commandsThatFailedDuringRebase->first(); - return sprintf('"%s" and %d further failures', $firstFailure?->exception->getMessage(), count($commandsThatFailedDuringRebase) - 1); + return sprintf('"%s" and %d further failures', $firstFailure?->getException()->getMessage(), count($commandsThatFailedDuringRebase) - 1); } } diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/GenericCommandExecutionAndEventPublication.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/GenericCommandExecutionAndEventPublication.php index d9d7f66def5..ccd1e73fd42 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/GenericCommandExecutionAndEventPublication.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/GenericCommandExecutionAndEventPublication.php @@ -176,8 +176,8 @@ public function theLastCommandShouldHaveThrownTheWorkspaceRebaseFailedWith(Table foreach ($exception->commandsThatFailedDuringRebase as $commandsThatFailed) { $actualComparableHash[] = [ 'SequenceNumber' => (string)$commandsThatFailed->getSequenceNumber()->value, - 'Command' => (new \ReflectionClass($commandsThatFailed->command))->getShortName(), - 'Exception' => (new \ReflectionClass($commandsThatFailed->exception))->getShortName(), + 'Command' => (new \ReflectionClass($commandsThatFailed->getCommand()))->getShortName(), + 'Exception' => (new \ReflectionClass($commandsThatFailed->getException()))->getShortName(), ]; } From d6ff6bb204adb877b31a5ea7fc8b87260ad9c4e1 Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Sat, 9 Nov 2024 17:44:54 +0100 Subject: [PATCH 10/15] TASK: Do not expose that `Command`'s failed during rebase This is an implementation detail, and we might change this concept and rather do constraint checks for events on the read model and then publish those. --- .../01-ConstraintChecks.feature | 4 +- .../03-RebasingWithConflictingChanges.feature | 10 +- .../01-ConstraintChecks.feature | 10 +- .../02-DiscardWorkspace.feature | 4 +- .../CommandHandler/CommandSimulator.php | 24 ++--- .../DimensionSpace/DimensionSpacePointSet.php | 8 ++ .../Classes/Feature/RebaseableCommand.php | 16 ++-- .../Classes/Feature/RebaseableCommands.php | 2 +- .../Feature/WorkspaceCommandHandler.php | 16 ++-- .../CommandThatFailedDuringRebase.php | 95 ------------------- .../EventThatFailedDuringRebase.php | 74 +++++++++++++++ ...e.php => EventsThatFailedDuringRebase.php} | 12 +-- .../Exception/WorkspaceRebaseFailed.php | 34 +++---- ...ricCommandExecutionAndEventPublication.php | 4 +- 14 files changed, 153 insertions(+), 160 deletions(-) delete mode 100644 Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/CommandThatFailedDuringRebase.php create mode 100644 Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/EventThatFailedDuringRebase.php rename Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/{CommandsThatFailedDuringRebase.php => EventsThatFailedDuringRebase.php} (69%) diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W10-IndividualNodeDiscarding/01-ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W10-IndividualNodeDiscarding/01-ConstraintChecks.feature index 7c5c5a7c002..bb15c251e28 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W10-IndividualNodeDiscarding/01-ConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W10-IndividualNodeDiscarding/01-ConstraintChecks.feature @@ -73,8 +73,8 @@ Feature: Workspace discarding - complex chained functionality | nodesToDiscard | [{"workspaceName": "user-ws", "dimensionSpacePoint": {"language": "en"}, "nodeAggregateId": "sir-david-nodenborough"}, {"workspaceName": "user-ws", "dimensionSpacePoint": {"language": "en"}, "nodeAggregateId": "sir-david-nodenborough"}] | | newContentStreamId | "user-cs-id-rebased" | Then the last command should have thrown the WorkspaceRebaseFailed exception with: - | SequenceNumber | Command | Exception | - | 11 | CreateNodeVariant | NodeAggregateDoesCurrentlyNotCoverDimensionSpacePoint | + | SequenceNumber | Event | Exception | + | 11 | NodeGeneralizationVariantWasCreated | NodeAggregateDoesCurrentlyNotCoverDimensionSpacePoint | When the command DiscardWorkspace is executed with payload: | Key | Value | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W6-WorkspaceRebasing/03-RebasingWithConflictingChanges.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W6-WorkspaceRebasing/03-RebasingWithConflictingChanges.feature index bbd1de5307c..7f30b4c68af 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W6-WorkspaceRebasing/03-RebasingWithConflictingChanges.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W6-WorkspaceRebasing/03-RebasingWithConflictingChanges.feature @@ -101,8 +101,8 @@ Feature: Workspace rebasing - conflicting changes Then I expect the content stream "user-cs-two" to exist Then I expect the content stream "user-cs-two-rebased" to not exist Then the last command should have thrown the WorkspaceRebaseFailed exception with: - | SequenceNumber | Command | Exception | - | 13 | SetSerializedNodeProperties | NodeAggregateCurrentlyDoesNotExist | + | SequenceNumber | Event | Exception | + | 13 | NodePropertiesWereSet | NodeAggregateCurrentlyDoesNotExist | When the command RebaseWorkspace is executed with payload: | Key | Value | @@ -169,9 +169,9 @@ Feature: Workspace rebasing - conflicting changes Then I expect the content stream "user-cs-identifier" to exist Then I expect the content stream "user-cs-identifier-rebased" to not exist Then the last command should have thrown the WorkspaceRebaseFailed exception with: - | SequenceNumber | Command | Exception | - | 12 | SetSerializedNodeProperties | NodeAggregateCurrentlyDoesNotExist | - | 14 | SetSerializedNodeProperties | NodeAggregateCurrentlyDoesNotExist | + | SequenceNumber | Event | Exception | + | 12 | NodePropertiesWereSet | NodeAggregateCurrentlyDoesNotExist | + | 14 | NodePropertiesWereSet | NodeAggregateCurrentlyDoesNotExist | When the command RebaseWorkspace is executed with payload: | Key | Value | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/01-ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/01-ConstraintChecks.feature index ac52e28289b..60bf7aadc2b 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/01-ConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/01-ConstraintChecks.feature @@ -83,9 +83,9 @@ Feature: Workspace publication - complex chained functionality | nodesToPublish | [{"dimensionSpacePoint": {"language": "de"}, "nodeAggregateId": "sir-nodebelig"}] | | newContentStreamId | "user-cs-id-rebased" | Then the last command should have thrown the WorkspaceRebaseFailed exception with: - | SequenceNumber | Command | Exception | - | 13 | SetSerializedNodeProperties | NodeAggregateCurrentlyDoesNotExist | - | 14 | SetSerializedNodeProperties | NodeAggregateCurrentlyDoesNotExist | + | SequenceNumber | Event | Exception | + | 13 | NodePropertiesWereSet | NodeAggregateCurrentlyDoesNotExist | + | 14 | NodePropertiesWereSet | NodeAggregateCurrentlyDoesNotExist | Scenario: Vary to generalization, then publish only the child node so that an exception is thrown. Ensure that the workspace recovers from this When the command CreateNodeVariant is executed with payload: @@ -107,8 +107,8 @@ Feature: Workspace publication - complex chained functionality | nodesToPublish | [{"workspaceName": "user-ws", "dimensionSpacePoint": {"language": "en"}, "nodeAggregateId": "nody-mc-nodeface"}] | | newContentStreamId | "user-cs-id-rebased" | Then the last command should have thrown the WorkspaceRebaseFailed exception with: - | SequenceNumber | Command | Exception | - | 13 | CreateNodeVariant | NodeAggregateDoesCurrentlyNotCoverDimensionSpacePoint | + | SequenceNumber | Event | Exception | + | 13 | NodeGeneralizationVariantWasCreated | NodeAggregateDoesCurrentlyNotCoverDimensionSpacePoint | When the command PublishWorkspace is executed with payload: | Key | Value | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W9-WorkspaceDiscarding/02-DiscardWorkspace.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W9-WorkspaceDiscarding/02-DiscardWorkspace.feature index 0e180f7d0dd..158cd4dabb5 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W9-WorkspaceDiscarding/02-DiscardWorkspace.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W9-WorkspaceDiscarding/02-DiscardWorkspace.feature @@ -139,8 +139,8 @@ Feature: Workspace discarding - basic functionality | workspaceName | "user-ws-two" | | rebasedContentStreamId | "user-cs-two-rebased" | Then the last command should have thrown the WorkspaceRebaseFailed exception with: - | SequenceNumber | Command | Exception | - | 13 | SetSerializedNodeProperties | NodeAggregateCurrentlyDoesNotExist | + | SequenceNumber | Event | Exception | + | 13 | NodePropertiesWereSet | NodeAggregateCurrentlyDoesNotExist | Then workspace user-ws-two has status OUTDATED diff --git a/Neos.ContentRepository.Core/Classes/CommandHandler/CommandSimulator.php b/Neos.ContentRepository.Core/Classes/CommandHandler/CommandSimulator.php index ee3ee2de52c..015fdd86947 100644 --- a/Neos.ContentRepository.Core/Classes/CommandHandler/CommandSimulator.php +++ b/Neos.ContentRepository.Core/Classes/CommandHandler/CommandSimulator.php @@ -9,8 +9,8 @@ use Neos\ContentRepository\Core\EventStore\EventNormalizer; use Neos\ContentRepository\Core\EventStore\EventsToPublish; use Neos\ContentRepository\Core\Feature\RebaseableCommand; -use Neos\ContentRepository\Core\Feature\WorkspaceRebase\CommandsThatFailedDuringRebase; -use Neos\ContentRepository\Core\Feature\WorkspaceRebase\CommandThatFailedDuringRebase; +use Neos\ContentRepository\Core\Feature\WorkspaceRebase\EventsThatFailedDuringRebase; +use Neos\ContentRepository\Core\Feature\WorkspaceRebase\EventThatFailedDuringRebase; use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphProjectionInterface; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\EventStore\Helper\InMemoryEventStore; @@ -45,7 +45,7 @@ */ final class CommandSimulator { - private CommandsThatFailedDuringRebase $commandsThatFailedDuringRebase; + private EventsThatFailedDuringRebase $eventsThatFailedDuringRebase; private readonly InMemoryEventStore $inMemoryEventStore; @@ -56,7 +56,7 @@ public function __construct( private readonly WorkspaceName $workspaceNameToSimulateIn, ) { $this->inMemoryEventStore = new InMemoryEventStore(); - $this->commandsThatFailedDuringRebase = new CommandsThatFailedDuringRebase(); + $this->eventsThatFailedDuringRebase = new EventsThatFailedDuringRebase(); } /** @@ -86,9 +86,11 @@ private function handle(RebaseableCommand $rebaseableCommand): void try { $eventsToPublish = $this->commandBus->handle($commandInWorkspace); } catch (\Exception $exception) { - $this->commandsThatFailedDuringRebase = $this->commandsThatFailedDuringRebase->withAppended( - new CommandThatFailedDuringRebase( - $rebaseableCommand->originalCommand, + $originalEvent = $this->eventNormalizer->denormalize($rebaseableCommand->originalEvent); + + $this->eventsThatFailedDuringRebase = $this->eventsThatFailedDuringRebase->withAppended( + new EventThatFailedDuringRebase( + $originalEvent, $exception, $rebaseableCommand->originalSequenceNumber ) @@ -159,13 +161,13 @@ public function eventStream(): EventStreamInterface return $this->inMemoryEventStore->load(VirtualStreamName::all()); } - public function hasCommandsThatFailed(): bool + public function hasEventsThatFailed(): bool { - return !$this->commandsThatFailedDuringRebase->isEmpty(); + return !$this->eventsThatFailedDuringRebase->isEmpty(); } - public function getCommandsThatFailed(): CommandsThatFailedDuringRebase + public function getEventsThatFailed(): EventsThatFailedDuringRebase { - return $this->commandsThatFailedDuringRebase; + return $this->eventsThatFailedDuringRebase; } } diff --git a/Neos.ContentRepository.Core/Classes/DimensionSpace/DimensionSpacePointSet.php b/Neos.ContentRepository.Core/Classes/DimensionSpace/DimensionSpacePointSet.php index 191dcd2d7f6..65d19b1e04c 100644 --- a/Neos.ContentRepository.Core/Classes/DimensionSpace/DimensionSpacePointSet.php +++ b/Neos.ContentRepository.Core/Classes/DimensionSpace/DimensionSpacePointSet.php @@ -148,6 +148,14 @@ public function equals(DimensionSpacePointSet $other): bool return $thisPointHashes === $otherPointHashes; } + public function getFirst(): ?DimensionSpacePoint + { + foreach ($this->points as $point) { + return $point; + } + return null; + } + public function getIterator(): \Traversable { yield from $this->points; diff --git a/Neos.ContentRepository.Core/Classes/Feature/RebaseableCommand.php b/Neos.ContentRepository.Core/Classes/Feature/RebaseableCommand.php index 210f91b8b8a..b62d85eddd8 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/RebaseableCommand.php +++ b/Neos.ContentRepository.Core/Classes/Feature/RebaseableCommand.php @@ -9,9 +9,11 @@ use Neos\ContentRepository\Core\EventStore\InitiatingEventMetadata; use Neos\ContentRepository\Core\Feature\Common\PublishableToWorkspaceInterface; use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; +use Neos\EventStore\Model\Event; use Neos\EventStore\Model\Event\EventId; use Neos\EventStore\Model\Event\EventMetadata; use Neos\EventStore\Model\Event\SequenceNumber; +use Neos\EventStore\Model\EventEnvelope; /** * @internal @@ -20,17 +22,18 @@ { public function __construct( public RebasableToOtherWorkspaceInterface $originalCommand, + public Event $originalEvent, public EventMetadata $initiatingMetaData, public SequenceNumber $originalSequenceNumber ) { } - public static function extractFromEventMetaData(EventMetadata $eventMetadata, SequenceNumber $sequenceNumber): self + public static function extractFromEventEnvelope(EventEnvelope $eventEnvelope): self { - $commandToRebaseClass = $eventMetadata->value['commandClass'] ?? null; - $commandToRebasePayload = $eventMetadata->value['commandPayload'] ?? null; + $commandToRebaseClass = $eventEnvelope->event->metadata?->value['commandClass'] ?? null; + $commandToRebasePayload = $eventEnvelope->event->metadata?->value['commandPayload'] ?? null; - if ($commandToRebaseClass === null || $commandToRebasePayload === null) { + if ($commandToRebaseClass === null || $commandToRebasePayload === null || $eventEnvelope->event->metadata === null) { throw new \RuntimeException('Command cannot be extracted from metadata, missing commandClass or commandPayload.', 1729847804); } @@ -46,8 +49,9 @@ public static function extractFromEventMetaData(EventMetadata $eventMetadata, Se $commandInstance = $commandToRebaseClass::fromArray($commandToRebasePayload); return new self( $commandInstance, - InitiatingEventMetadata::extractInitiatingMetadata($eventMetadata), - $sequenceNumber + $eventEnvelope->event, + InitiatingEventMetadata::extractInitiatingMetadata($eventEnvelope->event->metadata), + $eventEnvelope->sequenceNumber ); } diff --git a/Neos.ContentRepository.Core/Classes/Feature/RebaseableCommands.php b/Neos.ContentRepository.Core/Classes/Feature/RebaseableCommands.php index 5f4146321fe..fd746e051a4 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/RebaseableCommands.php +++ b/Neos.ContentRepository.Core/Classes/Feature/RebaseableCommands.php @@ -30,7 +30,7 @@ public static function extractFromEventStream(EventStreamInterface $eventStream) $commands = []; foreach ($eventStream as $eventEnvelope) { if ($eventEnvelope->event->metadata && isset($eventEnvelope->event->metadata?->value['commandClass'])) { - $commands[] = RebaseableCommand::extractFromEventMetaData($eventEnvelope->event->metadata, $eventEnvelope->sequenceNumber); + $commands[] = RebaseableCommand::extractFromEventEnvelope($eventEnvelope); } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php index cbec3e0d8e0..2d3467eae40 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php @@ -236,8 +236,8 @@ static function ($handle) use ($rebaseableCommands): void { } ); - if ($commandSimulator->hasCommandsThatFailed()) { - throw WorkspaceRebaseFailed::duringPublish($commandSimulator->getCommandsThatFailed()); + if ($commandSimulator->hasEventsThatFailed()) { + throw WorkspaceRebaseFailed::duringPublish($commandSimulator->getEventsThatFailed()); } yield new EventsToPublish( @@ -381,7 +381,7 @@ static function ($handle) use ($rebaseableCommands): void { if ( $command->rebaseErrorHandlingStrategy === RebaseErrorHandlingStrategy::STRATEGY_FAIL - && $commandSimulator->hasCommandsThatFailed() + && $commandSimulator->hasEventsThatFailed() ) { yield $this->reopenContentStream( $workspace->currentContentStreamId, @@ -389,7 +389,7 @@ static function ($handle) use ($rebaseableCommands): void { ); // throw an exception that contains all the information about what exactly failed - throw WorkspaceRebaseFailed::duringRebase($commandSimulator->getCommandsThatFailed()); + throw WorkspaceRebaseFailed::duringRebase($commandSimulator->getEventsThatFailed()); } // if we got so far without an exception (or if we don't care), we can switch the workspace's active content stream. @@ -504,13 +504,13 @@ static function ($handle) use ($commandSimulator, $matchingCommands, $remainingC } ); - if ($commandSimulator->hasCommandsThatFailed()) { + if ($commandSimulator->hasEventsThatFailed()) { yield $this->reopenContentStream( $workspace->currentContentStreamId, $commandHandlingDependencies ); - throw WorkspaceRebaseFailed::duringPublish($commandSimulator->getCommandsThatFailed()); + throw WorkspaceRebaseFailed::duringPublish($commandSimulator->getEventsThatFailed()); } // this could be a no-op for the rare case when a command returns empty events e.g. the node was already tagged with this subtree tag, meaning we actually just rebase @@ -622,12 +622,12 @@ static function ($handle) use ($commandsToKeep): void { } ); - if ($commandSimulator->hasCommandsThatFailed()) { + if ($commandSimulator->hasEventsThatFailed()) { yield $this->reopenContentStream( $workspace->currentContentStreamId, $commandHandlingDependencies ); - throw WorkspaceRebaseFailed::duringDiscard($commandSimulator->getCommandsThatFailed()); + throw WorkspaceRebaseFailed::duringDiscard($commandSimulator->getEventsThatFailed()); } yield from $this->forkNewContentStreamAndApplyEvents( diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/CommandThatFailedDuringRebase.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/CommandThatFailedDuringRebase.php deleted file mode 100644 index 4f6fd46d615..00000000000 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/CommandThatFailedDuringRebase.php +++ /dev/null @@ -1,95 +0,0 @@ -command::class) { - MoveNodeAggregate::class, - SetSerializedNodeProperties::class, - CreateNodeAggregateWithNodeAndSerializedProperties::class, - TagSubtree::class, - DisableNodeAggregate::class, - UntagSubtree::class, - EnableNodeAggregate::class, - RemoveNodeAggregate::class, - ChangeNodeAggregateType::class, - CreateNodeVariant::class => $this->command->nodeAggregateId, - SetSerializedNodeReferences::class => $this->command->sourceNodeAggregateId, - default => null - }; - } - - /** - * How the command failed that was attempted to be rebased - */ - public function getException(): \Throwable - { - return $this->exception; - } - - /** - * The event store sequence number of the event containing the command to be rebased - * - * @internal exposed for testing - */ - public function getSequenceNumber(): SequenceNumber - { - return $this->sequenceNumber; - } - - /** - * The command that failed - * - * @internal exposed for testing and experimental use cases - */ - public function getCommand(): RebasableToOtherWorkspaceInterface - { - return $this->command; - } -} diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/EventThatFailedDuringRebase.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/EventThatFailedDuringRebase.php new file mode 100644 index 00000000000..8c27ba35030 --- /dev/null +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/EventThatFailedDuringRebase.php @@ -0,0 +1,74 @@ +event instanceof EmbedsNodeAggregateId + ? $this->event->getNodeAggregateId() + : null; + } + + /** + * How the command failed that was attempted to be rebased + */ + public function getException(): \Throwable + { + return $this->exception; + } + + /** + * The event store sequence number of the event containing the command to be rebased + * + * @internal exposed for testing + */ + public function getSequenceNumber(): SequenceNumber + { + return $this->sequenceNumber; + } + + /** + * The command that failed + * + * @internal exposed for testing and experimental use cases + */ + public function getEvent(): EventInterface + { + return $this->event; + } +} diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/CommandsThatFailedDuringRebase.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/EventsThatFailedDuringRebase.php similarity index 69% rename from Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/CommandsThatFailedDuringRebase.php rename to Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/EventsThatFailedDuringRebase.php index 24f1087ee81..943fab58ce4 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/CommandsThatFailedDuringRebase.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/EventsThatFailedDuringRebase.php @@ -15,28 +15,28 @@ namespace Neos\ContentRepository\Core\Feature\WorkspaceRebase; /** - * @implements \IteratorAggregate + * @implements \IteratorAggregate * * @api part of the exception exposed when rebasing failed */ -final readonly class CommandsThatFailedDuringRebase implements \IteratorAggregate, \Countable +final readonly class EventsThatFailedDuringRebase implements \IteratorAggregate, \Countable { /** - * @var array + * @var array */ private array $items; - public function __construct(CommandThatFailedDuringRebase ...$items) + public function __construct(EventThatFailedDuringRebase ...$items) { $this->items = array_values($items); } - public function withAppended(CommandThatFailedDuringRebase $item): self + public function withAppended(EventThatFailedDuringRebase $item): self { return new self(...[...$this->items, $item]); } - public function first(): ?CommandThatFailedDuringRebase + public function first(): ?EventThatFailedDuringRebase { return $this->items[0] ?? null; } diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/Exception/WorkspaceRebaseFailed.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/Exception/WorkspaceRebaseFailed.php index 1ac611e412e..ad6d68afdaf 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/Exception/WorkspaceRebaseFailed.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/Exception/WorkspaceRebaseFailed.php @@ -14,7 +14,7 @@ namespace Neos\ContentRepository\Core\Feature\WorkspaceRebase\Exception; -use Neos\ContentRepository\Core\Feature\WorkspaceRebase\CommandsThatFailedDuringRebase; +use Neos\ContentRepository\Core\Feature\WorkspaceRebase\EventsThatFailedDuringRebase; /** * @api this exception contains information about what exactly went wrong during rebase @@ -22,7 +22,7 @@ final class WorkspaceRebaseFailed extends \Exception { private function __construct( - public readonly CommandsThatFailedDuringRebase $commandsThatFailedDuringRebase, + public readonly EventsThatFailedDuringRebase $eventsThatFailedDuringRebase, string $message, int $code, ?\Throwable $previous, @@ -30,39 +30,39 @@ private function __construct( parent::__construct($message, $code, $previous); } - public static function duringRebase(CommandsThatFailedDuringRebase $commandsThatFailedDuringRebase): self + public static function duringRebase(EventsThatFailedDuringRebase $eventsThatFailedDuringRebase): self { return new self( - $commandsThatFailedDuringRebase, - sprintf('Rebase failed: %s', self::renderMessage($commandsThatFailedDuringRebase)), + $eventsThatFailedDuringRebase, + sprintf('Rebase failed: %s', self::renderMessage($eventsThatFailedDuringRebase)), 1729974936, - $commandsThatFailedDuringRebase->first()?->getException() + $eventsThatFailedDuringRebase->first()?->getException() ); } - public static function duringPublish(CommandsThatFailedDuringRebase $commandsThatFailedDuringRebase): self + public static function duringPublish(EventsThatFailedDuringRebase $eventsThatFailedDuringRebase): self { return new self( - $commandsThatFailedDuringRebase, - sprintf('Publication failed: %s', self::renderMessage($commandsThatFailedDuringRebase)), + $eventsThatFailedDuringRebase, + sprintf('Publication failed: %s', self::renderMessage($eventsThatFailedDuringRebase)), 1729974980, - $commandsThatFailedDuringRebase->first()?->getException() + $eventsThatFailedDuringRebase->first()?->getException() ); } - public static function duringDiscard(CommandsThatFailedDuringRebase $commandsThatFailedDuringRebase): self + public static function duringDiscard(EventsThatFailedDuringRebase $eventsThatFailedDuringRebase): self { return new self( - $commandsThatFailedDuringRebase, - sprintf('Discard failed: %s', self::renderMessage($commandsThatFailedDuringRebase)), + $eventsThatFailedDuringRebase, + sprintf('Discard failed: %s', self::renderMessage($eventsThatFailedDuringRebase)), 1729974982, - $commandsThatFailedDuringRebase->first()?->getException() + $eventsThatFailedDuringRebase->first()?->getException() ); } - private static function renderMessage(CommandsThatFailedDuringRebase $commandsThatFailedDuringRebase): string + private static function renderMessage(EventsThatFailedDuringRebase $eventsThatFailedDuringRebase): string { - $firstFailure = $commandsThatFailedDuringRebase->first(); - return sprintf('"%s" and %d further failures', $firstFailure?->getException()->getMessage(), count($commandsThatFailedDuringRebase) - 1); + $firstFailure = $eventsThatFailedDuringRebase->first(); + return sprintf('"%s" and %d further failures', $firstFailure?->getException()->getMessage(), count($eventsThatFailedDuringRebase) - 1); } } diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/GenericCommandExecutionAndEventPublication.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/GenericCommandExecutionAndEventPublication.php index ccd1e73fd42..f7c05d7b553 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/GenericCommandExecutionAndEventPublication.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/GenericCommandExecutionAndEventPublication.php @@ -173,10 +173,10 @@ public function theLastCommandShouldHaveThrownTheWorkspaceRebaseFailedWith(Table Assert::assertInstanceOf(WorkspaceRebaseFailed::class, $exception, sprintf('Actual exception: %s (%s): %s', get_class($exception), $exception->getCode(), $exception->getMessage())); $actualComparableHash = []; - foreach ($exception->commandsThatFailedDuringRebase as $commandsThatFailed) { + foreach ($exception->eventsThatFailedDuringRebase as $commandsThatFailed) { $actualComparableHash[] = [ 'SequenceNumber' => (string)$commandsThatFailed->getSequenceNumber()->value, - 'Command' => (new \ReflectionClass($commandsThatFailed->getCommand()))->getShortName(), + 'Event' => (new \ReflectionClass($commandsThatFailed->getEvent()))->getShortName(), 'Exception' => (new \ReflectionClass($commandsThatFailed->getException()))->getShortName(), ]; } From 48ebbda430ace4b56de876e10042b1764d086ebb Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Sat, 9 Nov 2024 17:55:51 +0100 Subject: [PATCH 11/15] TASK: Rename `EventThatFailedDuringRebase` to `ConflictingEvent` because events dont fail usually :D --- .../CommandHandler/CommandSimulator.php | 20 +++++------ .../Feature/WorkspaceCommandHandler.php | 16 ++++----- ...dDuringRebase.php => ConflictingEvent.php} | 8 ++--- ...DuringRebase.php => ConflictingEvents.php} | 12 +++---- .../Exception/WorkspaceRebaseFailed.php | 34 +++++++++---------- ...ricCommandExecutionAndEventPublication.php | 8 ++--- 6 files changed, 49 insertions(+), 49 deletions(-) rename Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/{EventThatFailedDuringRebase.php => ConflictingEvent.php} (89%) rename Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/{EventsThatFailedDuringRebase.php => ConflictingEvents.php} (69%) diff --git a/Neos.ContentRepository.Core/Classes/CommandHandler/CommandSimulator.php b/Neos.ContentRepository.Core/Classes/CommandHandler/CommandSimulator.php index 015fdd86947..1b2d46e5333 100644 --- a/Neos.ContentRepository.Core/Classes/CommandHandler/CommandSimulator.php +++ b/Neos.ContentRepository.Core/Classes/CommandHandler/CommandSimulator.php @@ -9,8 +9,8 @@ use Neos\ContentRepository\Core\EventStore\EventNormalizer; use Neos\ContentRepository\Core\EventStore\EventsToPublish; use Neos\ContentRepository\Core\Feature\RebaseableCommand; -use Neos\ContentRepository\Core\Feature\WorkspaceRebase\EventsThatFailedDuringRebase; -use Neos\ContentRepository\Core\Feature\WorkspaceRebase\EventThatFailedDuringRebase; +use Neos\ContentRepository\Core\Feature\WorkspaceRebase\ConflictingEvents; +use Neos\ContentRepository\Core\Feature\WorkspaceRebase\ConflictingEvent; use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphProjectionInterface; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\EventStore\Helper\InMemoryEventStore; @@ -45,7 +45,7 @@ */ final class CommandSimulator { - private EventsThatFailedDuringRebase $eventsThatFailedDuringRebase; + private ConflictingEvents $conflictingEvents; private readonly InMemoryEventStore $inMemoryEventStore; @@ -56,7 +56,7 @@ public function __construct( private readonly WorkspaceName $workspaceNameToSimulateIn, ) { $this->inMemoryEventStore = new InMemoryEventStore(); - $this->eventsThatFailedDuringRebase = new EventsThatFailedDuringRebase(); + $this->conflictingEvents = new ConflictingEvents(); } /** @@ -88,8 +88,8 @@ private function handle(RebaseableCommand $rebaseableCommand): void } catch (\Exception $exception) { $originalEvent = $this->eventNormalizer->denormalize($rebaseableCommand->originalEvent); - $this->eventsThatFailedDuringRebase = $this->eventsThatFailedDuringRebase->withAppended( - new EventThatFailedDuringRebase( + $this->conflictingEvents = $this->conflictingEvents->withAppended( + new ConflictingEvent( $originalEvent, $exception, $rebaseableCommand->originalSequenceNumber @@ -161,13 +161,13 @@ public function eventStream(): EventStreamInterface return $this->inMemoryEventStore->load(VirtualStreamName::all()); } - public function hasEventsThatFailed(): bool + public function hasConflicts(): bool { - return !$this->eventsThatFailedDuringRebase->isEmpty(); + return !$this->conflictingEvents->isEmpty(); } - public function getEventsThatFailed(): EventsThatFailedDuringRebase + public function getConflictingEvents(): ConflictingEvents { - return $this->eventsThatFailedDuringRebase; + return $this->conflictingEvents; } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php index 2d3467eae40..b1be71e7ce6 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php @@ -236,8 +236,8 @@ static function ($handle) use ($rebaseableCommands): void { } ); - if ($commandSimulator->hasEventsThatFailed()) { - throw WorkspaceRebaseFailed::duringPublish($commandSimulator->getEventsThatFailed()); + if ($commandSimulator->hasConflicts()) { + throw WorkspaceRebaseFailed::duringPublish($commandSimulator->getConflictingEvents()); } yield new EventsToPublish( @@ -381,7 +381,7 @@ static function ($handle) use ($rebaseableCommands): void { if ( $command->rebaseErrorHandlingStrategy === RebaseErrorHandlingStrategy::STRATEGY_FAIL - && $commandSimulator->hasEventsThatFailed() + && $commandSimulator->hasConflicts() ) { yield $this->reopenContentStream( $workspace->currentContentStreamId, @@ -389,7 +389,7 @@ static function ($handle) use ($rebaseableCommands): void { ); // throw an exception that contains all the information about what exactly failed - throw WorkspaceRebaseFailed::duringRebase($commandSimulator->getEventsThatFailed()); + throw WorkspaceRebaseFailed::duringRebase($commandSimulator->getConflictingEvents()); } // if we got so far without an exception (or if we don't care), we can switch the workspace's active content stream. @@ -504,13 +504,13 @@ static function ($handle) use ($commandSimulator, $matchingCommands, $remainingC } ); - if ($commandSimulator->hasEventsThatFailed()) { + if ($commandSimulator->hasConflicts()) { yield $this->reopenContentStream( $workspace->currentContentStreamId, $commandHandlingDependencies ); - throw WorkspaceRebaseFailed::duringPublish($commandSimulator->getEventsThatFailed()); + throw WorkspaceRebaseFailed::duringPublish($commandSimulator->getConflictingEvents()); } // this could be a no-op for the rare case when a command returns empty events e.g. the node was already tagged with this subtree tag, meaning we actually just rebase @@ -622,12 +622,12 @@ static function ($handle) use ($commandsToKeep): void { } ); - if ($commandSimulator->hasEventsThatFailed()) { + if ($commandSimulator->hasConflicts()) { yield $this->reopenContentStream( $workspace->currentContentStreamId, $commandHandlingDependencies ); - throw WorkspaceRebaseFailed::duringDiscard($commandSimulator->getEventsThatFailed()); + throw WorkspaceRebaseFailed::duringDiscard($commandSimulator->getConflictingEvents()); } yield from $this->forkNewContentStreamAndApplyEvents( diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/EventThatFailedDuringRebase.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/ConflictingEvent.php similarity index 89% rename from Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/EventThatFailedDuringRebase.php rename to Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/ConflictingEvent.php index 8c27ba35030..21a0fe146e9 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/EventThatFailedDuringRebase.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/ConflictingEvent.php @@ -22,7 +22,7 @@ /** * @api part of the exception exposed when rebasing failed */ -final readonly class EventThatFailedDuringRebase +final readonly class ConflictingEvent { /** * @internal @@ -35,7 +35,7 @@ public function __construct( } /** - * The node aggregate id of the failed command + * The node aggregate id of the conflicting event */ public function getAffectedNodeAggregateId(): ?NodeAggregateId { @@ -45,7 +45,7 @@ public function getAffectedNodeAggregateId(): ?NodeAggregateId } /** - * How the command failed that was attempted to be rebased + * The exception for the conflict */ public function getException(): \Throwable { @@ -63,7 +63,7 @@ public function getSequenceNumber(): SequenceNumber } /** - * The command that failed + * The event that conflicts * * @internal exposed for testing and experimental use cases */ diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/EventsThatFailedDuringRebase.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/ConflictingEvents.php similarity index 69% rename from Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/EventsThatFailedDuringRebase.php rename to Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/ConflictingEvents.php index 943fab58ce4..1b30aa61007 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/EventsThatFailedDuringRebase.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/ConflictingEvents.php @@ -15,28 +15,28 @@ namespace Neos\ContentRepository\Core\Feature\WorkspaceRebase; /** - * @implements \IteratorAggregate + * @implements \IteratorAggregate * * @api part of the exception exposed when rebasing failed */ -final readonly class EventsThatFailedDuringRebase implements \IteratorAggregate, \Countable +final readonly class ConflictingEvents implements \IteratorAggregate, \Countable { /** - * @var array + * @var array */ private array $items; - public function __construct(EventThatFailedDuringRebase ...$items) + public function __construct(ConflictingEvent ...$items) { $this->items = array_values($items); } - public function withAppended(EventThatFailedDuringRebase $item): self + public function withAppended(ConflictingEvent $item): self { return new self(...[...$this->items, $item]); } - public function first(): ?EventThatFailedDuringRebase + public function first(): ?ConflictingEvent { return $this->items[0] ?? null; } diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/Exception/WorkspaceRebaseFailed.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/Exception/WorkspaceRebaseFailed.php index ad6d68afdaf..499ea7a247c 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/Exception/WorkspaceRebaseFailed.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/Exception/WorkspaceRebaseFailed.php @@ -14,7 +14,7 @@ namespace Neos\ContentRepository\Core\Feature\WorkspaceRebase\Exception; -use Neos\ContentRepository\Core\Feature\WorkspaceRebase\EventsThatFailedDuringRebase; +use Neos\ContentRepository\Core\Feature\WorkspaceRebase\ConflictingEvents; /** * @api this exception contains information about what exactly went wrong during rebase @@ -22,7 +22,7 @@ final class WorkspaceRebaseFailed extends \Exception { private function __construct( - public readonly EventsThatFailedDuringRebase $eventsThatFailedDuringRebase, + public readonly ConflictingEvents $conflictingEvents, string $message, int $code, ?\Throwable $previous, @@ -30,39 +30,39 @@ private function __construct( parent::__construct($message, $code, $previous); } - public static function duringRebase(EventsThatFailedDuringRebase $eventsThatFailedDuringRebase): self + public static function duringRebase(ConflictingEvents $conflictingEvents): self { return new self( - $eventsThatFailedDuringRebase, - sprintf('Rebase failed: %s', self::renderMessage($eventsThatFailedDuringRebase)), + $conflictingEvents, + sprintf('Rebase failed: %s', self::renderMessage($conflictingEvents)), 1729974936, - $eventsThatFailedDuringRebase->first()?->getException() + $conflictingEvents->first()?->getException() ); } - public static function duringPublish(EventsThatFailedDuringRebase $eventsThatFailedDuringRebase): self + public static function duringPublish(ConflictingEvents $conflictingEvents): self { return new self( - $eventsThatFailedDuringRebase, - sprintf('Publication failed: %s', self::renderMessage($eventsThatFailedDuringRebase)), + $conflictingEvents, + sprintf('Publication failed: %s', self::renderMessage($conflictingEvents)), 1729974980, - $eventsThatFailedDuringRebase->first()?->getException() + $conflictingEvents->first()?->getException() ); } - public static function duringDiscard(EventsThatFailedDuringRebase $eventsThatFailedDuringRebase): self + public static function duringDiscard(ConflictingEvents $conflictingEvents): self { return new self( - $eventsThatFailedDuringRebase, - sprintf('Discard failed: %s', self::renderMessage($eventsThatFailedDuringRebase)), + $conflictingEvents, + sprintf('Discard failed: %s', self::renderMessage($conflictingEvents)), 1729974982, - $eventsThatFailedDuringRebase->first()?->getException() + $conflictingEvents->first()?->getException() ); } - private static function renderMessage(EventsThatFailedDuringRebase $eventsThatFailedDuringRebase): string + private static function renderMessage(ConflictingEvents $conflictingEvents): string { - $firstFailure = $eventsThatFailedDuringRebase->first(); - return sprintf('"%s" and %d further failures', $firstFailure?->getException()->getMessage(), count($eventsThatFailedDuringRebase) - 1); + $firstConflict = $conflictingEvents->first(); + return sprintf('"%s" and %d further conflicts', $firstConflict?->getException()->getMessage(), count($conflictingEvents) - 1); } } diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/GenericCommandExecutionAndEventPublication.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/GenericCommandExecutionAndEventPublication.php index f7c05d7b553..cdc96abf93b 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/GenericCommandExecutionAndEventPublication.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/GenericCommandExecutionAndEventPublication.php @@ -173,11 +173,11 @@ public function theLastCommandShouldHaveThrownTheWorkspaceRebaseFailedWith(Table Assert::assertInstanceOf(WorkspaceRebaseFailed::class, $exception, sprintf('Actual exception: %s (%s): %s', get_class($exception), $exception->getCode(), $exception->getMessage())); $actualComparableHash = []; - foreach ($exception->eventsThatFailedDuringRebase as $commandsThatFailed) { + foreach ($exception->conflictingEvents as $conflictingEvent) { $actualComparableHash[] = [ - 'SequenceNumber' => (string)$commandsThatFailed->getSequenceNumber()->value, - 'Event' => (new \ReflectionClass($commandsThatFailed->getEvent()))->getShortName(), - 'Exception' => (new \ReflectionClass($commandsThatFailed->getException()))->getShortName(), + 'SequenceNumber' => (string)$conflictingEvent->getSequenceNumber()->value, + 'Event' => (new \ReflectionClass($conflictingEvent->getEvent()))->getShortName(), + 'Exception' => (new \ReflectionClass($conflictingEvent->getException()))->getShortName(), ]; } From 930266df5197653bcb8fde2d3a191ed9658738bc Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Mon, 11 Nov 2024 21:00:27 +0100 Subject: [PATCH 12/15] TASK: Remove hacky method again Chances that its okay to just be interested in the first dsp are low :D --- .../Classes/DimensionSpace/DimensionSpacePointSet.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Neos.ContentRepository.Core/Classes/DimensionSpace/DimensionSpacePointSet.php b/Neos.ContentRepository.Core/Classes/DimensionSpace/DimensionSpacePointSet.php index 65d19b1e04c..191dcd2d7f6 100644 --- a/Neos.ContentRepository.Core/Classes/DimensionSpace/DimensionSpacePointSet.php +++ b/Neos.ContentRepository.Core/Classes/DimensionSpace/DimensionSpacePointSet.php @@ -148,14 +148,6 @@ public function equals(DimensionSpacePointSet $other): bool return $thisPointHashes === $otherPointHashes; } - public function getFirst(): ?DimensionSpacePoint - { - foreach ($this->points as $point) { - return $point; - } - return null; - } - public function getIterator(): \Traversable { yield from $this->points; From 255b38e994eb8c9bbec00db3a4bd612f78ee9287 Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Tue, 12 Nov 2024 12:35:50 +0100 Subject: [PATCH 13/15] TASK: Adjust changed `WorkspaceRebaseFailed` --- .../W8-IndividualNodePublication/03-MoreBasicFeatures.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/03-MoreBasicFeatures.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/03-MoreBasicFeatures.feature index b65bee35200..68a71a14266 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/03-MoreBasicFeatures.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/03-MoreBasicFeatures.feature @@ -201,8 +201,8 @@ Feature: Publishing individual nodes (basics) | nodesToPublish | [{"dimensionSpacePoint": {}, "nodeAggregateId": "sir-unchanged"}] | | contentStreamIdForRemainingPart | "user-cs-identifier-remaining" | Then the last command should have thrown the WorkspaceRebaseFailed exception with: - | SequenceNumber | Command | Exception | - | 14 | TagSubtree | SubtreeIsAlreadyTagged | + | SequenceNumber | Event | Exception | + | 14 | SubtreeWasTagged | SubtreeIsAlreadyTagged | Scenario: It is possible to publish all nodes When the command PublishIndividualNodesFromWorkspace is executed with payload: From dbbb7f19c23987437c11c672caf3ae53fe062e8a Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Tue, 12 Nov 2024 12:36:14 +0100 Subject: [PATCH 14/15] TASK: Remove obsolete array declaration due to interface --- .../Command/AddDimensionShineThrough.php | 3 --- .../CreateNodeAggregateWithNodeAndSerializedProperties.php | 3 --- .../NodeModification/Command/SetSerializedNodeProperties.php | 3 --- .../NodeReferencing/Command/SetSerializedNodeReferences.php | 3 --- .../Feature/NodeRenaming/Command/ChangeNodeAggregateName.php | 3 --- 5 files changed, 15 deletions(-) diff --git a/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/Command/AddDimensionShineThrough.php b/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/Command/AddDimensionShineThrough.php index 936505d278d..f3e3f55bdad 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/Command/AddDimensionShineThrough.php +++ b/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/Command/AddDimensionShineThrough.php @@ -63,9 +63,6 @@ public static function create( return new self($workspaceName, $source, $target); } - /** - * @param array $array - */ public static function fromArray(array $array): self { return new self( diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php b/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php index 3aa8d471d0e..2eb1324ae2e 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php @@ -78,9 +78,6 @@ public static function create(WorkspaceName $workspaceName, NodeAggregateId $nod return new self($workspaceName, $nodeAggregateId, $nodeTypeName, $originDimensionSpacePoint, $parentNodeAggregateId, $initialPropertyValues ?? SerializedPropertyValues::createEmpty(), $succeedingSiblingNodeAggregateId, null, NodeAggregateIdsByNodePaths::createEmpty(), $references ?: SerializedNodeReferences::createEmpty()); } - /** - * @param array $array - */ public static function fromArray(array $array): self { return new self( diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php b/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php index b3d38bf88dc..c3906bae03f 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php @@ -74,9 +74,6 @@ public static function create( ); } - /** - * @param array $array - */ public static function fromArray(array $array): self { return new self( diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php b/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php index 5e95099f806..132f1299ed7 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php @@ -59,9 +59,6 @@ public static function create(WorkspaceName $workspaceName, NodeAggregateId $sou return new self($workspaceName, $sourceNodeAggregateId, $sourceOriginDimensionSpacePoint, $references); } - /** - * @param array $array - */ public static function fromArray(array $array): self { return new self( diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeRenaming/Command/ChangeNodeAggregateName.php b/Neos.ContentRepository.Core/Classes/Feature/NodeRenaming/Command/ChangeNodeAggregateName.php index 38d1f195ed6..d19d6210a48 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeRenaming/Command/ChangeNodeAggregateName.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeRenaming/Command/ChangeNodeAggregateName.php @@ -59,9 +59,6 @@ public static function create(WorkspaceName $workspaceName, NodeAggregateId $nod return new self($workspaceName, $nodeAggregateId, $newNodeName); } - /** - * @param array $array - */ public static function fromArray(array $array): self { return new self( From 9f9f946e3ede5ee37d6e4645779a310ab7ff6fd9 Mon Sep 17 00:00:00 2001 From: Bastian Waidelich Date: Tue, 12 Nov 2024 12:39:59 +0100 Subject: [PATCH 15/15] Fix test --- .../W8-IndividualNodePublication/03-MoreBasicFeatures.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/03-MoreBasicFeatures.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/03-MoreBasicFeatures.feature index b65bee35200..68a71a14266 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/03-MoreBasicFeatures.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/03-MoreBasicFeatures.feature @@ -201,8 +201,8 @@ Feature: Publishing individual nodes (basics) | nodesToPublish | [{"dimensionSpacePoint": {}, "nodeAggregateId": "sir-unchanged"}] | | contentStreamIdForRemainingPart | "user-cs-identifier-remaining" | Then the last command should have thrown the WorkspaceRebaseFailed exception with: - | SequenceNumber | Command | Exception | - | 14 | TagSubtree | SubtreeIsAlreadyTagged | + | SequenceNumber | Event | Exception | + | 14 | SubtreeWasTagged | SubtreeIsAlreadyTagged | Scenario: It is possible to publish all nodes When the command PublishIndividualNodesFromWorkspace is executed with payload: