Skip to content

Commit

Permalink
Merge pull request #5371 from mhsdesign/bugfix/copy-nodes-as-a-service
Browse files Browse the repository at this point in the history
FEATURE: Node copying Version 3 (as a Neos service)
  • Loading branch information
kitsunet authored Nov 19, 2024
2 parents ff6cf21 + d3115ce commit 56d616f
Show file tree
Hide file tree
Showing 26 changed files with 1,331 additions and 160 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
use Neos\ContentRepository\Core\Projection\ContentGraph\Nodes;
use Neos\ContentRepository\Core\Projection\ContentGraph\References;
use Neos\ContentRepository\Core\Projection\ContentGraph\Subtree;
use Neos\ContentRepository\Core\Projection\ContentGraph\Subtrees;
use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints;
use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId;
use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateClassification;
Expand Down Expand Up @@ -304,7 +305,11 @@ public function findSubtree(NodeAggregateId $entryNodeAggregateId, FindSubtreeFi
$this->dimensionSpacePoint,
$this->visibilityConstraints
);
$subtree = new Subtree((int)$nodeData['level'], $node, array_key_exists($nodeAggregateId, $subtreesByParentNodeId) ? array_reverse($subtreesByParentNodeId[$nodeAggregateId]) : []);
$subtree = Subtree::create(
(int)$nodeData['level'],
$node,
array_key_exists($nodeAggregateId, $subtreesByParentNodeId) ? Subtrees::fromArray(array_reverse($subtreesByParentNodeId[$nodeAggregateId])) : Subtrees::createEmpty()
);
if ($subtree->level === 0) {
return $subtree;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
use Neos\ContentRepository\Core\Projection\ContentGraph\Reference;
use Neos\ContentRepository\Core\Projection\ContentGraph\References;
use Neos\ContentRepository\Core\Projection\ContentGraph\Subtree;
use Neos\ContentRepository\Core\Projection\ContentGraph\Subtrees;
use Neos\ContentRepository\Core\Projection\ContentGraph\Timestamps;
use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints;
use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId;
Expand Down Expand Up @@ -154,7 +155,11 @@ public function mapNodeRowsToSubtree(
$nodeAggregateId = $nodeRow['nodeaggregateid'];
$parentNodeAggregateId = $nodeRow['parentnodeaggregateid'];
$node = $this->mapNodeRowToNode($nodeRow, $visibilityConstraints);
$subtree = new Subtree((int)$nodeRow['level'], $node, array_key_exists($nodeAggregateId, $subtreesByParentNodeId) ? array_reverse($subtreesByParentNodeId[$nodeAggregateId]) : []);
$subtree = Subtree::create(
(int)$nodeRow['level'],
$node,
array_key_exists($nodeAggregateId, $subtreesByParentNodeId) ? Subtrees::fromArray(array_reverse($subtreesByParentNodeId[$nodeAggregateId])) : Subtrees::createEmpty()
);
if ($subtree->level === 0) {
return $subtree;
}
Expand Down

This file was deleted.

62 changes: 62 additions & 0 deletions Neos.ContentRepository.Core/Classes/CommandHandler/Commands.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

declare(strict_types=1);

namespace Neos\ContentRepository\Core\CommandHandler;

/**
* @api can be used as collection of commands to be individually handled:
*
* foreach ($commands as $command) {
* $contentRepository->handle($command);
* }
*
* @implements \IteratorAggregate<CommandInterface>
*/
final readonly class Commands implements \IteratorAggregate, \Countable
{
/** @var array<int,CommandInterface> */
private array $items;

private function __construct(
CommandInterface ...$items
) {
$this->items = array_values($items);
}

public static function create(CommandInterface ...$items): self
{
return new self(...$items);
}

public static function createEmpty(): self
{
return new self();
}

/** @param array<CommandInterface> $array */
public static function fromArray(array $array): self
{
return new self(...$array);
}

public function append(CommandInterface $command): self
{
return new self(...[...$this->items, $command]);
}

public function merge(self $other): self
{
return new self(...$this->items, ...$other->items);
}

public function getIterator(): \Traversable
{
yield from $this->items;
}

public function count(): int
{
return count($this->items);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,17 @@

namespace Neos\ContentRepository\Core\Feature\NodeDuplication\Command;

use Neos\ContentRepository\Core\CommandHandler\CommandInterface;
use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint;
use Neos\ContentRepository\Core\Feature\Common\MatchableWithNodeIdToPublishOrDiscardInterface;
use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface;
use Neos\ContentRepository\Core\Feature\NodeDuplication\Dto\NodeAggregateIdMapping;
use Neos\ContentRepository\Core\Feature\NodeDuplication\Dto\NodeSubtreeSnapshot;
use Neos\ContentRepository\Core\Feature\WorkspacePublication\Dto\NodeIdToPublishOrDiscard;
use Neos\ContentRepository\Core\Projection\ContentGraph\ContentSubgraphInterface;
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
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\WorkspaceName;
use Neos\Neos\Domain\Service\NodeDuplication\NodeAggregateIdMapping;

/**
* CopyNodesRecursively command
Expand All @@ -35,10 +33,10 @@
* The node will be appended as child node of the given `parentNodeId` which must cover the given
* `dimensionSpacePoint`.
*
* @api commands are the write-API of the ContentRepository
* @internal
* @deprecated with Neos 9 Beta 16, please use Neos's {@see \Neos\Neos\Domain\Service\NodeDuplicationService} instead.
*/
final readonly class CopyNodesRecursively implements
CommandInterface,
\JsonSerializable,
MatchableWithNodeIdToPublishOrDiscardInterface,
RebasableToOtherWorkspaceInterface
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ private function handleCopyNodesRecursively(

private function requireNewNodeAggregateIdsToNotExist(
ContentGraphInterface $contentGraph,
Dto\NodeAggregateIdMapping $nodeAggregateIdMapping
\Neos\Neos\Domain\Service\NodeDuplication\NodeAggregateIdMapping $nodeAggregateIdMapping
): void {
foreach ($nodeAggregateIdMapping->getAllNewNodeAggregateIds() as $nodeAggregateId) {
$this->requireProjectedNodeAggregateToNotExist(
Expand All @@ -191,7 +191,7 @@ private function createEventsForNodeToInsert(
?NodeAggregateId $targetSucceedingSiblingNodeAggregateId,
?NodeName $targetNodeName,
NodeSubtreeSnapshot $nodeToInsert,
Dto\NodeAggregateIdMapping $nodeAggregateIdMapping,
\Neos\Neos\Domain\Service\NodeDuplication\NodeAggregateIdMapping $nodeAggregateIdMapping,
array &$events,
): void {
$events[] = new NodeAggregateWithNodeWasCreated(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public static function fromRootNodeTypeNameAndRelativePath(
public static function fromLeafNodeAndAncestors(Node $leafNode, Nodes $ancestors): self
{
if ($leafNode->classification->isRoot()) {
return new self($leafNode->nodeTypeName, NodePath::forRoot());
return new self($leafNode->nodeTypeName, NodePath::createEmpty());
}
$rootNode = $ancestors->first();
if (!$rootNode || !$rootNode->classification->isRoot()) {
Expand Down Expand Up @@ -147,7 +147,7 @@ public function appendPathSegment(NodeName $nodeName): self
*/
public function isRoot(): bool
{
return $this->path->isRoot();
return $this->path->isEmpty();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
use Neos\ContentRepository\Core\SharedModel\Node\NodeName;

/**
* The relative node path is a collection of node names {@see NodeName}. If it contains no elements, it is considered root.
* The relative node path is a collection of node names {@see NodeName}.
*
* If it contains no elements, it is considered root in combination with {@see AbsoluteNodePath}.
*
* Example:
* root path: '' is resolved to []
Expand Down Expand Up @@ -48,7 +50,7 @@ private function __construct(NodeName ...$nodeNames)
$this->nodeNames = $nodeNames;
}

public static function forRoot(): self
public static function createEmpty(): self
{
return new self();
}
Expand All @@ -57,7 +59,7 @@ public static function fromString(string $path): self
{
$path = ltrim($path, '/');
if ($path === '') {
return self::forRoot();
return self::createEmpty();
}

return self::fromPathSegments(
Expand Down Expand Up @@ -92,7 +94,7 @@ public static function fromNodeNames(NodeName ...$nodeNames): self
return new self(...$nodeNames);
}

public function isRoot(): bool
public function isEmpty(): bool
{
return $this->getLength() === 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,25 @@
namespace Neos\ContentRepository\Core\Projection\ContentGraph;

/**
* @api returned by {@see ContentSubgraphInterface}
* @api returned by {@see ContentSubgraphInterface::findSubtree()}
*/
final readonly class Subtree
{
/**
* @param array<int,Subtree> $children
*/
public function __construct(
private function __construct(
public int $level,
public Node $node,
public array $children
public Subtrees $children
) {
}

/**
* @internal
*/
public static function create(
int $level,
Node $node,
Subtrees $children
): self {
return new self($level, $node, $children);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

namespace Neos\ContentRepository\Core\Projection\ContentGraph;

/**
* @api part of {@see Subtree}
* @implements \IteratorAggregate<Subtree>
*/
final readonly class Subtrees implements \IteratorAggregate, \Countable
{
/** @var array<Subtree> */
private array $items;

private function __construct(
Subtree ...$items
) {
$this->items = $items;
}

/**
* @internal
*/
public static function createEmpty(): self
{
return new self();
}

/**
* @internal
* @param array<Subtree> $items
*/
public static function fromArray(array $items): self
{
return new self(...$items);
}

public function getIterator(): \Traversable
{
yield from $this->items;
}

public function count(): int
{
return count($this->items);
}
}
Loading

0 comments on commit 56d616f

Please sign in to comment.