Skip to content

Commit

Permalink
Merge pull request #4943 from neos/publishingBonanza
Browse files Browse the repository at this point in the history
Highlevel Workspace API
  • Loading branch information
nezaniel committed Apr 5, 2024
2 parents f8966a9 + cbb8b54 commit f1e7d73
Show file tree
Hide file tree
Showing 8 changed files with 749 additions and 57 deletions.
69 changes: 34 additions & 35 deletions Neos.Neos/Classes/Command/WorkspaceCommandController.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@
use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Exception\BaseWorkspaceDoesNotExist;
use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Exception\WorkspaceAlreadyExists;
use Neos\ContentRepository\Core\Feature\WorkspaceModification\Command\DeleteWorkspace;
use Neos\ContentRepository\Core\Feature\WorkspacePublication\Command\DiscardWorkspace;
use Neos\ContentRepository\Core\Feature\WorkspacePublication\Command\PublishWorkspace;
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\WorkspaceStatus;
Expand All @@ -39,6 +36,7 @@
use Neos\Flow\Cli\Exception\StopCommandException;
use Neos\Flow\Persistence\PersistenceManagerInterface;
use Neos\Neos\Domain\Service\UserService;
use Neos\Neos\Domain\Workspace\WorkspaceProvider;
use Neos\Neos\PendingChangesProjection\ChangeFinder;

/**
Expand All @@ -56,6 +54,9 @@ class WorkspaceCommandController extends CommandController
#[Flow\Inject]
protected ContentRepositoryRegistry $contentRepositoryRegistry;

#[Flow\Inject]
protected WorkspaceProvider $workspaceProvider;

/**
* Publish changes of a workspace
*
Expand All @@ -66,16 +67,16 @@ class WorkspaceCommandController extends CommandController
*/
public function publishCommand(string $workspace, string $contentRepositoryIdentifier = 'default'): void
{
$contentRepositoryId = ContentRepositoryId::fromString($contentRepositoryIdentifier);
$contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId);

$contentRepository->handle(PublishWorkspace::create(
WorkspaceName::fromString($workspace),
))->block();
// @todo: bypass access control
$workspace = $this->workspaceProvider->provideForWorkspaceName(
ContentRepositoryId::fromString($contentRepositoryIdentifier),
WorkspaceName::fromString($workspace)
);
$workspace->publishAllChanges();

$this->outputLine(
'Published all nodes in workspace %s to its base workspace',
[$workspace]
[$workspace->name->value]
);
}

Expand All @@ -90,20 +91,19 @@ public function publishCommand(string $workspace, string $contentRepositoryIdent
*/
public function discardCommand(string $workspace, string $contentRepositoryIdentifier = 'default'): void
{
$contentRepositoryId = ContentRepositoryId::fromString($contentRepositoryIdentifier);
$contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId);
// @todo: bypass access control
$workspace = $this->workspaceProvider->provideForWorkspaceName(
ContentRepositoryId::fromString($contentRepositoryIdentifier),
WorkspaceName::fromString($workspace)
);

try {
$contentRepository->handle(
DiscardWorkspace::create(
WorkspaceName::fromString($workspace),
)
)->block();
$workspace->discardAllChanges();
} catch (WorkspaceDoesNotExist $exception) {
$this->outputLine('Workspace "%s" does not exist', [$workspace]);
$this->outputLine('Workspace "%s" does not exist', [$workspace->name->value]);
$this->quit(1);
}
$this->outputLine('Discarded all nodes in workspace %s', [$workspace]);
$this->outputLine('Discarded all nodes in workspace %s', [$workspace->name->value]);
}

/**
Expand All @@ -118,29 +118,25 @@ public function discardCommand(string $workspace, string $contentRepositoryIdent
*/
public function rebaseCommand(string $workspace, string $contentRepositoryIdentifier = 'default', bool $force = false): void
{
$contentRepositoryId = ContentRepositoryId::fromString($contentRepositoryIdentifier);
$contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId);
// @todo: bypass access control
$workspace = $this->workspaceProvider->provideForWorkspaceName(
ContentRepositoryId::fromString($contentRepositoryIdentifier),
WorkspaceName::fromString($workspace)
);

