diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/ContentGraphReadModelAdapter.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/ContentGraphReadModelAdapter.php index 2aeab76b054..a95df6236c9 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/ContentGraphReadModelAdapter.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/ContentGraphReadModelAdapter.php @@ -159,7 +159,7 @@ private function getBasicWorkspaceQuery(): QueryBuilder $queryBuilder = $this->dbal->createQueryBuilder(); return $queryBuilder - ->select('ws.name, ws.baseWorkspaceName, ws.currentContentStreamId, cs.sourceContentStreamVersion = scs.version as upToDateWithBase, cs.publishableEvents as publishableEventsOnStream') + ->select('ws.name, ws.baseWorkspaceName, ws.currentContentStreamId, cs.sourceContentStreamVersion = scs.version as upToDateWithBase, cs.dirty as workspaceHasChanges') ->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'); @@ -188,7 +188,9 @@ private static function workspaceFromDatabaseRow(array $row): Workspace $baseWorkspaceName, ContentStreamId::fromString($row['currentContentStreamId']), $status, - $baseWorkspaceName === null ? 0 : $row['publishableEventsOnStream'], + $baseWorkspaceName === null + ? false + : (bool)$row['workspaceHasChanges'], ); } diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphSchemaBuilder.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphSchemaBuilder.php index 6c26bb966e3..2683b06b86c 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphSchemaBuilder.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphSchemaBuilder.php @@ -129,8 +129,8 @@ private function createContentStreamTable(): Table (new Column('version', Type::getType(Types::INTEGER)))->setNotnull(true), DbalSchemaFactory::columnForContentStreamId('sourceContentStreamId')->setNotnull(false), (new Column('sourceContentStreamVersion', Type::getType(Types::INTEGER)))->setNotnull(false), - (new Column('closed', Type::getType(Types::BOOLEAN)))->setDefault(false)->setNotnull(true), - (new Column('publishableEvents', Type::getType(Types::INTEGER)))->setNotnull(true), + (new Column('closed', Type::getType(Types::BOOLEAN)))->setNotnull(true), + (new Column('dirty', Type::getType(Types::BOOLEAN)))->setNotnull(true), ]); return $contentStreamTable->setPrimaryKey(['id']); diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/ContentStream.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/ContentStream.php index 1ac406ee1f1..cc5abaf69a8 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/ContentStream.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/ContentStream.php @@ -24,7 +24,8 @@ private function createContentStream(ContentStreamId $contentStreamId, ?ContentS 'version' => 0, 'sourceContentStreamId' => $sourceContentStreamId?->value, 'sourceContentStreamVersion' => $sourceVersion?->value, - 'publishableEvents' => 0 + 'closed' => 0, + 'dirty' => 0 ]); } @@ -57,20 +58,14 @@ private function updateContentStreamVersion(EventInterface&EmbedsContentStreamId { // todo make fork content stream `EmbedsContentStreamId` but then just ignore it here because we set the version already $isPublishableEvent = $event instanceof PublishableToWorkspaceInterface; + $updatePayload = [ + 'version' => $version->value, + ]; if ($isPublishableEvent) { - $this->dbal->executeStatement( - "UPDATE {$this->tableNames->contentStream()} SET version=:version, publishableEvents=publishableEvents+1 WHERE id=:id", - [ - 'version' => $version->value, - 'id' => $event->getContentStreamId()->value, - ] - ); - } else { - $this->dbal->update($this->tableNames->contentStream(), [ - 'version' => $version->value, - ], [ - 'id' => $event->getContentStreamId()->value, - ]); + $updatePayload['dirty'] = 1; } + $this->dbal->update($this->tableNames->contentStream(), $updatePayload, [ + 'id' => $event->getContentStreamId()->value, + ]); } } diff --git a/Neos.ContentRepository.Core/Classes/SharedModel/Workspace/Workspace.php b/Neos.ContentRepository.Core/Classes/SharedModel/Workspace/Workspace.php index 4e15eb038d4..5a9a9985e2e 100644 --- a/Neos.ContentRepository.Core/Classes/SharedModel/Workspace/Workspace.php +++ b/Neos.ContentRepository.Core/Classes/SharedModel/Workspace/Workspace.php @@ -32,12 +32,9 @@ private function __construct( public ?WorkspaceName $baseWorkspaceName, public ContentStreamId $currentContentStreamId, public WorkspaceStatus $status, - private int $countOfPublishableChanges + private bool $hasPublishableChanges ) { - if ($this->countOfPublishableChanges < 0) { - throw new \InvalidArgumentException('The number of changes must be greater than 0', 1730371545); - } - if ($this->isRootWorkspace() && $this->countOfPublishableChanges !== 0) { + if ($this->isRootWorkspace() && $this->hasPublishableChanges) { throw new \InvalidArgumentException('Root workspaces cannot have changes', 1730371566); } } @@ -50,19 +47,17 @@ public static function create( ?WorkspaceName $baseWorkspaceName, ContentStreamId $currentContentStreamId, WorkspaceStatus $status, - int $countOfPublishableChanges + bool $hasPublishableChanges ): self { - return new self($workspaceName, $baseWorkspaceName, $currentContentStreamId, $status, $countOfPublishableChanges); + return new self($workspaceName, $baseWorkspaceName, $currentContentStreamId, $status, $hasPublishableChanges); } + /** + * Indicates if the workspace contains changed to be published + */ public function hasPublishableChanges(): bool { - return $this->countOfPublishableChanges !== 0; - } - - public function countPublishableChanges(): int - { - return $this->countOfPublishableChanges; + return $this->hasPublishableChanges; } /** diff --git a/Neos.Neos/Classes/Command/WorkspaceCommandController.php b/Neos.Neos/Classes/Command/WorkspaceCommandController.php index 2acd849db5c..5e58e39f5a5 100644 --- a/Neos.Neos/Classes/Command/WorkspaceCommandController.php +++ b/Neos.Neos/Classes/Command/WorkspaceCommandController.php @@ -398,13 +398,15 @@ public function deleteCommand(string $workspace, bool $force = false, string $co if ($crWorkspace->hasPublishableChanges()) { if ($force === false) { + try { + $nodesCount = $this->workspacePublishingService->countPendingWorkspaceChanges($contentRepositoryId, $workspaceName); + } catch (\Exception) { + $nodesCount = 'NAN'; + } $this->outputLine( - 'Did not delete workspace "%s" because it contains %d publishable changes.' - . ' Use --force to delete it nevertheless.', - [ - $crWorkspace->countPublishableChanges(), - $workspaceName->value - ] + 'Did not delete workspace "%s" because it contains %s unpublished node(s).' + . ' Use --force to delete it nevertheless.', + [$workspaceName->value, $nodesCount] ); $this->quit(5); } diff --git a/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php b/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php index aea6f8d3f7c..1ba6afe6e20 100644 --- a/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php +++ b/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php @@ -27,11 +27,11 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Projection\ContentGraph\Nodes; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; -use Neos\ContentRepository\Core\SharedModel\Workspace\Workspace; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; use Neos\ContentRepository\Core\SharedModel\Node\NodeAddress; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\Workspace; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Diff\Diff; @@ -374,12 +374,15 @@ public function deleteAction(WorkspaceName $workspaceName): void } if ($workspace->hasPublishableChanges()) { - // todo indicate to the user that theses changes ARE NOT change projection changes - $changesCount = $workspace->countPublishableChanges(); + try { + $nodesCount = $this->workspacePublishingService->countPendingWorkspaceChanges($contentRepositoryId, $workspaceName); + } catch (\Exception) { + $nodesCount = null; + } $message = $this->translator->translateById( 'workspaces.workspaceCannotBeDeletedBecauseOfUnpublishedNodes', - [$workspaceMetadata->title->value, $changesCount], - $changesCount, + [$workspaceMetadata->title->value, $nodesCount ?? 'NAN'], + $nodesCount, null, 'Main', 'Neos.Workspace.Ui'