diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/ContentGraphTableNames.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/ContentGraphTableNames.php index e591fdec386..787b5d24665 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/ContentGraphTableNames.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/ContentGraphTableNames.php @@ -47,6 +47,11 @@ public function workspace(): string return $this->tableNamePrefix . '_workspace'; } + public function contentStream(): string + { + return $this->tableNamePrefix . '_contentstream'; + } + public function checkpoint(): string { return $this->tableNamePrefix . '_checkpoint'; diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphProjection.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphProjection.php index ed89f7adcf4..0b6225571e5 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphProjection.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphProjection.php @@ -6,6 +6,7 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\Exception as DBALException; +use Neos\ContentGraph\DoctrineDbalAdapter\Domain\Projection\Feature\ContentStream; use Neos\ContentGraph\DoctrineDbalAdapter\Domain\Projection\Feature\NodeMove; use Neos\ContentGraph\DoctrineDbalAdapter\Domain\Projection\Feature\NodeRemoval; use Neos\ContentGraph\DoctrineDbalAdapter\Domain\Projection\Feature\NodeVariation; @@ -22,6 +23,10 @@ use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\EventStore\EventInterface; use Neos\ContentRepository\Core\Feature\Common\InterdimensionalSiblings; +use Neos\ContentRepository\Core\Feature\ContentStreamClosing\Event\ContentStreamWasClosed; +use Neos\ContentRepository\Core\Feature\ContentStreamClosing\Event\ContentStreamWasReopened; +use Neos\ContentRepository\Core\Feature\ContentStreamCreation\Event\ContentStreamWasCreated; +use Neos\ContentRepository\Core\Feature\ContentStreamEventStreamName; use Neos\ContentRepository\Core\Feature\ContentStreamForking\Event\ContentStreamWasForked; use Neos\ContentRepository\Core\Feature\ContentStreamRemoval\Event\ContentStreamWasRemoved; use Neos\ContentRepository\Core\Feature\DimensionSpaceAdjustment\Event\DimensionShineThroughWasAdded; @@ -65,6 +70,7 @@ use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamState; use Neos\EventStore\Model\Event\SequenceNumber; use Neos\EventStore\Model\EventEnvelope; @@ -74,6 +80,7 @@ */ final class DoctrineDbalContentGraphProjection implements ProjectionInterface { + use ContentStream; use NodeMove; use NodeRemoval; use NodeVariation; @@ -103,7 +110,7 @@ public function setUp(): void { $statements = $this->determineRequiredSqlStatements(); - // MIGRATION from 2024-05-23: copy data from "cr__p_workspace" to "cr__p_graph_workspace" table + // MIGRATION from 2024-05-25: copy data from "cr__p_workspace"/"cr__p_contentstream" to "cr__p_graph_workspace"/"cr__p_graph_contentstream" tables $legacyWorkspaceTableName = str_replace('_p_graph_workspace', '_p_workspace', $this->tableNames->workspace()); if ( $this->dbal->getSchemaManager()->tablesExist([$legacyWorkspaceTableName]) @@ -111,6 +118,13 @@ public function setUp(): void ) { $statements[] = 'INSERT INTO ' . $this->tableNames->workspace() . ' (workspacename, baseworkspacename, currentcontentstreamid, status) SELECT workspacename, baseworkspacename, currentcontentstreamid, status FROM ' . $legacyWorkspaceTableName; } + $legacyContentStreamTableName = str_replace('_p_graph_contentstream', '_p_contentstream', $this->tableNames->contentStream()); + if ( + $this->dbal->getSchemaManager()->tablesExist([$legacyContentStreamTableName]) + && !$this->dbal->getSchemaManager()->tablesExist([$this->tableNames->contentStream()]) + ) { + $statements[] = 'INSERT INTO ' . $this->tableNames->contentStream() . ' (contentStreamId, version, sourceContentStreamId, state, removed) SELECT contentStreamId, version, sourceContentStreamId, state, removed FROM ' . $legacyContentStreamTableName; + } // /MIGRATION foreach ($statements as $statement) { @@ -169,8 +183,11 @@ public function getState(): ContentGraphFinder public function canHandle(EventInterface $event): bool { return in_array($event::class, [ + ContentStreamWasClosed::class, + ContentStreamWasCreated::class, ContentStreamWasForked::class, ContentStreamWasRemoved::class, + ContentStreamWasReopened::class, DimensionShineThroughWasAdded::class, DimensionSpacePointWasMoved::class, NodeAggregateNameWasChanged::class, @@ -203,8 +220,11 @@ public function canHandle(EventInterface $event): bool public function apply(EventInterface $event, EventEnvelope $eventEnvelope): void { match ($event::class) { + ContentStreamWasClosed::class => $this->whenContentStreamWasClosed($event), + ContentStreamWasCreated::class => $this->whenContentStreamWasCreated($event), ContentStreamWasForked::class => $this->whenContentStreamWasForked($event), ContentStreamWasRemoved::class => $this->whenContentStreamWasRemoved($event), + ContentStreamWasReopened::class => $this->whenContentStreamWasReopened($event), DimensionShineThroughWasAdded::class => $this->whenDimensionShineThroughWasAdded($event), DimensionSpacePointWasMoved::class => $this->whenDimensionSpacePointWasMoved($event), NodeAggregateNameWasChanged::class => $this->whenNodeAggregateNameWasChanged($event, $eventEnvelope), @@ -233,6 +253,19 @@ public function apply(EventInterface $event, EventEnvelope $eventEnvelope): void WorkspaceWasRemoved::class => $this->whenWorkspaceWasRemoved($event), default => throw new \InvalidArgumentException(sprintf('Unsupported event %s', get_debug_type($event))), }; + if (ContentStreamEventStreamName::isContentStreamStreamName($eventEnvelope->streamName)) { + $this->updateContentStreamVersion(ContentStreamEventStreamName::extractContentStreamIdFromStreamName($eventEnvelope->streamName), $eventEnvelope->version); + } + } + + private function whenContentStreamWasClosed(ContentStreamWasClosed $event): void + { + $this->updateContentStreamState($event->contentStreamId, ContentStreamState::STATE_CLOSED); + } + + private function whenContentStreamWasCreated(ContentStreamWasCreated $event): void + { + $this->createContentStream($event->contentStreamId, ContentStreamState::STATE_CREATED); } private function whenContentStreamWasForked(ContentStreamWasForked $event): void @@ -270,6 +303,8 @@ private function whenContentStreamWasForked(ContentStreamWasForked $event): void // NOTE: as reference edges are attached to Relation Anchor Points (and they are lazily copy-on-written), // we do not need to copy reference edges here (but we need to do it during copy on write). + + $this->createContentStream($event->newContentStreamId, ContentStreamState::STATE_FORKED); } private function whenContentStreamWasRemoved(ContentStreamWasRemoved $event): void @@ -313,6 +348,13 @@ private function whenContentStreamWasRemoved(ContentStreamWasRemoved $event): vo } catch (DBALException $e) { throw new \RuntimeException(sprintf('Failed to delete non-referenced reference relations: %s', $e->getMessage()), 1716489328, $e); } + + $this->removeContentStream($event->contentStreamId); + } + + private function whenContentStreamWasReopened(ContentStreamWasReopened $event): void + { + $this->updateContentStreamState($event->contentStreamId, $event->previousState); } private function whenDimensionShineThroughWasAdded(DimensionShineThroughWasAdded $event): void @@ -667,6 +709,9 @@ private function whenRootNodeAggregateWithNodeWasCreated(RootNodeAggregateWithNo private function whenRootWorkspaceWasCreated(RootWorkspaceWasCreated $event): void { $this->createWorkspace($event->workspaceName, null, $event->newContentStreamId); + + // the content stream is in use now + $this->updateContentStreamState($event->newContentStreamId, ContentStreamState::STATE_IN_USE_BY_WORKSPACE); } private function whenSubtreeWasTagged(SubtreeWasTagged $event): void @@ -687,11 +732,15 @@ private function whenWorkspaceBaseWorkspaceWasChanged(WorkspaceBaseWorkspaceWasC private function whenWorkspaceRebaseFailed(WorkspaceRebaseFailed $event): void { $this->markWorkspaceAsOutdatedConflict($event->workspaceName); + $this->updateContentStreamState($event->candidateContentStreamId, ContentStreamState::STATE_REBASE_ERROR); } private function whenWorkspaceWasCreated(WorkspaceWasCreated $event): void { $this->createWorkspace($event->workspaceName, $event->baseWorkspaceName, $event->newContentStreamId); + + // the content stream is in use now + $this->updateContentStreamState($event->newContentStreamId, ContentStreamState::STATE_IN_USE_BY_WORKSPACE); } private function whenWorkspaceWasDiscarded(WorkspaceWasDiscarded $event): void @@ -699,12 +748,23 @@ private function whenWorkspaceWasDiscarded(WorkspaceWasDiscarded $event): void $this->updateWorkspaceContentStreamId($event->workspaceName, $event->newContentStreamId); $this->markWorkspaceAsOutdated($event->workspaceName); $this->markDependentWorkspacesAsOutdated($event->workspaceName); + + // the new content stream is in use now + $this->updateContentStreamState($event->newContentStreamId, ContentStreamState::STATE_IN_USE_BY_WORKSPACE); + // the previous content stream is no longer in use + $this->updateContentStreamState($event->previousContentStreamId, ContentStreamState::STATE_NO_LONGER_IN_USE); } private function whenWorkspaceWasPartiallyDiscarded(WorkspaceWasPartiallyDiscarded $event): void { $this->updateWorkspaceContentStreamId($event->workspaceName, $event->newContentStreamId); $this->markDependentWorkspacesAsOutdated($event->workspaceName); + + // the new content stream is in use now + $this->updateContentStreamState($event->newContentStreamId, ContentStreamState::STATE_IN_USE_BY_WORKSPACE); + + // the previous content stream is no longer in use + $this->updateContentStreamState($event->previousContentStreamId, ContentStreamState::STATE_NO_LONGER_IN_USE); } private function whenWorkspaceWasPartiallyPublished(WorkspaceWasPartiallyPublished $event): void @@ -717,6 +777,12 @@ private function whenWorkspaceWasPartiallyPublished(WorkspaceWasPartiallyPublish $this->markWorkspaceAsUpToDate($event->sourceWorkspaceName); $this->markDependentWorkspacesAsOutdated($event->sourceWorkspaceName); + + // the new content stream is in use now + $this->updateContentStreamState($event->newSourceContentStreamId, ContentStreamState::STATE_IN_USE_BY_WORKSPACE); + + // the previous content stream is no longer in use + $this->updateContentStreamState($event->previousSourceContentStreamId, ContentStreamState::STATE_NO_LONGER_IN_USE); } private function whenWorkspaceWasPublished(WorkspaceWasPublished $event): void @@ -729,6 +795,12 @@ private function whenWorkspaceWasPublished(WorkspaceWasPublished $event): void $this->markWorkspaceAsUpToDate($event->sourceWorkspaceName); $this->markDependentWorkspacesAsOutdated($event->sourceWorkspaceName); + + // the new content stream is in use now + $this->updateContentStreamState($event->newSourceContentStreamId, ContentStreamState::STATE_IN_USE_BY_WORKSPACE); + + // the previous content stream is no longer in use + $this->updateContentStreamState($event->previousSourceContentStreamId, ContentStreamState::STATE_NO_LONGER_IN_USE); } private function whenWorkspaceWasRebased(WorkspaceWasRebased $event): void @@ -738,6 +810,12 @@ private function whenWorkspaceWasRebased(WorkspaceWasRebased $event): void // When the rebase is successful, we can set the status of the workspace back to UP_TO_DATE. $this->markWorkspaceAsUpToDate($event->workspaceName); + + // the new content stream is in use now + $this->updateContentStreamState($event->newContentStreamId, ContentStreamState::STATE_IN_USE_BY_WORKSPACE); + + // the previous content stream is no longer in use + $this->updateContentStreamState($event->previousContentStreamId, ContentStreamState::STATE_NO_LONGER_IN_USE); } private function whenWorkspaceWasRemoved(WorkspaceWasRemoved $event): void diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphSchemaBuilder.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphSchemaBuilder.php index 13b561e12f9..98c11ddc39a 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphSchemaBuilder.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphSchemaBuilder.php @@ -38,6 +38,7 @@ public function buildSchema(AbstractSchemaManager $schemaManager): Schema $this->createReferenceRelationTable(), $this->createDimensionSpacePointsTable(), $this->createWorkspaceTable(), + $this->createContentStreamTable(), ]); } @@ -120,6 +121,18 @@ private function createWorkspaceTable(): Table return $workspaceTable->setPrimaryKey(['workspacename']); } + private function createContentStreamTable(): Table + { + return self::createTable($this->tableNames->contentStream(), [ + DbalSchemaFactory::columnForContentStreamId('contentStreamId')->setNotnull(true), + (new Column('version', Type::getType(Types::INTEGER)))->setNotnull(true), + DbalSchemaFactory::columnForContentStreamId('sourceContentStreamId')->setNotnull(false), + // Should become a DB ENUM (unclear how to configure with DBAL) or int (latter needs adaption to code) + (new Column('state', Type::getType(Types::BINARY)))->setLength(20)->setNotnull(true), + (new Column('removed', Type::getType(Types::BOOLEAN)))->setDefault(false)->setNotnull(false) + ]); + } + /** * @param array $columns */ diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/ContentStream.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/ContentStream.php new file mode 100644 index 00000000000..bc39979bf46 --- /dev/null +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/ContentStream.php @@ -0,0 +1,54 @@ +dbal->insert($this->tableNames->contentStream(), [ + 'contentStreamId' => $contentStreamId->value, + 'sourceContentStreamId' => $sourceContentStreamId?->value, + 'version' => 0, + 'state' => $state->value, + ]); + } + + private function updateContentStreamState(ContentStreamId $contentStreamId, ContentStreamState $state): void + { + $this->dbal->update($this->tableNames->contentStream(), [ + 'state' => $state->value, + ], [ + 'contentStreamId' => $contentStreamId->value + ]); + } + + private function removeContentStream(ContentStreamId $contentStreamId): void + { + $this->dbal->update($this->tableNames->contentStream(), [ + 'removed' => true, + ], [ + 'contentStreamId' => $contentStreamId->value + ]); + } + + private function updateContentStreamVersion(ContentStreamId $contentStreamId, Version $version): void + { + $this->dbal->update($this->tableNames->contentStream(), [ + 'version' => $version->value, + ], [ + 'contentStreamId' => $contentStreamId->value, + ]); + } +} diff --git a/Neos.ContentRepository.Core/Classes/CommandHandlingDependencies.php b/Neos.ContentRepository.Core/Classes/CommandHandlingDependencies.php index c0b5270cc37..3f3515e81f3 100644 --- a/Neos.ContentRepository.Core/Classes/CommandHandlingDependencies.php +++ b/Neos.ContentRepository.Core/Classes/CommandHandlingDependencies.php @@ -17,11 +17,12 @@ use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\CommandHandler\CommandResult; use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphInterface; -use Neos\ContentRepository\Core\Projection\ContentStream\ContentStreamFinder; -use Neos\ContentRepository\Core\Projection\Workspace\WorkspaceFinder; +use Neos\ContentRepository\Core\Projection\Workspace\Workspace; use Neos\ContentRepository\Core\SharedModel\Exception\WorkspaceDoesNotExist; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamState; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; +use Neos\EventStore\Model\Event\Version; /** * An adapter to provide aceess to read projection data and delegate (sub) commands @@ -46,14 +47,28 @@ public function handle(CommandInterface $command): CommandResult return $this->contentRepository->handle($command); } - public function getWorkspaceFinder(): WorkspaceFinder + public function getContentStreamVersion(ContentStreamId $contentStreamId): Version { - return $this->contentRepository->getWorkspaceFinder(); + // TODO implement + return Version::fromInteger(1); } - public function getContentStreamFinder(): ContentStreamFinder + public function contentStreamExists(ContentStreamId $contentStreamId): bool { - return $this->contentRepository->getContentStreamFinder(); + // TODO implement + return false; + } + + public function getContentStreamState(ContentStreamId $contentStreamId): ContentStreamState + { + // TODO implement + return ContentStreamState::STATE_FORKED; + } + + public function findWorkspaceByName(WorkspaceName $workspaceName): ?Workspace + { + // TODO implement + return null; } /** diff --git a/Neos.ContentRepository.Core/Classes/ContentRepository.php b/Neos.ContentRepository.Core/Classes/ContentRepository.php index 955cf80fe26..d107f399139 100644 --- a/Neos.ContentRepository.Core/Classes/ContentRepository.php +++ b/Neos.ContentRepository.Core/Classes/ContentRepository.php @@ -30,13 +30,13 @@ use Neos\ContentRepository\Core\Projection\CatchUp; use Neos\ContentRepository\Core\Projection\CatchUpOptions; use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphInterface; -use Neos\ContentRepository\Core\Projection\ContentStream\ContentStreamFinder; use Neos\ContentRepository\Core\Projection\ProjectionInterface; use Neos\ContentRepository\Core\Projection\ProjectionsAndCatchUpHooks; use Neos\ContentRepository\Core\Projection\ProjectionStateInterface; use Neos\ContentRepository\Core\Projection\ProjectionStatuses; use Neos\ContentRepository\Core\Projection\WithMarkStaleInterface; -use Neos\ContentRepository\Core\Projection\Workspace\WorkspaceFinder; +use Neos\ContentRepository\Core\Projection\Workspace\Workspace; +use Neos\ContentRepository\Core\Projection\Workspace\Workspaces; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryStatus; use Neos\ContentRepository\Core\SharedModel\Exception\WorkspaceDoesNotExist; @@ -239,22 +239,23 @@ public function getNodeTypeManager(): NodeTypeManager return $this->nodeTypeManager; } - /** - * @throws WorkspaceDoesNotExist if the workspace does not exist - */ - public function getContentGraph(WorkspaceName $workspaceName): ContentGraphInterface + public function findWorkspaceByName(WorkspaceName $workspaceName): ?Workspace { - return $this->projectionState(ContentGraphFinder::class)->getByWorkspaceName($workspaceName); + // TODO implement + return null; } - public function getWorkspaceFinder(): WorkspaceFinder + public function getWorkspaces(): Workspaces { - return $this->projectionState(WorkspaceFinder::class); + // TODO implement } - public function getContentStreamFinder(): ContentStreamFinder + /** + * @throws WorkspaceDoesNotExist if the workspace does not exist + */ + public function getContentGraph(WorkspaceName $workspaceName): ContentGraphInterface { - return $this->projectionState(ContentStreamFinder::class); + return $this->projectionState(ContentGraphFinder::class)->getByWorkspaceName($workspaceName); } public function getVariationGraph(): InterDimensionalVariationGraph diff --git a/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php b/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php index 9cb894f5d76..69259c8a5fa 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php +++ b/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php @@ -81,14 +81,13 @@ protected function requireContentStream( CommandHandlingDependencies $commandHandlingDependencies ): ContentStreamId { $contentStreamId = $commandHandlingDependencies->getContentGraph($workspaceName)->getContentStreamId(); - $state = $commandHandlingDependencies->getContentStreamFinder()->findStateForContentStream($contentStreamId); - if ($state === null) { + if (!$commandHandlingDependencies->contentStreamExists($contentStreamId)) { throw new ContentStreamDoesNotExistYet( 'Content stream for "' . $workspaceName->value . '" does not exist yet.', 1521386692 ); } - + $state = $commandHandlingDependencies->getContentStreamState($contentStreamId); if ($state === ContentStreamState::STATE_CLOSED) { throw new ContentStreamIsClosed( 'Content stream "' . $contentStreamId->value . '" is closed.', @@ -676,7 +675,7 @@ protected function getExpectedVersionOfContentStream( ): ExpectedVersion { return ExpectedVersion::fromVersion( - $commandHandlingDependencies->getContentStreamFinder()->findVersionForContentStream($contentStreamId)->unwrap() + $commandHandlingDependencies->getContentStreamVersion($contentStreamId) ); } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/ContentStreamCommandHandler.php b/Neos.ContentRepository.Core/Classes/Feature/ContentStreamCommandHandler.php index 2c9d9160ccd..c1e33319d5f 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/ContentStreamCommandHandler.php +++ b/Neos.ContentRepository.Core/Classes/Feature/ContentStreamCommandHandler.php @@ -137,7 +137,7 @@ private function handleForkContentStream( $this->requireContentStreamToNotBeClosed($command->sourceContentStreamId, $commandHandlingDependencies); $this->requireContentStreamToNotExistYet($command->newContentStreamId, $commandHandlingDependencies); - $sourceContentStreamVersion = $commandHandlingDependencies->getContentStreamFinder()->findVersionForContentStream($command->sourceContentStreamId); + $sourceContentStreamVersion = $commandHandlingDependencies->getContentStreamVersion($command->sourceContentStreamId); $streamName = ContentStreamEventStreamName::fromContentStreamId($command->newContentStreamId) ->getEventStreamName(); @@ -148,7 +148,7 @@ private function handleForkContentStream( new ContentStreamWasForked( $command->newContentStreamId, $command->sourceContentStreamId, - $sourceContentStreamVersion->unwrap(), + $sourceContentStreamVersion, ), ), // NO_STREAM to ensure the "fork" happens as the first event of the new content stream @@ -187,7 +187,7 @@ protected function requireContentStreamToNotExistYet( ContentStreamId $contentStreamId, CommandHandlingDependencies $commandHandlingDependencies ): void { - if ($commandHandlingDependencies->getContentStreamFinder()->hasContentStream($contentStreamId)) { + if ($commandHandlingDependencies->contentStreamExists($contentStreamId)) { throw new ContentStreamAlreadyExists( 'Content stream "' . $contentStreamId->value . '" already exists.', 1521386345 @@ -204,8 +204,7 @@ protected function requireContentStreamToExist( ContentStreamId $contentStreamId, CommandHandlingDependencies $commandHandlingDependencies ): void { - $maybeVersion = $commandHandlingDependencies->getContentStreamFinder()->findVersionForContentStream($contentStreamId); - if ($maybeVersion->isNothing()) { + if (!$commandHandlingDependencies->contentStreamExists($contentStreamId)) { throw new ContentStreamDoesNotExistYet( 'Content stream "' . $contentStreamId->value . '" does not exist yet.', 1521386692 @@ -217,8 +216,7 @@ protected function requireContentStreamToNotBeClosed( ContentStreamId $contentStreamId, CommandHandlingDependencies $commandHandlingDependencies ): void { - $contentStreamState = $commandHandlingDependencies->getContentStreamFinder()->findStateForContentStream($contentStreamId); - if ($contentStreamState === ContentStreamState::STATE_CLOSED) { + if ($commandHandlingDependencies->getContentStreamState($contentStreamId) === ContentStreamState::STATE_CLOSED) { throw new ContentStreamIsClosed( 'Content stream "' . $contentStreamId->value . '" is closed.', 1710260081 @@ -230,8 +228,7 @@ protected function requireContentStreamToBeClosed( ContentStreamId $contentStreamId, CommandHandlingDependencies $commandHandlingDependencies ): void { - $contentStreamState = $commandHandlingDependencies->getContentStreamFinder()->findStateForContentStream($contentStreamId); - if ($contentStreamState !== ContentStreamState::STATE_CLOSED) { + if ($commandHandlingDependencies->getContentStreamState($contentStreamId) !== ContentStreamState::STATE_CLOSED) { throw new ContentStreamIsNotClosed( 'Content stream "' . $contentStreamId->value . '" is not closed.', 1710405911 @@ -243,10 +240,7 @@ protected function getExpectedVersionOfContentStream( ContentStreamId $contentStreamId, CommandHandlingDependencies $commandHandlingDependencies ): ExpectedVersion { - $maybeVersion = $commandHandlingDependencies->getContentStreamFinder()->findVersionForContentStream($contentStreamId); - return ExpectedVersion::fromVersion( - $maybeVersion - ->unwrap() - ); + $version = $commandHandlingDependencies->getContentStreamVersion($contentStreamId); + return ExpectedVersion::fromVersion($version); } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/ContentStreamEventStreamName.php b/Neos.ContentRepository.Core/Classes/Feature/ContentStreamEventStreamName.php index b1735fc01e9..395d7861959 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/ContentStreamEventStreamName.php +++ b/Neos.ContentRepository.Core/Classes/Feature/ContentStreamEventStreamName.php @@ -24,7 +24,7 @@ */ final readonly class ContentStreamEventStreamName { - public const EVENT_STREAM_NAME_PREFIX = 'ContentStream:'; + private const EVENT_STREAM_NAME_PREFIX = 'ContentStream:'; private function __construct( public string $value @@ -36,6 +36,19 @@ public static function fromContentStreamId(ContentStreamId $contentStreamId): se return new self(self::EVENT_STREAM_NAME_PREFIX . $contentStreamId->value); } + public static function isContentStreamStreamName(StreamName $streamName): bool + { + return str_starts_with($streamName->value, self::EVENT_STREAM_NAME_PREFIX); + } + + public static function extractContentStreamIdFromStreamName(StreamName $streamName): ContentStreamId + { + if (!self::isContentStreamStreamName($streamName)) { + throw new \InvalidArgumentException(sprintf('Failed to extract content stream id from stream name "%s"', $streamName->value), 1716640692); + } + return ContentStreamId::fromString(substr($streamName->value, strlen(self::EVENT_STREAM_NAME_PREFIX))); + } + public function getEventStreamName(): StreamName { return StreamName::fromString($this->value); diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php index 3789512c04d..3ca93c83168 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php @@ -41,13 +41,10 @@ use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Exception\BaseWorkspaceDoesNotExist; use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Exception\WorkspaceAlreadyExists; use Neos\ContentRepository\Core\Feature\WorkspaceModification\Command\ChangeBaseWorkspace; -use Neos\ContentRepository\Core\Feature\WorkspaceModification\Command\ChangeWorkspaceOwner; use Neos\ContentRepository\Core\Feature\WorkspaceModification\Command\DeleteWorkspace; -use Neos\ContentRepository\Core\Feature\WorkspaceModification\Command\RenameWorkspace; use Neos\ContentRepository\Core\Feature\WorkspaceModification\Event\WorkspaceBaseWorkspaceWasChanged; use Neos\ContentRepository\Core\Feature\WorkspaceModification\Event\WorkspaceOwnerWasChanged; use Neos\ContentRepository\Core\Feature\WorkspaceModification\Event\WorkspaceWasRemoved; -use Neos\ContentRepository\Core\Feature\WorkspaceModification\Event\WorkspaceWasRenamed; use Neos\ContentRepository\Core\Feature\WorkspaceModification\Exception\BaseWorkspaceEqualsWorkspaceException; use Neos\ContentRepository\Core\Feature\WorkspaceModification\Exception\CircularRelationBetweenWorkspacesException; use Neos\ContentRepository\Core\Feature\WorkspaceModification\Exception\WorkspaceIsNotEmptyException; @@ -68,7 +65,6 @@ use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Event\WorkspaceWasRebased; use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Exception\WorkspaceRebaseFailed; use Neos\ContentRepository\Core\Projection\Workspace\Workspace; -use Neos\ContentRepository\Core\Projection\Workspace\WorkspaceFinder; use Neos\ContentRepository\Core\SharedModel\Exception\ContentStreamAlreadyExists; use Neos\ContentRepository\Core\SharedModel\Exception\ContentStreamDoesNotExistYet; use Neos\ContentRepository\Core\SharedModel\Exception\WorkspaceDoesNotExist; @@ -103,7 +99,6 @@ public function handle(CommandInterface $command, CommandHandlingDependencies $c /** @phpstan-ignore-next-line */ return match ($command::class) { CreateWorkspace::class => $this->handleCreateWorkspace($command, $commandHandlingDependencies), - RenameWorkspace::class => $this->handleRenameWorkspace($command, $commandHandlingDependencies), CreateRootWorkspace::class => $this->handleCreateRootWorkspace($command, $commandHandlingDependencies), PublishWorkspace::class => $this->handlePublishWorkspace($command, $commandHandlingDependencies), RebaseWorkspace::class => $this->handleRebaseWorkspace($command, $commandHandlingDependencies), @@ -111,7 +106,6 @@ public function handle(CommandInterface $command, CommandHandlingDependencies $c DiscardIndividualNodesFromWorkspace::class => $this->handleDiscardIndividualNodesFromWorkspace($command, $commandHandlingDependencies), DiscardWorkspace::class => $this->handleDiscardWorkspace($command, $commandHandlingDependencies), DeleteWorkspace::class => $this->handleDeleteWorkspace($command, $commandHandlingDependencies), - ChangeWorkspaceOwner::class => $this->handleChangeWorkspaceOwner($command, $commandHandlingDependencies), ChangeBaseWorkspace::class => $this->handleChangeBaseWorkspace($command, $commandHandlingDependencies), }; } @@ -127,9 +121,7 @@ private function handleCreateWorkspace( CommandHandlingDependencies $commandHandlingDependencies, ): EventsToPublish { $this->requireWorkspaceToNotExist($command->workspaceName, $commandHandlingDependencies); - - $baseWorkspace = $commandHandlingDependencies->getWorkspaceFinder()->findOneByName($command->baseWorkspaceName); - if ($baseWorkspace === null) { + if ($commandHandlingDependencies->findWorkspaceByName($command->baseWorkspaceName) === null) { throw new BaseWorkspaceDoesNotExist(sprintf( 'The workspace %s (base workspace of %s) does not exist', $command->baseWorkspaceName->value, @@ -164,30 +156,6 @@ private function handleCreateWorkspace( ); } - /** - * @throws WorkspaceDoesNotExist - */ - private function handleRenameWorkspace( - RenameWorkspace $command, - CommandHandlingDependencies $commandHandlingDependencies - ): EventsToPublish { - $this->requireWorkspace($command->workspaceName, $commandHandlingDependencies->getWorkspaceFinder()); - - $events = Events::with( - new WorkspaceWasRenamed( - $command->workspaceName, - $command->workspaceTitle, - $command->workspaceDescription, - ) - ); - - return new EventsToPublish( - WorkspaceEventStreamName::fromWorkspaceName($command->workspaceName)->getEventStreamName(), - $events, - ExpectedVersion::STREAM_EXISTS() - ); - } - /** * @param CreateRootWorkspace $command * @return EventsToPublish @@ -236,8 +204,8 @@ private function handlePublishWorkspace( PublishWorkspace $command, CommandHandlingDependencies $commandHandlingDependencies, ): EventsToPublish { - $workspace = $this->requireWorkspace($command->workspaceName, $commandHandlingDependencies->getWorkspaceFinder()); - $baseWorkspace = $this->requireBaseWorkspace($workspace, $commandHandlingDependencies->getWorkspaceFinder()); + $workspace = $this->requireWorkspace($command->workspaceName, $commandHandlingDependencies); + $baseWorkspace = $this->requireBaseWorkspace($workspace, $commandHandlingDependencies); $this->publishContentStream( $workspace->currentContentStreamId, @@ -353,14 +321,13 @@ private function handleRebaseWorkspace( RebaseWorkspace $command, CommandHandlingDependencies $commandHandlingDependencies, ): EventsToPublish { - $workspace = $this->requireWorkspace($command->workspaceName, $commandHandlingDependencies->getWorkspaceFinder()); - $baseWorkspace = $this->requireBaseWorkspace($workspace, $commandHandlingDependencies->getWorkspaceFinder()); + $workspace = $this->requireWorkspace($command->workspaceName, $commandHandlingDependencies); + $baseWorkspace = $this->requireBaseWorkspace($workspace, $commandHandlingDependencies); $oldWorkspaceContentStreamId = $workspace->currentContentStreamId; - $oldWorkspaceContentStreamIdState = $commandHandlingDependencies->getContentStreamFinder() - ->findStateForContentStream($oldWorkspaceContentStreamId); - if ($oldWorkspaceContentStreamIdState === null) { + if (!$commandHandlingDependencies->contentStreamExists($oldWorkspaceContentStreamId)) { throw new \DomainException('Cannot rebase a workspace with a stateless content stream', 1711718314); } + $oldWorkspaceContentStreamIdState = $commandHandlingDependencies->getContentStreamState($oldWorkspaceContentStreamId); // 0) close old content stream $commandHandlingDependencies->handle( @@ -488,13 +455,13 @@ private function handlePublishIndividualNodesFromWorkspace( CommandHandlingDependencies $commandHandlingDependencies, ): EventsToPublish { $contentGraph = $commandHandlingDependencies->getContentGraph($command->workspaceName); - $workspace = $this->requireWorkspace($command->workspaceName, $commandHandlingDependencies->getWorkspaceFinder()); + $workspace = $this->requireWorkspace($command->workspaceName, $commandHandlingDependencies); $oldWorkspaceContentStreamId = $workspace->currentContentStreamId; - $oldWorkspaceContentStreamIdState = $commandHandlingDependencies->getContentStreamFinder()->findStateForContentStream($oldWorkspaceContentStreamId); - if ($oldWorkspaceContentStreamIdState === null) { + if (!$commandHandlingDependencies->contentStreamExists($oldWorkspaceContentStreamId)) { throw new \DomainException('Cannot publish nodes on a workspace with a stateless content stream', 1710410114); } - $baseWorkspace = $this->requireBaseWorkspace($workspace, $commandHandlingDependencies->getWorkspaceFinder()); + $oldWorkspaceContentStreamIdState = $commandHandlingDependencies->getContentStreamState($oldWorkspaceContentStreamId); + $baseWorkspace = $this->requireBaseWorkspace($workspace, $commandHandlingDependencies); // 1) close old content stream $commandHandlingDependencies->handle( @@ -629,13 +596,13 @@ private function handleDiscardIndividualNodesFromWorkspace( CommandHandlingDependencies $commandHandlingDependencies, ): EventsToPublish { $contentGraph = $commandHandlingDependencies->getContentGraph($command->workspaceName); - $workspace = $this->requireWorkspace($command->workspaceName, $commandHandlingDependencies->getWorkspaceFinder()); + $workspace = $this->requireWorkspace($command->workspaceName, $commandHandlingDependencies); $oldWorkspaceContentStreamId = $contentGraph->getContentStreamId(); - $oldWorkspaceContentStreamIdState = $commandHandlingDependencies->getContentStreamFinder()->findStateForContentStream($contentGraph->getContentStreamId()); - if ($oldWorkspaceContentStreamIdState === null) { + if (!$commandHandlingDependencies->contentStreamExists($contentGraph->getContentStreamId())) { throw new \DomainException('Cannot discard nodes on a workspace with a stateless content stream', 1710408112); } - $baseWorkspace = $this->requireBaseWorkspace($workspace, $commandHandlingDependencies->getWorkspaceFinder()); + $oldWorkspaceContentStreamIdState = $commandHandlingDependencies->getContentStreamState($contentGraph->getContentStreamId()); + $baseWorkspace = $this->requireBaseWorkspace($workspace, $commandHandlingDependencies); // 1) close old content stream $commandHandlingDependencies->handle( @@ -773,8 +740,8 @@ private function handleDiscardWorkspace( DiscardWorkspace $command, CommandHandlingDependencies $commandHandlingDependencies, ): EventsToPublish { - $workspace = $this->requireWorkspace($command->workspaceName, $commandHandlingDependencies->getWorkspaceFinder()); - $baseWorkspace = $this->requireBaseWorkspace($workspace, $commandHandlingDependencies->getWorkspaceFinder()); + $workspace = $this->requireWorkspace($command->workspaceName, $commandHandlingDependencies); + $baseWorkspace = $this->requireBaseWorkspace($workspace, $commandHandlingDependencies); $newContentStream = $command->newContentStreamId; $commandHandlingDependencies->handle( @@ -815,12 +782,12 @@ private function handleChangeBaseWorkspace( ChangeBaseWorkspace $command, CommandHandlingDependencies $commandHandlingDependencies, ): EventsToPublish { - $workspace = $this->requireWorkspace($command->workspaceName, $commandHandlingDependencies->getWorkspaceFinder()); + $workspace = $this->requireWorkspace($command->workspaceName, $commandHandlingDependencies); $this->requireEmptyWorkspace($workspace); - $this->requireBaseWorkspace($workspace, $commandHandlingDependencies->getWorkspaceFinder()); - $baseWorkspace = $this->requireBaseWorkspace($workspace, $commandHandlingDependencies->getWorkspaceFinder()); + $this->requireBaseWorkspace($workspace, $commandHandlingDependencies); + $baseWorkspace = $this->requireBaseWorkspace($workspace, $commandHandlingDependencies); - $this->requireNonCircularRelationBetweenWorkspaces($workspace, $baseWorkspace, $commandHandlingDependencies->getWorkspaceFinder()); + $this->requireNonCircularRelationBetweenWorkspaces($workspace, $baseWorkspace, $commandHandlingDependencies); $commandHandlingDependencies->handle( ForkContentStream::create( @@ -852,7 +819,7 @@ private function handleDeleteWorkspace( DeleteWorkspace $command, CommandHandlingDependencies $commandHandlingDependencies, ): EventsToPublish { - $workspace = $this->requireWorkspace($command->workspaceName, $commandHandlingDependencies->getWorkspaceFinder()); + $workspace = $this->requireWorkspace($command->workspaceName, $commandHandlingDependencies); $commandHandlingDependencies->handle( RemoveContentStream::create( @@ -874,30 +841,6 @@ private function handleDeleteWorkspace( ); } - /** - * @throws WorkspaceDoesNotExist - */ - private function handleChangeWorkspaceOwner( - ChangeWorkspaceOwner $command, - CommandHandlingDependencies $commandHandlingDependencies - ): EventsToPublish { - $this->requireWorkspace($command->workspaceName, $commandHandlingDependencies->getWorkspaceFinder()); - - $events = Events::with( - new WorkspaceOwnerWasChanged( - $command->workspaceName, - $command->newWorkspaceOwner - ) - ); - - $streamName = WorkspaceEventStreamName::fromWorkspaceName($command->workspaceName)->getEventStreamName(); - return new EventsToPublish( - $streamName, - $events, - ExpectedVersion::STREAM_EXISTS() - ); - } - private function requireWorkspaceToNotExist(WorkspaceName $workspaceName, CommandHandlingDependencies $commandHandlingDependencies): void { try { @@ -916,9 +859,9 @@ private function requireWorkspaceToNotExist(WorkspaceName $workspaceName, Comman /** * @throws WorkspaceDoesNotExist */ - private function requireWorkspace(WorkspaceName $workspaceName, WorkspaceFinder $workspaceFinder): Workspace + private function requireWorkspace(WorkspaceName $workspaceName, CommandHandlingDependencies $commandHandlingDependencies): Workspace { - $workspace = $workspaceFinder->findOneByName($workspaceName); + $workspace = $commandHandlingDependencies->findWorkspaceByName($workspaceName); if (is_null($workspace)) { throw WorkspaceDoesNotExist::butWasSupposedTo($workspaceName); } @@ -930,24 +873,15 @@ private function requireWorkspace(WorkspaceName $workspaceName, WorkspaceFinder * @throws WorkspaceHasNoBaseWorkspaceName * @throws BaseWorkspaceDoesNotExist */ - private function requireBaseWorkspace( - Workspace $workspace, - WorkspaceFinder $workspaceFinder - ): Workspace { + private function requireBaseWorkspace(Workspace $workspace, CommandHandlingDependencies $commandHandlingDependencies): Workspace + { if (is_null($workspace->baseWorkspaceName)) { throw WorkspaceHasNoBaseWorkspaceName::butWasSupposedTo($workspace->workspaceName); } - - try { - $baseWorkspace = $workspaceFinder->findOneByName($workspace->baseWorkspaceName); - } catch (WorkspaceDoesNotExist $_) { - $baseWorkspace = null; - } - + $baseWorkspace = $commandHandlingDependencies->findWorkspaceByName($workspace->baseWorkspaceName); if (is_null($baseWorkspace)) { throw BaseWorkspaceDoesNotExist::butWasSupposedTo($workspace->workspaceName); } - return $baseWorkspace; } @@ -955,7 +889,7 @@ private function requireBaseWorkspace( * @throws BaseWorkspaceEqualsWorkspaceException * @throws CircularRelationBetweenWorkspacesException */ - private function requireNonCircularRelationBetweenWorkspaces(Workspace $workspace, Workspace $baseWorkspace, WorkspaceFinder $workspaceFinder): void + private function requireNonCircularRelationBetweenWorkspaces(Workspace $workspace, Workspace $baseWorkspace, CommandHandlingDependencies $commandHandlingDependencies): void { if ($workspace->workspaceName->equals($baseWorkspace->workspaceName)) { throw new BaseWorkspaceEqualsWorkspaceException(sprintf('The base workspace of the target must be different from the given workspace "%s".', $workspace->workspaceName->value)); @@ -965,7 +899,7 @@ private function requireNonCircularRelationBetweenWorkspaces(Workspace $workspac if ($workspace->workspaceName->equals($nextBaseWorkspace->baseWorkspaceName)) { throw new CircularRelationBetweenWorkspacesException(sprintf('The workspace "%s" is already on the path of the target workspace "%s".', $workspace->workspaceName->value, $baseWorkspace->workspaceName->value)); } - $nextBaseWorkspace = $this->requireBaseWorkspace($nextBaseWorkspace, $workspaceFinder); + $nextBaseWorkspace = $this->requireBaseWorkspace($nextBaseWorkspace, $commandHandlingDependencies); } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceModification/Command/ChangeWorkspaceOwner.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceModification/Command/ChangeWorkspaceOwner.php deleted file mode 100644 index 740fed703b6..00000000000 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceModification/Command/ChangeWorkspaceOwner.php +++ /dev/null @@ -1,37 +0,0 @@ -updateContentStreamVersion($event, $eventEnvelope); } match ($event::class) { + ContentStreamWasClosed::class => $this->whenContentStreamWasClosed($event, $eventEnvelope), ContentStreamWasCreated::class => $this->whenContentStreamWasCreated($event, $eventEnvelope), + ContentStreamWasForked::class => $this->whenContentStreamWasForked($event, $eventEnvelope), + ContentStreamWasRemoved::class => $this->whenContentStreamWasRemoved($event, $eventEnvelope), + ContentStreamWasReopened::class => $this->whenContentStreamWasReopened($event, $eventEnvelope), + DimensionShineThroughWasAdded::class => $this->whenDimensionShineThroughWasAdded($event, $eventEnvelope), RootWorkspaceWasCreated::class => $this->whenRootWorkspaceWasCreated($event), + WorkspaceRebaseFailed::class => $this->whenWorkspaceRebaseFailed($event), WorkspaceWasCreated::class => $this->whenWorkspaceWasCreated($event), - ContentStreamWasForked::class => $this->whenContentStreamWasForked($event, $eventEnvelope), WorkspaceWasDiscarded::class => $this->whenWorkspaceWasDiscarded($event), WorkspaceWasPartiallyDiscarded::class => $this->whenWorkspaceWasPartiallyDiscarded($event), WorkspaceWasPartiallyPublished::class => $this->whenWorkspaceWasPartiallyPublished($event), WorkspaceWasPublished::class => $this->whenWorkspaceWasPublished($event), WorkspaceWasRebased::class => $this->whenWorkspaceWasRebased($event), - WorkspaceRebaseFailed::class => $this->whenWorkspaceRebaseFailed($event), - ContentStreamWasClosed::class => $this->whenContentStreamWasClosed($event, $eventEnvelope), - ContentStreamWasReopened::class => $this->whenContentStreamWasReopened($event, $eventEnvelope), - ContentStreamWasRemoved::class => $this->whenContentStreamWasRemoved($event, $eventEnvelope), - DimensionShineThroughWasAdded::class => $this->whenDimensionShineThroughWasAdded($event, $eventEnvelope), default => $event instanceof EmbedsContentStreamId || throw new \InvalidArgumentException(sprintf('Unsupported event %s', get_debug_type($event))), }; } @@ -393,13 +393,13 @@ private static function extractVersion(EventEnvelope $eventEnvelope): int if ( !str_starts_with( $eventEnvelope->streamName->value, - ContentStreamEventStreamName::EVENT_STREAM_NAME_PREFIX + 'ContentStream:' ) ) { throw new \RuntimeException( 'Cannot extract version number, as it was projected on wrong stream "' . $eventEnvelope->streamName->value . '", but needs to start with ' - . ContentStreamEventStreamName::EVENT_STREAM_NAME_PREFIX + . 'ContentStream:' ); } return $eventEnvelope->version->value; diff --git a/Neos.ContentRepository.Core/Classes/Projection/Workspace/Workspaces.php b/Neos.ContentRepository.Core/Classes/Projection/Workspace/Workspaces.php index f8fea6db6db..82a9399355c 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/Workspace/Workspaces.php +++ b/Neos.ContentRepository.Core/Classes/Projection/Workspace/Workspaces.php @@ -100,8 +100,34 @@ public function getIterator(): \Traversable yield from array_values($this->workspaces); } + /** + * @param \Closure(Workspace): bool $callback + */ + public function filter(\Closure $callback): self + { + return new self(array_Filter($this->workspaces, $callback)); + } + + /** + * @param \Closure(Workspace): bool $callback + */ + public function find(\Closure $callback): ?Workspace + { + foreach ($this->workspaces as $workspace) { + if ($callback($workspace)) { + return $workspace; + } + } + return null; + } + public function count(): int { return count($this->workspaces); } + + public function isEmpty(): bool + { + return $this->workspaces === []; + } } diff --git a/Neos.ContentRepository.Core/Classes/Service/ContentRepositoryBootstrapper.php b/Neos.ContentRepository.Core/Classes/Service/ContentRepositoryBootstrapper.php index 3a835b5cb77..6dd837c9a81 100644 --- a/Neos.ContentRepository.Core/Classes/Service/ContentRepositoryBootstrapper.php +++ b/Neos.ContentRepository.Core/Classes/Service/ContentRepositoryBootstrapper.php @@ -40,7 +40,7 @@ public static function create(ContentRepository $contentRepository): self public function getOrCreateLiveWorkspace(): Workspace { $liveWorkspaceName = WorkspaceName::forLive(); - $liveWorkspace = $this->contentRepository->getWorkspaceFinder()->findOneByName($liveWorkspaceName); + $liveWorkspace = $this->contentRepository->findWorkspaceByName($liveWorkspaceName); if ($liveWorkspace instanceof Workspace) { return $liveWorkspace; } @@ -53,7 +53,7 @@ public function getOrCreateLiveWorkspace(): Workspace ContentStreamId::create() ) ); - $liveWorkspace = $this->contentRepository->getWorkspaceFinder()->findOneByName($liveWorkspaceName); + $liveWorkspace = $this->contentRepository->findWorkspaceByName($liveWorkspaceName); if (!$liveWorkspace) { throw new \Exception('Live workspace creation failed', 1699002435); } diff --git a/Neos.ContentRepository.Core/Classes/Service/WorkspaceMaintenanceService.php b/Neos.ContentRepository.Core/Classes/Service/WorkspaceMaintenanceService.php index 053d0dc3565..521af3a1a40 100644 --- a/Neos.ContentRepository.Core/Classes/Service/WorkspaceMaintenanceService.php +++ b/Neos.ContentRepository.Core/Classes/Service/WorkspaceMaintenanceService.php @@ -10,6 +10,8 @@ use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Command\RebaseWorkspace; use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Dto\RebaseErrorHandlingStrategy; use Neos\ContentRepository\Core\Projection\Workspace\Workspace; +use Neos\ContentRepository\Core\Projection\Workspace\Workspaces; +use Neos\ContentRepository\Core\Projection\Workspace\WorkspaceStatus; use Neos\EventStore\EventStoreInterface; /** @@ -24,17 +26,18 @@ public function __construct( } /** - * @return array the workspaces of the removed content streams - * @throws \Doctrine\DBAL\Driver\Exception - * @throws \Doctrine\DBAL\Exception - * @throws \Neos\ContentRepository\Core\Feature\WorkspaceCreation\Exception\BaseWorkspaceDoesNotExist - * @throws \Neos\ContentRepository\Core\SharedModel\Exception\WorkspaceDoesNotExist + * @return Workspaces the workspaces of the removed content streams */ - public function rebaseOutdatedWorkspaces(?RebaseErrorHandlingStrategy $strategy = null): array + public function rebaseOutdatedWorkspaces(?RebaseErrorHandlingStrategy $strategy = null): Workspaces { - $outdatedWorkspaces = $this->contentRepository->getWorkspaceFinder()->findOutdated(); - + $outdatedWorkspaces = $this->contentRepository->getWorkspaces()->filter( + fn (Workspace $workspace) => $workspace->status === WorkspaceStatus::OUTDATED + ); + /** @var Workspace $workspace */ foreach ($outdatedWorkspaces as $workspace) { + if ($workspace->status !== WorkspaceStatus::OUTDATED) { + continue; + } $rebaseCommand = RebaseWorkspace::create( $workspace->workspaceName, ); @@ -49,9 +52,7 @@ public function rebaseOutdatedWorkspaces(?RebaseErrorHandlingStrategy $strategy public function pruneAll(): void { - $workspaces = $this->contentRepository->getWorkspaceFinder()->findAll(); - - foreach ($workspaces as $workspace) { + foreach ($this->contentRepository->getWorkspaces() as $workspace) { $streamName = WorkspaceEventStreamName::fromWorkspaceName($workspace->workspaceName)->getEventStreamName(); $this->eventStore->deleteStream($streamName); } diff --git a/Neos.ContentRepository.Export/Tests/Behavior/Features/Bootstrap/CrImportExportTrait.php b/Neos.ContentRepository.Export/Tests/Behavior/Features/Bootstrap/CrImportExportTrait.php index 2b1ce7fd096..16b8155fe8f 100644 --- a/Neos.ContentRepository.Export/Tests/Behavior/Features/Bootstrap/CrImportExportTrait.php +++ b/Neos.ContentRepository.Export/Tests/Behavior/Features/Bootstrap/CrImportExportTrait.php @@ -21,6 +21,7 @@ use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceFactoryDependencies; use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceFactoryInterface; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepository\Export\Event\ValueObject\ExportedEvents; use Neos\ContentRepository\Export\ProcessorResult; use Neos\ContentRepository\Export\Processors\EventExportProcessor; @@ -64,7 +65,7 @@ public function __construct(private readonly Filesystem $filesystem) public function build(ContentRepositoryServiceFactoryDependencies $serviceFactoryDependencies): EventExportProcessor { return new EventExportProcessor( $this->filesystem, - $serviceFactoryDependencies->contentRepository->getWorkspaceFinder(), + $serviceFactoryDependencies->contentRepository->findWorkspaceByName(WorkspaceName::forLive())->currentContentStreamId, $serviceFactoryDependencies->eventStore ); } diff --git a/Neos.ContentRepository.Export/src/ExportService.php b/Neos.ContentRepository.Export/src/ExportService.php index 00a45bcbb16..51707a57a93 100644 --- a/Neos.ContentRepository.Export/src/ExportService.php +++ b/Neos.ContentRepository.Export/src/ExportService.php @@ -5,7 +5,7 @@ use League\Flysystem\Filesystem; use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceInterface; -use Neos\ContentRepository\Core\Projection\Workspace\WorkspaceFinder; +use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Export\Processors\AssetExportProcessor; use Neos\ContentRepository\Export\Processors\EventExportProcessor; use Neos\EventStore\EventStoreInterface; @@ -20,7 +20,7 @@ class ExportService implements ContentRepositoryServiceInterface public function __construct( private readonly Filesystem $filesystem, - private readonly WorkspaceFinder $workspaceFinder, + private readonly ContentStreamId $targetContentStreamId, private readonly AssetRepository $assetRepository, private readonly AssetUsageFinder $assetUsageFinder, private readonly EventStoreInterface $eventStore, @@ -33,13 +33,13 @@ public function runAllProcessors(\Closure $outputLineFn, bool $verbose = false): $processors = [ 'Exporting events' => new EventExportProcessor( $this->filesystem, - $this->workspaceFinder, + $this->targetContentStreamId, $this->eventStore ), 'Exporting assets' => new AssetExportProcessor( $this->filesystem, $this->assetRepository, - $this->workspaceFinder, + $this->targetContentStreamId, $this->assetUsageFinder ) ]; diff --git a/Neos.ContentRepository.Export/src/ExportServiceFactory.php b/Neos.ContentRepository.Export/src/ExportServiceFactory.php index baa013bca98..4e2dadd59a5 100644 --- a/Neos.ContentRepository.Export/src/ExportServiceFactory.php +++ b/Neos.ContentRepository.Export/src/ExportServiceFactory.php @@ -6,7 +6,8 @@ use League\Flysystem\Filesystem; use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceFactoryDependencies; use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceFactoryInterface; -use Neos\ContentRepository\Core\Projection\Workspace\WorkspaceFinder; +use Neos\ContentRepository\Core\Projection\Workspace\Workspace; +use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\Media\Domain\Repository\AssetRepository; use Neos\Neos\AssetUsage\Projection\AssetUsageFinder; @@ -19,7 +20,7 @@ class ExportServiceFactory implements ContentRepositoryServiceFactoryInterface public function __construct( private readonly Filesystem $filesystem, - private readonly WorkspaceFinder $workspaceFinder, + private readonly ContentStreamId $targetContentStreamId, private readonly AssetRepository $assetRepository, private readonly AssetUsageFinder $assetUsageFinder, ) { @@ -29,7 +30,7 @@ public function build(ContentRepositoryServiceFactoryDependencies $serviceFactor { return new ExportService( $this->filesystem, - $this->workspaceFinder, + $this->targetContentStreamId, $this->assetRepository, $this->assetUsageFinder, $serviceFactoryDependencies->eventStore, diff --git a/Neos.ContentRepository.Export/src/Processors/AssetExportProcessor.php b/Neos.ContentRepository.Export/src/Processors/AssetExportProcessor.php index db7679a18b9..8373616c6d7 100644 --- a/Neos.ContentRepository.Export/src/Processors/AssetExportProcessor.php +++ b/Neos.ContentRepository.Export/src/Processors/AssetExportProcessor.php @@ -3,8 +3,7 @@ namespace Neos\ContentRepository\Export\Processors; use League\Flysystem\Filesystem; -use Neos\ContentRepository\Core\Projection\Workspace\WorkspaceFinder; -use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; +use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Export\Asset\ValueObject\SerializedAsset; use Neos\ContentRepository\Export\Asset\ValueObject\SerializedImageVariant; use Neos\ContentRepository\Export\ProcessorInterface; @@ -31,7 +30,7 @@ final class AssetExportProcessor implements ProcessorInterface public function __construct( private readonly Filesystem $files, private readonly AssetRepository $assetRepository, - private readonly WorkspaceFinder $workspaceFinder, + private readonly ContentStreamId $targetContentStreamId, private readonly AssetUsageFinder $assetUsageFinder, ) {} @@ -43,11 +42,7 @@ public function onMessage(\Closure $callback): void public function run(): ProcessorResult { - $liveWorkspace = $this->workspaceFinder->findOneByName(WorkspaceName::forLive()); - if ($liveWorkspace === null) { - return ProcessorResult::error('Failed to find live workspace'); - } - $assetFilter = AssetUsageFilter::create()->withContentStream($liveWorkspace->currentContentStreamId)->groupByAsset(); + $assetFilter = AssetUsageFilter::create()->withContentStream($this->targetContentStreamId)->groupByAsset(); $numberOfExportedAssets = 0; $numberOfExportedImageVariants = 0; diff --git a/Neos.ContentRepository.Export/src/Processors/EventExportProcessor.php b/Neos.ContentRepository.Export/src/Processors/EventExportProcessor.php index 5bd6b142dec..d12fc5a1d08 100644 --- a/Neos.ContentRepository.Export/src/Processors/EventExportProcessor.php +++ b/Neos.ContentRepository.Export/src/Processors/EventExportProcessor.php @@ -6,8 +6,7 @@ use League\Flysystem\FilesystemException; use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceInterface; use Neos\ContentRepository\Core\Feature\ContentStreamEventStreamName; -use Neos\ContentRepository\Core\Projection\Workspace\WorkspaceFinder; -use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; +use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Export\Event\ValueObject\ExportedEvent; use Neos\ContentRepository\Export\ProcessorInterface; use Neos\ContentRepository\Export\ProcessorResult; @@ -24,7 +23,7 @@ final class EventExportProcessor implements ProcessorInterface, ContentRepositor public function __construct( private readonly Filesystem $files, - private readonly WorkspaceFinder $workspaceFinder, + private readonly ContentStreamId $targetContentStreamId, private readonly EventStoreInterface $eventStore, ) { } @@ -36,11 +35,7 @@ public function onMessage(\Closure $callback): void public function run(): ProcessorResult { - $liveWorkspace = $this->workspaceFinder->findOneByName(WorkspaceName::forLive()); - if ($liveWorkspace === null) { - return ProcessorResult::error('Failed to find live workspace'); - } - $streamName = ContentStreamEventStreamName::fromContentStreamId($liveWorkspace->currentContentStreamId)->getEventStreamName(); + $streamName = ContentStreamEventStreamName::fromContentStreamId($this->targetContentStreamId)->getEventStreamName(); $eventStream = $this->eventStore->load($streamName); $eventFileResource = fopen('php://temp/maxmemory:5242880', 'rb+'); diff --git a/Neos.ContentRepository.NodeMigration/src/NodeMigrationService.php b/Neos.ContentRepository.NodeMigration/src/NodeMigrationService.php index ba7279ce0c2..69ba9a5bf7c 100644 --- a/Neos.ContentRepository.NodeMigration/src/NodeMigrationService.php +++ b/Neos.ContentRepository.NodeMigration/src/NodeMigrationService.php @@ -61,7 +61,7 @@ public function __construct( public function executeMigration(ExecuteMigration $command): void { - $sourceWorkspace = $this->contentRepository->getWorkspaceFinder()->findOneByName($command->sourceWorkspaceName); + $sourceWorkspace = $this->contentRepository->findWorkspaceByName($command->sourceWorkspaceName); if ($sourceWorkspace === null) { throw new WorkspaceDoesNotExist(sprintf( 'The workspace %s does not exist', diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteTrait.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteTrait.php index 1dbe5f71716..06a5fd3fd13 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteTrait.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteTrait.php @@ -133,6 +133,9 @@ protected function readPayloadTable(TableNode $payloadTable): array */ public function iExpectTheContentStreamToNotExist(string $rawContentStreamId): void { + // todo use, but also it should be assertFAlse?!!! + // $this->contentRepository->getContentStreams() + // ->find(fn (ContentStream $contentStream) => $contentStream->id->equals(ContentStreamId::fromString($rawContentStreamId))), Assert::assertTrue( $this->currentContentRepository->getContentStreamFinder()->hasContentStream(ContentStreamId::fromString($rawContentStreamId)), sprintf('The content stream "%s" does exist.', $rawContentStreamId) @@ -144,9 +147,9 @@ public function iExpectTheContentStreamToNotExist(string $rawContentStreamId): v */ public function workspaceHasStatus(string $rawWorkspaceName, string $status): void { - $workspace = $this->currentContentRepository->getWorkspaceFinder()->findOneByName(WorkspaceName::fromString($rawWorkspaceName)); + $workspace = $this->currentContentRepository->findWorkspaceByName(WorkspaceName::fromString($rawWorkspaceName)); - Assert::assertSame($status, $workspace->status->value); + Assert::assertSame($status, $workspace?->status->value); } /** @@ -245,8 +248,7 @@ public function theCurrentContentStreamHasState(string $expectedState): void { $this->theContentStreamHasState( $this->currentContentRepository - ->getWorkspaceFinder() - ->findOneByName($this->currentWorkspaceName) + ->findWorkspaceByName($this->currentWorkspaceName) ->currentContentStreamId->value, $expectedState ); diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/ProjectedNodeTrait.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/ProjectedNodeTrait.php index fcf91a05526..017327f22ed 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/ProjectedNodeTrait.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/ProjectedNodeTrait.php @@ -80,6 +80,7 @@ public function iGetTheNodeAtPath(string $serializedNodePath): void public function iExpectANodeIdentifiedByXToExistInTheContentGraph(string $serializedNodeDiscriminator): void { $nodeDiscriminator = NodeDiscriminator::fromShorthand($serializedNodeDiscriminator); + // TODO Fix $workspaceName = $this->currentContentRepository->getWorkspaceFinder()->findOneByCurrentContentStreamId( $nodeDiscriminator->contentStreamId )->workspaceName; diff --git a/Neos.Media.Browser/Classes/Controller/UsageController.php b/Neos.Media.Browser/Classes/Controller/UsageController.php index 17baf481e21..c0fe9f11ae3 100644 --- a/Neos.Media.Browser/Classes/Controller/UsageController.php +++ b/Neos.Media.Browser/Classes/Controller/UsageController.php @@ -14,6 +14,7 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; +use Neos\ContentRepository\Core\Projection\Workspace\Workspace; use Neos\ContentRepository\Core\SharedModel\Exception\NodeTypeNotFound; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; @@ -106,7 +107,9 @@ public function relatedNodesAction(AssetInterface $asset) $contentRepository = $this->contentRepositoryRegistry->get($usage->getContentRepositoryId()); - $workspace = $contentRepository->getWorkspaceFinder()->findOneByCurrentContentStreamId($usage->getContentStreamId()); + $workspace = $contentRepository->getWorkspaces()->find( + fn (Workspace $potentialWorkspace) => $potentialWorkspace->currentContentStreamId->equals($usage->getContentStreamId()) + ); // FIXME: AssetUsageReference->workspaceName ? $nodeAggregate = $contentRepository->getContentGraph($workspace->workspaceName)->findNodeAggregateById( diff --git a/Neos.Neos/Classes/AssetUsage/Service/AssetUsageSyncService.php b/Neos.Neos/Classes/AssetUsage/Service/AssetUsageSyncService.php index f73bf9865d5..cb4c17337ef 100644 --- a/Neos.Neos/Classes/AssetUsage/Service/AssetUsageSyncService.php +++ b/Neos.Neos/Classes/AssetUsage/Service/AssetUsageSyncService.php @@ -7,6 +7,7 @@ use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceInterface; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; +use Neos\ContentRepository\Core\Projection\Workspace\Workspace; use Neos\Media\Domain\Model\AssetInterface; use Neos\Media\Domain\Repository\AssetRepository; use Neos\Neos\AssetUsage\Dto\AssetUsage; @@ -56,7 +57,9 @@ public function isAssetUsageStillValid(AssetUsage $usage): bool $dimensionSpacePoint = $usage->originDimensionSpacePoint->toDimensionSpacePoint(); // FIXME: AssetUsage->workspaceName ? - $workspace = $this->contentRepository->getWorkspaceFinder()->findOneByCurrentContentStreamId($usage->contentStreamId); + $workspace = $this->contentRepository->getWorkspaces()->find( + fn (Workspace $potentialWorkspace) => $potentialWorkspace->currentContentStreamId->equals($usage->contentStreamId) + ); if (is_null($workspace)) { return false; } diff --git a/Neos.Neos/Classes/Command/CrCommandController.php b/Neos.Neos/Classes/Command/CrCommandController.php index af2719e83e4..af42afec9af 100644 --- a/Neos.Neos/Classes/Command/CrCommandController.php +++ b/Neos.Neos/Classes/Command/CrCommandController.php @@ -9,6 +9,7 @@ use Neos\ContentRepository\Core\Projection\CatchUpOptions; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepository\Export\ExportService; use Neos\ContentRepository\Export\ExportServiceFactory; use Neos\ContentRepository\Export\ImportService; @@ -54,18 +55,22 @@ public function __construct( public function exportCommand(string $path, string $contentRepository = 'default', bool $verbose = false): void { $contentRepositoryId = ContentRepositoryId::fromString($contentRepository); - $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); + $contentRepositoryInstance = $this->contentRepositoryRegistry->get($contentRepositoryId); Files::createDirectoryRecursively($path); $filesystem = new Filesystem(new LocalFilesystemAdapter($path)); + $liveWorkspace = $contentRepositoryInstance->findWorkspaceByName(WorkspaceName::forLive()); + if ($liveWorkspace === null) { + throw new \RuntimeException('Failed to find live workspace', 1716652280); + } $exportService = $this->contentRepositoryRegistry->buildService( $contentRepositoryId, new ExportServiceFactory( $filesystem, - $contentRepository->getWorkspaceFinder(), + $liveWorkspace->currentContentStreamId, $this->assetRepository, - $contentRepository->projectionState(AssetUsageFinder::class), + $contentRepositoryInstance->projectionState(AssetUsageFinder::class), ) ); assert($exportService instanceof ExportService); diff --git a/Neos.Neos/Classes/Command/WorkspaceCommandController.php b/Neos.Neos/Classes/Command/WorkspaceCommandController.php index cc9742a49c5..eab83907d49 100644 --- a/Neos.Neos/Classes/Command/WorkspaceCommandController.php +++ b/Neos.Neos/Classes/Command/WorkspaceCommandController.php @@ -21,6 +21,8 @@ use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Dto\RebaseErrorHandlingStrategy; use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Exception\WorkspaceRebaseFailed; use Neos\ContentRepository\Core\Projection\Workspace\Workspace; +use Neos\ContentRepository\Core\Projection\Workspace\Workspaces; +use Neos\ContentRepository\Core\Projection\Workspace\WorkspaceStatus; use Neos\ContentRepository\Core\Service\WorkspaceMaintenanceServiceFactory; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; use Neos\ContentRepository\Core\SharedModel\Exception\WorkspaceDoesNotExist; @@ -249,7 +251,7 @@ public function deleteCommand(string $workspace, bool $force = false, string $co $this->quit(2); } - $crWorkspace = $contentRepositoryInstance->getWorkspaceFinder()->findOneByName($workspaceName); + $crWorkspace = $contentRepositoryInstance->findWorkspaceByName($workspaceName); if ($crWorkspace === null) { $this->outputLine('Workspace "%s" does not exist', [$workspaceName->value]); $this->quit(1); @@ -265,8 +267,10 @@ public function deleteCommand(string $workspace, bool $force = false, string $co $this->quit(2); } - $dependentWorkspaces = $contentRepositoryInstance->getWorkspaceFinder()->findByBaseWorkspace($workspaceName); - if (count($dependentWorkspaces) > 0) { + $dependentWorkspaces = $contentRepository->getWorkspaces()->filter( + static fn (Workspace $potentiallyDependentWorkspace) => $potentiallyDependentWorkspace->baseWorkspaceName?->equals($workspaceName) ?? false + ); + if (!$dependentWorkspaces->isEmpty()) { $this->outputLine( 'Workspace "%s" cannot be deleted because the following workspaces are based on it:', [$workspaceName->value] @@ -333,12 +337,12 @@ public function rebaseOutdatedCommand(string $contentRepository = 'default', boo $force ? RebaseErrorHandlingStrategy::STRATEGY_FORCE : RebaseErrorHandlingStrategy::STRATEGY_FAIL ); - if (!count($outdatedWorkspaces)) { + if ($outdatedWorkspaces->isEmpty()) { $this->outputLine('There are no outdated workspaces.'); - } else { - foreach ($outdatedWorkspaces as $outdatedWorkspace) { - $this->outputFormatted('Rebased workspace %s', [$outdatedWorkspace->workspaceName->value]); - } + return; + } + foreach ($outdatedWorkspaces as $outdatedWorkspace) { + $this->outputFormatted('Rebased workspace %s', [$outdatedWorkspace->workspaceName->value]); } } @@ -353,9 +357,9 @@ public function listCommand(string $contentRepository = 'default'): void $contentRepositoryId = ContentRepositoryId::fromString($contentRepository); $contentRepositoryInstance = $this->contentRepositoryRegistry->get($contentRepositoryId); - $workspaces = $contentRepositoryInstance->getWorkspaceFinder()->findAll(); + $workspaces = $this->contentRepositoryRegistry->get($contentRepositoryId)->getWorkspaces(); - if (count($workspaces) === 0) { + if ($workspaces->isEmpty()) { $this->outputLine('No workspaces found.'); $this->quit(0); } diff --git a/Neos.Neos/Classes/Controller/Module/Administration/SitesController.php b/Neos.Neos/Classes/Controller/Module/Administration/SitesController.php index 3fe98412645..5afd08ec56e 100755 --- a/Neos.Neos/Classes/Controller/Module/Administration/SitesController.php +++ b/Neos.Neos/Classes/Controller/Module/Administration/SitesController.php @@ -176,7 +176,7 @@ public function updateSiteAction(Site $site, $newSiteNodeName) if ($site->getNodeName()->value !== $newSiteNodeName) { $contentRepository = $this->contentRepositoryRegistry->get($site->getConfiguration()->contentRepositoryId); - $liveWorkspace = $contentRepository->getWorkspaceFinder()->findOneByName(WorkspaceName::forLive()); + $liveWorkspace = $contentRepository->findWorkspaceByName(WorkspaceName::forLive()); if (!$liveWorkspace instanceof Workspace) { throw new \InvalidArgumentException( 'Cannot update a site without the live workspace being present.', @@ -202,7 +202,7 @@ public function updateSiteAction(Site $site, $newSiteNodeName) ); } - foreach ($contentRepository->getWorkspaceFinder()->findAll() as $workspace) { + foreach ($contentRepository->getWorkspaces() as $workspace) { $siteNodeAggregate = $contentRepository->getContentGraph($workspace->workspaceName)->findChildNodeAggregateByName( $sitesNode->nodeAggregateId, $site->getNodeName()->toNodeName() diff --git a/Neos.Neos/Classes/Domain/Service/SiteServiceInternals.php b/Neos.Neos/Classes/Domain/Service/SiteServiceInternals.php index 3337686ebeb..9ab73ee61fd 100644 --- a/Neos.Neos/Classes/Domain/Service/SiteServiceInternals.php +++ b/Neos.Neos/Classes/Domain/Service/SiteServiceInternals.php @@ -55,7 +55,7 @@ public function removeSiteNode(SiteNodeName $siteNodeName): void ); } - foreach ($this->contentRepository->getWorkspaceFinder()->findAll() as $workspace) { + foreach ($this->contentRepository->getWorkspaces() as $workspace) { $contentGraph = $this->contentRepository->getContentGraph($workspace->workspaceName); $sitesNodeAggregate = $contentGraph->findRootNodeAggregateByType( NodeTypeNameFactory::forSites() diff --git a/Neos.Neos/Classes/Fusion/Helper/CachingHelper.php b/Neos.Neos/Classes/Fusion/Helper/CachingHelper.php index f921df9b4ef..c1a9f11c6ec 100644 --- a/Neos.Neos/Classes/Fusion/Helper/CachingHelper.php +++ b/Neos.Neos/Classes/Fusion/Helper/CachingHelper.php @@ -176,7 +176,7 @@ public function getWorkspaceChain(?Node $node): array $node->contentRepositoryId ); - $currentWorkspace = $contentRepository->getWorkspaceFinder()->findOneByName( + $currentWorkspace = $contentRepository->findWorkspaceByName( $node->workspaceName ); $workspaceChain = []; @@ -184,7 +184,7 @@ public function getWorkspaceChain(?Node $node): array while ($currentWorkspace !== null) { $workspaceChain[$currentWorkspace->workspaceName->value] = $currentWorkspace; $currentWorkspace = $currentWorkspace->baseWorkspaceName - ? $contentRepository->getWorkspaceFinder()->findOneByName($currentWorkspace->baseWorkspaceName) + ? $contentRepository->findWorkspaceByName($currentWorkspace->baseWorkspaceName) : null; } diff --git a/Neos.Neos/Classes/Service/LinkingService.php b/Neos.Neos/Classes/Service/LinkingService.php index 6354c69b937..f112a02e641 100644 --- a/Neos.Neos/Classes/Service/LinkingService.php +++ b/Neos.Neos/Classes/Service/LinkingService.php @@ -309,7 +309,7 @@ public function createNodeUri( )->contentRepositoryId; $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); $nodeAddress = NodeAddress::fromJsonString($nodeString); - $workspace = $contentRepository->getWorkspaceFinder()->findOneByName($nodeAddress->workspaceName); + $workspace = $contentRepository->findWorkspaceByName($nodeAddress->workspaceName); $subgraph = $contentRepository->getContentGraph($nodeAddress->workspaceName)->getSubgraph( $nodeAddress->dimensionSpacePoint, $workspace && !$workspace->isPublicWorkspace() @@ -348,7 +348,7 @@ public function createNodeUri( $contentRepository = $this->contentRepositoryRegistry->get( $node->contentRepositoryId ); - $workspace = $contentRepository->getWorkspaceFinder()->findOneByName( + $workspace = $contentRepository->findWorkspaceByName( $node->workspaceName ); $mainRequest = $controllerContext->getRequest()->getMainRequest(); diff --git a/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php b/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php index f07732d5d96..160d1dbadd1 100644 --- a/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php +++ b/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php @@ -17,9 +17,7 @@ use Doctrine\DBAL\Exception as DBALException; use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Exception\WorkspaceAlreadyExists; -use Neos\ContentRepository\Core\Feature\WorkspaceModification\Command\ChangeWorkspaceOwner; use Neos\ContentRepository\Core\Feature\WorkspaceModification\Command\DeleteWorkspace; -use Neos\ContentRepository\Core\Feature\WorkspaceModification\Command\RenameWorkspace; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Command\DiscardIndividualNodesFromWorkspace; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Command\PublishIndividualNodesFromWorkspace; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Dto\NodeIdsToPublishOrDiscard; @@ -165,7 +163,7 @@ public function showAction(WorkspaceName $workspace): void $contentRepositoryId = SiteDetectionResult::fromRequest($this->request->getHttpRequest())->contentRepositoryId; $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); - $workspaceObj = $contentRepository->getWorkspaceFinder()->findOneByName($workspace); + $workspaceObj = $contentRepository->findWorkspaceByName($workspace); if (is_null($workspaceObj)) { /** @todo add flash message */ $this->redirect('index'); @@ -238,7 +236,7 @@ public function editAction(WorkspaceName $workspaceName): void ->contentRepositoryId; $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); - $workspace = $contentRepository->getWorkspaceFinder()->findOneByName($workspaceName); + $workspace = $contentRepository->findWorkspaceByName($workspaceName); if (is_null($workspace)) { $this->addFlashMessage('Failed to find workspace "%s"', 'Error', Message::SEVERITY_ERROR, [$workspaceName->value]); $this->redirect('index'); @@ -275,7 +273,7 @@ public function updateAction( $title = WorkspaceTitle::fromString($workspaceName->value); } - $workspace = $contentRepository->getWorkspaceFinder()->findOneByName($workspaceName); + $workspace = $contentRepository->findWorkspaceByName($workspaceName); if ($workspace === null) { $this->addFlashMessage( $this->getModuleLabel('workspaces.workspaceDoesNotExist'), @@ -315,7 +313,7 @@ public function deleteAction(WorkspaceName $workspaceName): void $contentRepositoryId = SiteDetectionResult::fromRequest($this->request->getHttpRequest())->contentRepositoryId; $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); - $workspace = $contentRepository->getWorkspaceFinder()->findOneByName($workspaceName); + $workspace = $contentRepository->findWorkspaceByName($workspaceName); if ($workspace === null) { $this->addFlashMessage( $this->getModuleLabel('workspaces.workspaceDoesNotExist'), @@ -331,9 +329,12 @@ public function deleteAction(WorkspaceName $workspaceName): void $this->redirect('index'); } - $dependentWorkspaces = $contentRepository->getWorkspaceFinder()->findByBaseWorkspace($workspace->workspaceName); - if (count($dependentWorkspaces) > 0) { + $dependentWorkspaces = $contentRepository->getWorkspaces()->filter( + static fn (Workspace $potentiallyDependentWorkspace) => $potentiallyDependentWorkspace->baseWorkspaceName?->equals($workspaceName) ?? false + ); + if (!$dependentWorkspaces->isEmpty()) { $dependentWorkspaceTitles = []; + /** @var Workspace $dependentWorkspace */ foreach ($dependentWorkspaces as $dependentWorkspace) { $dependentWorkspaceMetadata = $this->workspaceService->getWorkspaceMetadata($contentRepositoryId, $dependentWorkspace->workspaceName); $dependentWorkspaceTitles[] = $dependentWorkspaceMetadata->title->value; @@ -832,8 +833,8 @@ protected function renderContentChanges( ContentStreamId $contentStreamIdOfOriginalNode, ContentRepository $contentRepository, ): array { - $currentWorkspace = $contentRepository->getWorkspaceFinder()->findOneByCurrentContentStreamId( - $contentStreamIdOfOriginalNode + $currentWorkspace = $contentRepository->getWorkspaces()->find( + fn (Workspace $potentialWorkspace) => $potentialWorkspace->currentContentStreamId->equals($contentStreamIdOfOriginalNode) ); $originalNode = null; if ($currentWorkspace !== null) { @@ -1016,7 +1017,7 @@ protected function prepareBaseWorkspaceOptions( ): array { $user = $this->userService->getCurrentUser(); $baseWorkspaceOptions = []; - $workspaces = $contentRepository->getWorkspaceFinder()->findAll(); + $workspaces = $contentRepository->getWorkspaces(); foreach ($workspaces as $workspace) { if ($excludedWorkspace !== null) { if ($workspace->workspaceName->equals($excludedWorkspace)) { @@ -1066,7 +1067,7 @@ private function getBaseWorkspaceWhenSureItExists( /** @var WorkspaceName $baseWorkspaceName We expect this to exist */ $baseWorkspaceName = $workspace->baseWorkspaceName; /** @var Workspace $baseWorkspace We expect this to exist */ - $baseWorkspace = $contentRepository->getWorkspaceFinder()->findOneByName($baseWorkspaceName); + $baseWorkspace = $contentRepository->findWorkspaceByName($baseWorkspaceName); return $baseWorkspace; }