diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/ContentGraphReadModelAdapter.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/ContentGraphReadModelAdapter.php index 8a0f6de9359..217127e4026 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/ContentGraphReadModelAdapter.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/ContentGraphReadModelAdapter.php @@ -142,7 +142,7 @@ private function getBasicWorkspaceQuery(): QueryBuilder $queryBuilder = $this->dbal->createQueryBuilder(); return $queryBuilder - ->select('ws.name, ws.baseWorkspaceName, ws.currentContentStreamId, cs.hasChanges, cs.sourceContentStreamVersion = scs.version as upToDateWithBase') + ->select('ws.name, ws.baseWorkspaceName, ws.currentContentStreamId, cs.hasChanges, cs.sourceContentStreamVersion = scs.version as upToDateWithBase, ws.version') ->from($this->tableNames->workspace(), 'ws') ->join('ws', $this->tableNames->contentStream(), 'cs', 'cs.id = ws.currentcontentstreamid') ->leftJoin('cs', $this->tableNames->contentStream(), 'scs', 'scs.id = cs.sourceContentStreamId'); @@ -174,6 +174,7 @@ private static function workspaceFromDatabaseRow(array $row): Workspace $baseWorkspaceName === null ? false : (bool)$row['hasChanges'], + Version::fromInteger((int)$row['version']), ); } diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphProjection.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphProjection.php index f4c146f23bd..751e5fc2c77 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphProjection.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphProjection.php @@ -161,15 +161,15 @@ public function apply(EventInterface $event, EventEnvelope $eventEnvelope): void NodeSpecializationVariantWasCreated::class => $this->whenNodeSpecializationVariantWasCreated($event, $eventEnvelope), RootNodeAggregateDimensionsWereUpdated::class => $this->whenRootNodeAggregateDimensionsWereUpdated($event), RootNodeAggregateWithNodeWasCreated::class => $this->whenRootNodeAggregateWithNodeWasCreated($event, $eventEnvelope), - RootWorkspaceWasCreated::class => $this->whenRootWorkspaceWasCreated($event), + RootWorkspaceWasCreated::class => $this->whenRootWorkspaceWasCreated($event, $eventEnvelope), SubtreeWasTagged::class => $this->whenSubtreeWasTagged($event), SubtreeWasUntagged::class => $this->whenSubtreeWasUntagged($event), - WorkspaceBaseWorkspaceWasChanged::class => $this->whenWorkspaceBaseWorkspaceWasChanged($event), + WorkspaceBaseWorkspaceWasChanged::class => $this->whenWorkspaceBaseWorkspaceWasChanged($event, $eventEnvelope), WorkspaceRebaseFailed::class => $this->whenWorkspaceRebaseFailed($event), - WorkspaceWasCreated::class => $this->whenWorkspaceWasCreated($event), - WorkspaceWasDiscarded::class => $this->whenWorkspaceWasDiscarded($event), - WorkspaceWasPublished::class => $this->whenWorkspaceWasPublished($event), - WorkspaceWasRebased::class => $this->whenWorkspaceWasRebased($event), + WorkspaceWasCreated::class => $this->whenWorkspaceWasCreated($event, $eventEnvelope), + WorkspaceWasDiscarded::class => $this->whenWorkspaceWasDiscarded($event, $eventEnvelope), + WorkspaceWasPublished::class => $this->whenWorkspaceWasPublished($event, $eventEnvelope), + WorkspaceWasRebased::class => $this->whenWorkspaceWasRebased($event, $eventEnvelope), WorkspaceWasRemoved::class => $this->whenWorkspaceWasRemoved($event), default => null, }; @@ -668,9 +668,9 @@ private function whenRootNodeAggregateWithNodeWasCreated(RootNodeAggregateWithNo ); } - private function whenRootWorkspaceWasCreated(RootWorkspaceWasCreated $event): void + private function whenRootWorkspaceWasCreated(RootWorkspaceWasCreated $event, EventEnvelope $eventEnvelope): void { - $this->createWorkspace($event->workspaceName, null, $event->newContentStreamId); + $this->createWorkspace($event->workspaceName, null, $event->newContentStreamId, $eventEnvelope->version); } private function whenSubtreeWasTagged(SubtreeWasTagged $event): void @@ -683,9 +683,9 @@ private function whenSubtreeWasUntagged(SubtreeWasUntagged $event): void $this->removeSubtreeTag($event->contentStreamId, $event->nodeAggregateId, $event->affectedDimensionSpacePoints, $event->tag); } - private function whenWorkspaceBaseWorkspaceWasChanged(WorkspaceBaseWorkspaceWasChanged $event): void + private function whenWorkspaceBaseWorkspaceWasChanged(WorkspaceBaseWorkspaceWasChanged $event, EventEnvelope $eventEnvelope): void { - $this->updateBaseWorkspace($event->workspaceName, $event->baseWorkspaceName, $event->newContentStreamId); + $this->updateBaseWorkspace($event->workspaceName, $event->baseWorkspaceName, $event->newContentStreamId, $eventEnvelope->version); } private function whenWorkspaceRebaseFailed(WorkspaceRebaseFailed $event): void @@ -697,24 +697,24 @@ private function whenWorkspaceRebaseFailed(WorkspaceRebaseFailed $event): void $this->reopenContentStream($event->sourceContentStreamId); } - private function whenWorkspaceWasCreated(WorkspaceWasCreated $event): void + private function whenWorkspaceWasCreated(WorkspaceWasCreated $event, EventEnvelope $eventEnvelope): void { - $this->createWorkspace($event->workspaceName, $event->baseWorkspaceName, $event->newContentStreamId); + $this->createWorkspace($event->workspaceName, $event->baseWorkspaceName, $event->newContentStreamId, $eventEnvelope->version); } - private function whenWorkspaceWasDiscarded(WorkspaceWasDiscarded $event): void + private function whenWorkspaceWasDiscarded(WorkspaceWasDiscarded $event, EventEnvelope $eventEnvelope): void { - $this->updateWorkspaceContentStreamId($event->workspaceName, $event->newContentStreamId); + $this->updateWorkspaceContentStreamId($event->workspaceName, $event->newContentStreamId, $eventEnvelope->version); } - private function whenWorkspaceWasPublished(WorkspaceWasPublished $event): void + private function whenWorkspaceWasPublished(WorkspaceWasPublished $event, EventEnvelope $eventEnvelope): void { - $this->updateWorkspaceContentStreamId($event->sourceWorkspaceName, $event->newSourceContentStreamId); + $this->updateWorkspaceContentStreamId($event->sourceWorkspaceName, $event->newSourceContentStreamId, $eventEnvelope->version); } - private function whenWorkspaceWasRebased(WorkspaceWasRebased $event): void + private function whenWorkspaceWasRebased(WorkspaceWasRebased $event, EventEnvelope $eventEnvelope): void { - $this->updateWorkspaceContentStreamId($event->workspaceName, $event->newContentStreamId); + $this->updateWorkspaceContentStreamId($event->workspaceName, $event->newContentStreamId, $eventEnvelope->version); } private function whenWorkspaceWasRemoved(WorkspaceWasRemoved $event): void diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphSchemaBuilder.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphSchemaBuilder.php index 77cda091e68..05486ee7100 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphSchemaBuilder.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphSchemaBuilder.php @@ -110,6 +110,7 @@ private function createWorkspaceTable(AbstractPlatform $platform): Table DbalSchemaFactory::columnForWorkspaceName('name', $platform)->setNotnull(true), DbalSchemaFactory::columnForWorkspaceName('baseWorkspaceName', $platform)->setNotnull(false), DbalSchemaFactory::columnForContentStreamId('currentContentStreamId', $platform)->setNotNull(true), + (new Column('version', Type::getType(Types::INTEGER)))->setNotnull(true), ]); $workspaceTable->addUniqueIndex(['currentContentStreamId']); diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/Workspace.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/Workspace.php index 882e4469f96..99ec5aeedc2 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/Workspace.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/Workspace.php @@ -6,6 +6,7 @@ use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; +use Neos\EventStore\Model\Event\Version; /** * The Workspace projection feature trait @@ -14,12 +15,13 @@ */ trait Workspace { - private function createWorkspace(WorkspaceName $workspaceName, ?WorkspaceName $baseWorkspaceName, ContentStreamId $contentStreamId): void + private function createWorkspace(WorkspaceName $workspaceName, ?WorkspaceName $baseWorkspaceName, ContentStreamId $contentStreamId, Version $version): void { $this->dbal->insert($this->tableNames->workspace(), [ 'name' => $workspaceName->value, 'baseWorkspaceName' => $baseWorkspaceName?->value, - 'currentContentStreamId' => $contentStreamId->value + 'currentContentStreamId' => $contentStreamId->value, + 'version' => $version->value, ]); } @@ -31,13 +33,14 @@ private function removeWorkspace(WorkspaceName $workspaceName): void ); } - private function updateBaseWorkspace(WorkspaceName $workspaceName, WorkspaceName $baseWorkspaceName, ContentStreamId $newContentStreamId): void + private function updateBaseWorkspace(WorkspaceName $workspaceName, WorkspaceName $baseWorkspaceName, ContentStreamId $newContentStreamId, Version $version): void { $this->dbal->update( $this->tableNames->workspace(), [ 'baseWorkspaceName' => $baseWorkspaceName->value, 'currentContentStreamId' => $newContentStreamId->value, + 'version' => $version->value, ], ['name' => $workspaceName->value] ); @@ -46,9 +49,11 @@ private function updateBaseWorkspace(WorkspaceName $workspaceName, WorkspaceName private function updateWorkspaceContentStreamId( WorkspaceName $workspaceName, ContentStreamId $contentStreamId, + Version $version, ): void { $this->dbal->update($this->tableNames->workspace(), [ 'currentContentStreamId' => $contentStreamId->value, + 'version' => $version->value, ], [ 'name' => $workspaceName->value ]); diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php index 46b5b33064d..11d2b50c9c0 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php @@ -270,7 +270,7 @@ static function ($handle) use ($rebaseableCommands): void { partial: false ) ), - ExpectedVersion::ANY() + ExpectedVersion::fromVersion($workspace->version), ); yield $this->removeContentStreamWithoutConstraintChecks($workspace->currentContentStreamId); @@ -299,7 +299,7 @@ private function rebaseWorkspaceWithoutChanges( skippedEvents: [] ), ), - ExpectedVersion::ANY() + ExpectedVersion::fromVersion($workspace->version), ); yield $this->removeContentStreamWithoutConstraintChecks($workspace->currentContentStreamId); @@ -419,7 +419,7 @@ static function ($handle) use ($rebaseableCommands): void { ->map(fn (ConflictingEvent $conflictingEvent) => $conflictingEvent->getSequenceNumber()) ), ), - ExpectedVersion::ANY() + ExpectedVersion::fromVersion($workspace->version), ), $this->getCopiedEventsOfEventStream( $command->workspaceName, @@ -538,7 +538,7 @@ static function ($handle) use ($commandSimulator, $matchingCommands, $remainingC partial: !$remainingCommands->isEmpty() ) ]), - ExpectedVersion::ANY() + ExpectedVersion::fromVersion($workspace->version), ), $this->getCopiedEventsOfEventStream( $command->workspaceName, @@ -645,7 +645,7 @@ static function ($handle) use ($commandsToKeep): void { partial: true ) ), - ExpectedVersion::ANY() + ExpectedVersion::fromVersion($workspace->version), ), $this->getCopiedEventsOfEventStream( $command->workspaceName, @@ -711,7 +711,7 @@ private function discardWorkspace( partial: false ) ), - ExpectedVersion::ANY() + ExpectedVersion::fromVersion($workspace->version), ); yield $this->removeContentStreamWithoutConstraintChecks($workspace->currentContentStreamId); @@ -760,7 +760,7 @@ private function handleChangeBaseWorkspace( $command->newContentStreamId, ) ), - ExpectedVersion::ANY() + ExpectedVersion::fromVersion($workspace->version), ); } @@ -791,7 +791,7 @@ private function handleDeleteWorkspace( $command->workspaceName, ) ), - ExpectedVersion::ANY() + ExpectedVersion::fromVersion($workspace->version), ); } diff --git a/Neos.ContentRepository.Core/Classes/SharedModel/Workspace/Workspace.php b/Neos.ContentRepository.Core/Classes/SharedModel/Workspace/Workspace.php index 5a9a9985e2e..0d73d6226f7 100644 --- a/Neos.ContentRepository.Core/Classes/SharedModel/Workspace/Workspace.php +++ b/Neos.ContentRepository.Core/Classes/SharedModel/Workspace/Workspace.php @@ -14,6 +14,8 @@ namespace Neos\ContentRepository\Core\SharedModel\Workspace; +use Neos\EventStore\Model\Event\Version; + /** * Workspace Read Model * @@ -32,7 +34,8 @@ private function __construct( public ?WorkspaceName $baseWorkspaceName, public ContentStreamId $currentContentStreamId, public WorkspaceStatus $status, - private bool $hasPublishableChanges + private bool $hasPublishableChanges, + public Version $version, ) { if ($this->isRootWorkspace() && $this->hasPublishableChanges) { throw new \InvalidArgumentException('Root workspaces cannot have changes', 1730371566); @@ -47,9 +50,10 @@ public static function create( ?WorkspaceName $baseWorkspaceName, ContentStreamId $currentContentStreamId, WorkspaceStatus $status, - bool $hasPublishableChanges + bool $hasPublishableChanges, + Version $version, ): self { - return new self($workspaceName, $baseWorkspaceName, $currentContentStreamId, $status, $hasPublishableChanges); + return new self($workspaceName, $baseWorkspaceName, $currentContentStreamId, $status, $hasPublishableChanges, $version); } /**