try {
$rebaseCommand = RebaseWorkspace::create(
WorkspaceName::fromString($workspace),
);
if ($force) {
$rebaseCommand = $rebaseCommand->withErrorHandlingStrategy(RebaseErrorHandlingStrategy::STRATEGY_FORCE);
}
$contentRepository->handle($rebaseCommand)->block();
$workspace->rebase($force ? RebaseErrorHandlingStrategy::STRATEGY_FORCE : RebaseErrorHandlingStrategy::STRATEGY_FAIL);
} catch (WorkspaceDoesNotExist $exception) {
$this->outputLine('Workspace "%s" does not exist', [$workspace]);
$this->outputLine('Workspace "%s" does not exist', [$workspace->name->value]);
$this->quit(1);
}

$workspaceObject = $contentRepository->getWorkspaceFinder()->findOneByName(WorkspaceName::fromString($workspace));
if ($workspaceObject && $workspaceObject->status === WorkspaceStatus::OUTDATED_CONFLICT) {
if ($workspace->getCurrentStatus() === WorkspaceStatus::OUTDATED_CONFLICT) {
$this->outputLine('Rebasing of workspace %s is not possible due to conflicts. You can try the --force option.', [$workspace]);
$this->quit(1);
}

$this->outputLine('Rebased workspace %s', [$workspace]);
$this->outputLine('Rebased workspace %s', [$workspace->name->value]);
}

/**
Expand Down Expand Up @@ -303,9 +299,12 @@ public function deleteCommand(string $workspace, bool $force = false, string $co
);
$this->quit(5);
}
$contentRepository->handle(
DiscardWorkspace::create($workspaceName)
)->block();
// @todo bypass access control?
$workspace = $this->workspaceProvider->provideForWorkspaceName(
$contentRepositoryId,
$workspaceName
);
$workspace->discardAllChanges();
}

$contentRepository->handle(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,14 @@
namespace Neos\Neos\Controller\Module\Management;

use Doctrine\DBAL\DBALException;
use JsonException;
use Neos\ContentRepository\Core\ContentRepository;
use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Command\CreateWorkspace;
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\DiscardWorkspace;
use Neos\ContentRepository\Core\Feature\WorkspacePublication\Command\PublishIndividualNodesFromWorkspace;
use Neos\ContentRepository\Core\Feature\WorkspacePublication\Command\PublishWorkspace;
use Neos\ContentRepository\Core\Feature\WorkspacePublication\Dto\NodeIdsToPublishOrDiscard;
use Neos\ContentRepository\Core\Feature\WorkspacePublication\Dto\NodeIdToPublishOrDiscard;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindAncestorNodesFilter;
Expand Down Expand Up @@ -62,6 +59,9 @@
use Neos\Neos\Domain\Service\NodeTypeNameFactory;
use Neos\Neos\Domain\Service\UserService;
use Neos\Neos\Domain\Service\WorkspaceNameBuilder;
use Neos\Neos\Domain\Workspace\DiscardAllChanges;
use Neos\Neos\Domain\Workspace\PublishAllChanges;
use Neos\Neos\Domain\Workspace\WorkspaceProvider;
use Neos\Neos\FrontendRouting\NodeAddress;
use Neos\Neos\FrontendRouting\NodeAddressFactory;
use Neos\Neos\FrontendRouting\SiteDetection\SiteDetectionResult;
Expand Down Expand Up @@ -96,6 +96,9 @@ class WorkspacesController extends AbstractModuleController
#[Flow\Inject]
protected PackageManager $packageManager;

#[Flow\Inject]
protected WorkspaceProvider $workspaceProvider;

/**
* Display a list of unpublished content
*
Expand Down Expand Up @@ -648,20 +651,23 @@ public function publishWorkspaceAction(WorkspaceName $workspace): void
{
$contentRepositoryId = SiteDetectionResult::fromRequest($this->request->getHttpRequest())
->contentRepositoryId;
$contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId);
$contentRepository->handle(
PublishWorkspace::create(
$workspace
)
)->block();
$workspace = $contentRepository->getWorkspaceFinder()->findOneByName($workspace);
/** @var Workspace $workspace Otherwise the command handler would have thrown an exception */
/** @todo send from UI */
$command = new PublishAllChanges(
$contentRepositoryId,
$workspace
);

