Skip to content

Commit

Permalink
TASK: Move logic to create Conflicts from WorkspaceRebaseFailed into …
Browse files Browse the repository at this point in the history
…dedicated Factory
  • Loading branch information
grebaldi committed Apr 29, 2024
1 parent ec9c060 commit e96ce99
Show file tree
Hide file tree
Showing 7 changed files with 301 additions and 283 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use Neos\Neos\Ui\Application\Shared\Conflicts;
use Neos\Neos\Ui\Application\Shared\ConflictsOccurred;
use Neos\Neos\Ui\Application\Shared\PublishSucceeded;
use Neos\Neos\Ui\Infrastructure\ContentRepository\ConflictsFactory;

/**
* The application layer level command handler to perform publication of
Expand Down Expand Up @@ -61,19 +62,15 @@ public function handle(
1682762156
);
} catch (WorkspaceRebaseFailed $e) {
$conflictsBuilder = Conflicts::builder(
$conflictsFactory = new ConflictsFactory(
contentRepository: $this->contentRepositoryRegistry
->get($command->contentRepositoryId),
workspaceName: $command->workspaceName,
preferredDimensionSpacePoint: $command->preferredDimensionSpacePoint
);

foreach ($e->commandsThatFailedDuringRebase as $commandThatFailedDuringRebase) {
$conflictsBuilder->addCommandThatFailedDuringRebase($commandThatFailedDuringRebase);
}

return new ConflictsOccurred(
conflicts: $conflictsBuilder->build()
conflicts: $conflictsFactory->fromWorkspaceRebaseFailed($e)
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry;
use Neos\Flow\Annotations as Flow;
use Neos\Neos\Domain\Workspace\WorkspaceProvider;
use Neos\Neos\Ui\Application\Shared\Conflicts;
use Neos\Neos\Ui\Application\Shared\ConflictsOccurred;
use Neos\Neos\Ui\Application\Shared\PublishSucceeded;
use Neos\Neos\Ui\Infrastructure\ContentRepository\ConflictsFactory;

/**
* The application layer level command handler to perform publication of
Expand Down Expand Up @@ -52,19 +52,15 @@ public function handle(
baseWorkspaceName: $workspace->getCurrentBaseWorkspaceName()?->value
);
} catch (WorkspaceRebaseFailed $e) {
$conflictsBuilder = Conflicts::builder(
$conflictsFactory = new ConflictsFactory(
contentRepository: $this->contentRepositoryRegistry
->get($command->contentRepositoryId),
workspaceName: $command->workspaceName,
preferredDimensionSpacePoint: $command->preferredDimensionSpacePoint
);

foreach ($e->commandsThatFailedDuringRebase as $commandThatFailedDuringRebase) {
$conflictsBuilder->addCommandThatFailedDuringRebase($commandThatFailedDuringRebase);
}

return new ConflictsOccurred(
conflicts: $conflictsBuilder->build()
conflicts: $conflictsFactory->fromWorkspaceRebaseFailed($e)
);
}
}
Expand Down
2 changes: 2 additions & 0 deletions Classes/Application/Shared/Conflict.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

namespace Neos\Neos\Ui\Application\Shared;

use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId;
use Neos\Flow\Annotations as Flow;

/**
Expand All @@ -25,6 +26,7 @@
final readonly class Conflict implements \JsonSerializable
{
public function __construct(
public string $key,
public ?IconLabel $affectedSite,
public ?IconLabel $affectedDocument,
public ?IconLabel $affectedNode,
Expand Down
13 changes: 3 additions & 10 deletions Classes/Application/Shared/Conflicts.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,9 @@ public function __construct(Conflict ...$items)
$this->items = $items;
}

public static function builder(
ContentRepository $contentRepository,
WorkspaceName $workspaceName,
?DimensionSpacePoint $preferredDimensionSpacePoint,
): ConflictsBuilder {
return new ConflictsBuilder(
contentRepository: $contentRepository,
workspaceName: $workspaceName,
preferredDimensionSpacePoint: $preferredDimensionSpacePoint
);
public static function builder(): ConflictsBuilder
{
return new ConflictsBuilder();
}

public function jsonSerialize(): mixed
Expand Down
260 changes: 7 additions & 253 deletions Classes/Application/Shared/ConflictsBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,47 +14,14 @@

namespace Neos\Neos\Ui\Application\Shared;

use Neos\ContentRepository\Core\CommandHandler\CommandInterface;
use Neos\ContentRepository\Core\ContentRepository;
use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint;
use Neos\ContentRepository\Core\Feature\NodeCreation\Command\CreateNodeAggregateWithNode;
use Neos\ContentRepository\Core\Feature\NodeCreation\Command\CreateNodeAggregateWithNodeAndSerializedProperties;
use Neos\ContentRepository\Core\Feature\NodeDisabling\Command\DisableNodeAggregate;
use Neos\ContentRepository\Core\Feature\NodeDisabling\Command\EnableNodeAggregate;
use Neos\ContentRepository\Core\Feature\NodeModification\Command\SetNodeProperties;
use Neos\ContentRepository\Core\Feature\NodeModification\Command\SetSerializedNodeProperties;
use Neos\ContentRepository\Core\Feature\NodeMove\Command\MoveNodeAggregate;
use Neos\ContentRepository\Core\Feature\NodeReferencing\Command\SetNodeReferences;
use Neos\ContentRepository\Core\Feature\NodeReferencing\Command\SetSerializedNodeReferences;
use Neos\ContentRepository\Core\Feature\NodeRemoval\Command\RemoveNodeAggregate;
use Neos\ContentRepository\Core\Feature\NodeTypeChange\Command\ChangeNodeAggregateType;
use Neos\ContentRepository\Core\Feature\NodeVariation\Command\CreateNodeVariant;
use Neos\ContentRepository\Core\Feature\SubtreeTagging\Command\TagSubtree;
use Neos\ContentRepository\Core\Feature\SubtreeTagging\Command\UntagSubtree;
use Neos\ContentRepository\Core\Feature\WorkspaceRebase\CommandThatFailedDuringRebase;
use Neos\ContentRepository\Core\NodeType\NodeTypeManager;
use Neos\ContentRepository\Core\Projection\ContentGraph\ContentSubgraphInterface;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter;
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate;
use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints;
use Neos\ContentRepository\Core\Projection\Workspace\Workspace;
use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregateCurrentlyDoesNotExist;
use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId;
use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName;
use Neos\Flow\Annotations as Flow;
use Neos\Neos\Domain\Service\NodeTypeNameFactory;

/**
* @internal
*/
#[Flow\Proxy(false)]
final class ConflictsBuilder
{
private NodeTypeManager $nodeTypeManager;

private ?Workspace $workspace;

/**
* @var Conflict[]
*/
Expand All @@ -63,233 +30,20 @@ final class ConflictsBuilder
/**
* @var array<string,Conflict>
*/
private array $itemsByAffectedNodeAggregateId = [];

public function __construct(
private ContentRepository $contentRepository,
WorkspaceName $workspaceName,
private ?DimensionSpacePoint $preferredDimensionSpacePoint,
) {
$this->nodeTypeManager = $contentRepository->getNodeTypeManager();

$this->workspace = $contentRepository->getWorkspaceFinder()
->findOneByName($workspaceName);
}
private array $itemsByKey = [];

public function addCommandThatFailedDuringRebase(
CommandThatFailedDuringRebase $commandThatFailedDuringRebase
): void {
$nodeAggregateId = $this->extractNodeAggregateIdFromCommand(
$commandThatFailedDuringRebase->command
);

if ($nodeAggregateId && isset($this->itemsByAffectedNodeAggregateId[$nodeAggregateId->value])) {
return;
public function addConflict(Conflict $conflict): self
{
if (!isset($this->itemsByKey[$conflict->key])) {
$this->itemsByKey[$conflict->key] = $conflict;
$this->items[] = $conflict;
}

$conflict = $this->createConflictFromCommandThatFailedDuringRebase(
$commandThatFailedDuringRebase
);

$this->items[] = $conflict;

if ($nodeAggregateId) {
$this->itemsByAffectedNodeAggregateId[$nodeAggregateId->value] = $conflict;
}
return $this;
}

public function build(): Conflicts
{
return new Conflicts(...$this->items);
}

private function createConflictFromCommandThatFailedDuringRebase(
CommandThatFailedDuringRebase $commandThatFailedDuringRebase
): Conflict {
$nodeAggregateId = $this->extractNodeAggregateIdFromCommand(
$commandThatFailedDuringRebase->command
);
$subgraph = $this->acquireSubgraphFromCommand(
$commandThatFailedDuringRebase->command,
$nodeAggregateId
);
$affectedSite = $nodeAggregateId
? $subgraph->findClosestNode(
$nodeAggregateId,
FindClosestNodeFilter::create(nodeTypes: NodeTypeNameFactory::NAME_SITE)
)
: null;
$affectedDocument = $nodeAggregateId
? $subgraph->findClosestNode(
$nodeAggregateId,
FindClosestNodeFilter::create(nodeTypes: NodeTypeNameFactory::NAME_DOCUMENT)
)
: null;
$affectedNode = $nodeAggregateId
? $subgraph?->findNodeById($nodeAggregateId)
: null;

return new Conflict(
affectedSite: $affectedSite
? $this->createIconLabelForNode($affectedSite)
: null,
affectedDocument: $affectedDocument
? $this->createIconLabelForNode($affectedDocument)
: null,
affectedNode: $affectedNode
? $this->createIconLabelForNode($affectedNode)
: null,
typeOfChange: $this->createTypeOfChangeFromCommand(
$commandThatFailedDuringRebase->command
),
reasonForConflict: $this->createReasonForConflictFromException(
$commandThatFailedDuringRebase->exception
)
);
}

private function extractNodeAggregateIdFromCommand(CommandInterface $command): ?NodeAggregateId
{
return match (true) {
$command instanceof MoveNodeAggregate,
$command instanceof SetNodeProperties,
$command instanceof SetSerializedNodeProperties,
$command instanceof CreateNodeAggregateWithNode,
$command instanceof CreateNodeAggregateWithNodeAndSerializedProperties,
$command instanceof TagSubtree,
$command instanceof DisableNodeAggregate,
$command instanceof UntagSubtree,
$command instanceof EnableNodeAggregate,
$command instanceof RemoveNodeAggregate,
$command instanceof ChangeNodeAggregateType,
$command instanceof CreateNodeVariant =>
$command->nodeAggregateId,
$command instanceof SetNodeReferences,
$command instanceof SetSerializedNodeReferences =>
$command->sourceNodeAggregateId,
default => null
};
}

private function acquireSubgraphFromCommand(
CommandInterface $command,
?NodeAggregateId $nodeAggregateIdForDimensionFallback
): ?ContentSubgraphInterface {
if ($this->workspace === null) {
return null;
}

$dimensionSpacePoint = match (true) {
$command instanceof MoveNodeAggregate =>
$command->dimensionSpacePoint,
$command instanceof SetNodeProperties,
$command instanceof SetSerializedNodeProperties,
$command instanceof CreateNodeAggregateWithNode,
$command instanceof CreateNodeAggregateWithNodeAndSerializedProperties =>
$command->originDimensionSpacePoint->toDimensionSpacePoint(),
$command instanceof SetNodeReferences,
$command instanceof SetSerializedNodeReferences =>
$command->sourceOriginDimensionSpacePoint->toDimensionSpacePoint(),
$command instanceof TagSubtree,
$command instanceof DisableNodeAggregate,
$command instanceof UntagSubtree,
$command instanceof EnableNodeAggregate,
$command instanceof RemoveNodeAggregate =>
$command->coveredDimensionSpacePoint,
$command instanceof ChangeNodeAggregateType =>
null,
$command instanceof CreateNodeVariant =>
$command->targetOrigin->toDimensionSpacePoint(),
default => null
};

if ($dimensionSpacePoint === null) {
if ($nodeAggregateIdForDimensionFallback === null) {
return null;
}

$nodeAggregate = $this->contentRepository->getContentGraph()
->findNodeAggregateById(
$this->workspace->currentContentStreamId,
$nodeAggregateIdForDimensionFallback
);

if ($nodeAggregate) {
$dimensionSpacePoint = $this->extractValidDimensionSpacePointFromNodeAggregate(
$nodeAggregate
);

if ($dimensionSpacePoint === null) {
return null;
}
}
}

return $this->contentRepository->getContentGraph()->getSubgraph(
$this->workspace->currentContentStreamId,
$dimensionSpacePoint,
VisibilityConstraints::withoutRestrictions()
);
}

private function extractValidDimensionSpacePointFromNodeAggregate(
NodeAggregate $nodeAggregate
): ?DimensionSpacePoint {
$result = null;

foreach ($nodeAggregate->coveredDimensionSpacePoints as $coveredDimensionSpacePoint) {
if ($this->preferredDimensionSpacePoint?->equals($coveredDimensionSpacePoint)) {
return $coveredDimensionSpacePoint;
}
$result ??= $coveredDimensionSpacePoint;
}

return $result;
}

private function createIconLabelForNode(Node $node): IconLabel
{
$nodeType = $this->nodeTypeManager->getNodeType($node->nodeTypeName);

return new IconLabel(
icon: $nodeType?->getConfiguration('ui.icon') ?? 'questionmark',
label: $node->getLabel()
);
}

private function createTypeOfChangeFromCommand(
CommandInterface $command
): ?TypeOfChange {
return match (true) {
$command instanceof CreateNodeAggregateWithNode,
$command instanceof CreateNodeAggregateWithNodeAndSerializedProperties,
$command instanceof CreateNodeVariant =>
TypeOfChange::NODE_HAS_BEEN_CREATED,
$command instanceof SetNodeProperties,
$command instanceof SetSerializedNodeProperties,
$command instanceof SetNodeReferences,
$command instanceof SetSerializedNodeReferences,
$command instanceof TagSubtree,
$command instanceof DisableNodeAggregate,
$command instanceof UntagSubtree,
$command instanceof EnableNodeAggregate,
$command instanceof ChangeNodeAggregateType =>
TypeOfChange::NODE_HAS_BEEN_CHANGED,
$command instanceof MoveNodeAggregate =>
TypeOfChange::NODE_HAS_BEEN_MOVED,
$command instanceof RemoveNodeAggregate =>
TypeOfChange::NODE_HAS_BEEN_DELETED,
default => null
};
}

private function createReasonForConflictFromException(
\Throwable $exception
): ?ReasonForConflict {
return match ($exception::class) {
NodeAggregateCurrentlyDoesNotExist::class =>
ReasonForConflict::NODE_HAS_BEEN_DELETED,
default => null
};
}
}
Loading

0 comments on commit e96ce99

Please sign in to comment.