$workspace = $this->workspaceProvider->provideForWorkspaceName(
$command->contentRepositoryId,
$command->workspaceName
);
$workspace->publishAllChanges();
/** @var WorkspaceName $baseWorkspaceName Otherwise the command handler would have thrown an exception */
$baseWorkspaceName = $workspace->baseWorkspaceName;
$baseWorkspaceName = $workspace->getCurrentBaseWorkspaceName();
$this->addFlashMessage($this->translator->translateById(
'workspaces.allChangesInWorkspaceHaveBeenPublished',
[
htmlspecialchars($workspace->workspaceName->value),
htmlspecialchars($workspace->name->value),
htmlspecialchars($baseWorkspaceName->value)
],
null,
Expand All @@ -681,16 +687,20 @@ public function discardWorkspaceAction(WorkspaceName $workspace): void
{
$contentRepositoryId = SiteDetectionResult::fromRequest($this->request->getHttpRequest())
->contentRepositoryId;
$contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId);
$contentRepository->handle(
DiscardWorkspace::create(
$workspace,
)
)->block();
/** @todo send from UI */
$command = new DiscardAllChanges(
$contentRepositoryId,
$workspace
);
$workspace = $this->workspaceProvider->provideForWorkspaceName(
$command->contentRepositoryId,
$command->workspaceName
);
$workspace->discardAllChanges();

$this->addFlashMessage($this->translator->translateById(
'workspaces.allChangesInWorkspaceHaveBeenDiscarded',
[htmlspecialchars($workspace->value)],
[htmlspecialchars($workspace->name->value)],
null,
null,
'Modules',
Expand All @@ -703,7 +713,7 @@ public function discardWorkspaceAction(WorkspaceName $workspace): void
* Computes the number of added, changed and removed nodes for the given workspace
*
* @return array<string,int>
* @throws JsonException
* @throws \JsonException
*/
protected function computeChangesCount(Workspace $selectedWorkspace, ContentRepository $contentRepository): array
{
Expand All @@ -729,7 +739,7 @@ protected function computeChangesCount(Workspace $selectedWorkspace, ContentRepo
/**
* Builds an array of changes for sites in the given workspace
* @return array<string,mixed>
* @throws JsonException
* @throws \JsonException
*/
protected function computeSiteChanges(Workspace $selectedWorkspace, ContentRepository $contentRepository): array
{
Expand Down
45 changes: 45 additions & 0 deletions Neos.Neos/Classes/Domain/Workspace/DiscardAllChanges.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/*
* This file is part of the Neos.Neos package.
*
* (c) Contributors of the Neos Project - www.neos.io
*
* This package is Open Source Software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/

declare(strict_types=1);

namespace Neos\Neos\Domain\Workspace;

use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId;
use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName;
use Neos\Flow\Annotations as Flow;

/**
* The command DTO to communicate discarding of all changes recorded in a given workspace
*
* @internal for communication within Neos only
*/
#[Flow\Proxy(false)]
final readonly class DiscardAllChanges
{
public function __construct(
public ContentRepositoryId $contentRepositoryId,
public WorkspaceName $workspaceName,
) {
}

/**
* @param array<string,string> $values
*/
public static function fromArray(array $values): self
{
return new self(
ContentRepositoryId::fromString($values['contentRepositoryId']),
WorkspaceName::fromString($values['workspaceName']),
);
}
}
31 changes: 31 additions & 0 deletions Neos.Neos/Classes/Domain/Workspace/DiscardingResult.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

/*
* This file is part of the Neos.Neos package.
*
* (c) Contributors of the Neos Project - www.neos.io
*
* This package is Open Source Software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/

declare(strict_types=1);

namespace Neos\Neos\Domain\Workspace;

use Neos\Flow\Annotations as Flow;

/**
* The discarding result DTO
*
* @internal for communication within Neos only
*/
#[Flow\Proxy(false)]
final readonly class DiscardingResult
{
public function __construct(
public int $numberOfDiscardedChanges,
) {
}
}
45 changes: 45 additions & 0 deletions Neos.Neos/Classes/Domain/Workspace/PublishAllChanges.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/*
* This file is part of the Neos.Neos package.
*
* (c) Contributors of the Neos Project - www.neos.io
*
* This package is Open Source Software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/

declare(strict_types=1);

namespace Neos\Neos\Domain\Workspace;

use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId;
use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName;
use Neos\Flow\Annotations as Flow;

/**
* The command DTO to communicate publication of all changes recorded in a given workspace
*
* @internal for communication within Neos only
*/
#[Flow\Proxy(false)]
final readonly class PublishAllChanges
{
public function __construct(
public ContentRepositoryId $contentRepositoryId,
public WorkspaceName $workspaceName,
) {
}

/**
* @param array<string,string> $values
*/
public static function fromArray(array $values): self
{
return new self(
ContentRepositoryId::fromString($values['contentRepositoryId']),
WorkspaceName::fromString($values['workspaceName']),
);
}
}

0 comments on commit f1e7d73

Please sign in to comment.