-
-
Notifications
You must be signed in to change notification settings - Fork 135
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3519 from neos/feature/improveNodeCreationHandler…
…Interface !!! FEATURE: Overhaul `NodeCreationHandlerInterface`
- Loading branch information
Showing
20 changed files
with
1,238 additions
and
375 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
<?php | ||
declare(strict_types=1); | ||
namespace Neos\Neos\Ui\Domain\NodeCreation; | ||
|
||
/* | ||
* This file is part of the Neos.Neos.Ui 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. | ||
*/ | ||
|
||
use Neos\ContentRepository\Core\CommandHandler\CommandInterface; | ||
use Neos\ContentRepository\Core\Feature\NodeCreation\Command\CreateNodeAggregateWithNode; | ||
use Neos\ContentRepository\Core\Feature\NodeCreation\Dto\NodeAggregateIdsByNodePaths; | ||
use Neos\ContentRepository\Core\Feature\NodeDisabling\Command\DisableNodeAggregate; | ||
use Neos\ContentRepository\Core\Feature\NodeDisabling\Command\EnableNodeAggregate; | ||
use Neos\ContentRepository\Core\Feature\NodeDuplication\Command\CopyNodesRecursively; | ||
use Neos\ContentRepository\Core\Feature\NodeModification\Command\SetNodeProperties; | ||
use Neos\ContentRepository\Core\Feature\NodeModification\Dto\PropertyValuesToWrite; | ||
use Neos\ContentRepository\Core\Feature\NodeReferencing\Command\SetNodeReferences; | ||
use Neos\ContentRepository\Core\NodeType\NodeTypeManager; | ||
|
||
/** | ||
* A collection of commands that describe a node creation from the Neos Ui. | ||
* | ||
* The node creation can be enriched via a node creation handler {@see NodeCreationHandlerInterface} | ||
* | ||
* The first command points to the triggered node creation command. | ||
* To not contradict the users intend it is ensured that the initial node | ||
* creation will be mostly preserved by only allowing to add additional properties. | ||
* | ||
* Additional commands can be also appended, to be run after the initial node creation command. | ||
* All commands will be executed blocking. | ||
* | ||
* You can retrieve the subgraph or the parent node (where the first node will be created in) the following way: | ||
* | ||
* $subgraph = $contentRepository->getContentGraph()->getSubgraph( | ||
* $commands->first->contentStreamId, | ||
* $commands->first->originDimensionSpacePoint->toDimensionSpacePoint(), | ||
* VisibilityConstraints::frontend() | ||
* ); | ||
* $parentNode = $subgraph->findNodeById($commands->first->parentNodeAggregateId); | ||
* | ||
* @implements \IteratorAggregate<int, CommandInterface> | ||
* @internal Especially the constructors | ||
*/ | ||
final readonly class NodeCreationCommands implements \IteratorAggregate | ||
{ | ||
/** | ||
* The initial node creation command. | ||
* It is only allowed to change its properties via {@see self::withInitialPropertyValues()} | ||
*/ | ||
public CreateNodeAggregateWithNode $first; | ||
|
||
/** | ||
* Add a list of commands that are executed after the initial created command was run. | ||
* This allows to create child-nodes and append other allowed commands. | ||
* | ||
* @var array<int,CreateNodeAggregateWithNode|SetNodeProperties|DisableNodeAggregate|EnableNodeAggregate|SetNodeReferences|CopyNodesRecursively> | ||
*/ | ||
public array $additionalCommands; | ||
|
||
private function __construct( | ||
CreateNodeAggregateWithNode $first, | ||
CreateNodeAggregateWithNode|SetNodeProperties|DisableNodeAggregate|EnableNodeAggregate|SetNodeReferences|CopyNodesRecursively ...$additionalCommands | ||
) { | ||
$this->first = $first; | ||
$this->additionalCommands = array_values($additionalCommands); | ||
} | ||
|
||
/** | ||
* @internal to guarantee that the initial create command is mostly preserved as intended. | ||
* You can use {@see self::withInitialPropertyValues()} to add new properties of the to be created node. | ||
*/ | ||
public static function fromFirstCommand( | ||
CreateNodeAggregateWithNode $first, | ||
NodeTypeManager $nodeTypeManager | ||
): self { | ||
$tetheredDescendantNodeAggregateIds = NodeAggregateIdsByNodePaths::createForNodeType( | ||
$first->nodeTypeName, | ||
$nodeTypeManager | ||
); | ||
return new self( | ||
$first->withTetheredDescendantNodeAggregateIds($tetheredDescendantNodeAggregateIds), | ||
); | ||
} | ||
|
||
/** | ||
* Augment the first {@see CreateNodeAggregateWithNode} command with altered properties. | ||
* | ||
* The properties will be completely replaced. | ||
* To merge the properties please use: | ||
* | ||
* $commands->withInitialPropertyValues( | ||
* $commands->first->initialPropertyValues | ||
* ->withValue('album', 'rep') | ||
* ) | ||
* | ||
*/ | ||
public function withInitialPropertyValues(PropertyValuesToWrite $newInitialPropertyValues): self | ||
{ | ||
return new self( | ||
$this->first->withInitialPropertyValues($newInitialPropertyValues), | ||
...$this->additionalCommands | ||
); | ||
} | ||
|
||
public function withAdditionalCommands( | ||
CreateNodeAggregateWithNode|SetNodeProperties|DisableNodeAggregate|EnableNodeAggregate|SetNodeReferences|CopyNodesRecursively ...$additionalCommands | ||
): self { | ||
return new self($this->first, ...$this->additionalCommands, ...$additionalCommands); | ||
} | ||
|
||
/** | ||
* @return \Traversable<int, CommandInterface> | ||
*/ | ||
public function getIterator(): \Traversable | ||
{ | ||
yield from [$this->first, ...$this->additionalCommands]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Neos\Neos\Ui\Domain\NodeCreation; | ||
|
||
use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateIds; | ||
|
||
/** | ||
* Holds the deserialized elements of the submitted node creation dialog form | ||
* | ||
* Elements are configured like properties or references in the schema, | ||
* but its up to the node-creation-handler if they are handled in any way or just left out. | ||
* | ||
* Elements that are of simple types or objects, will be available according to its type. | ||
* For example myImage will be an actual image object instance. | ||
* | ||
* Vendor.Site:Content: | ||
* ui: | ||
* creationDialog: | ||
* elements: | ||
* myString: | ||
* type: string | ||
* myImage: | ||
* type: Neos\Media\Domain\Model\ImageInterface | ||
* | ||
* Elements that refer to nodes are of type `references` or `reference`. | ||
* They will be available as {@see NodeAggregateIds} collection. | ||
* | ||
* Vendor.Site:Content: | ||
* ui: | ||
* creationDialog: | ||
* elements: | ||
* myReferences: | ||
* type: references | ||
* | ||
* The naming `references` in the `element` configuration does not refer to the content repository reference edges. | ||
* Referring to a node will just denote that an editor will be used capable of returning node ids. | ||
* The node ids might be used for setting references but that is up to a node-creation-handler. | ||
* | ||
* To promoted properties / references the same rules apply: | ||
* | ||
* Vendor.Site:Content: | ||
* properties: | ||
* myString: | ||
* type: string | ||
* ui: | ||
* showInCreationDialog: true | ||
* | ||
* @implements \IteratorAggregate<string, mixed> | ||
* @internal Especially the constructor and the serialized data | ||
*/ | ||
final readonly class NodeCreationElements implements \IteratorAggregate | ||
{ | ||
/** | ||
* @param array<string, mixed> $elementValues | ||
* @param array<int|string, mixed> $serializedValues | ||
* @internal you should not need to construct this | ||
*/ | ||
public function __construct( | ||
private array $elementValues, | ||
private array $serializedValues, | ||
) { | ||
} | ||
|
||
public function has(string $name): bool | ||
{ | ||
return isset($this->elementValues[$name]); | ||
} | ||
|
||
/** | ||
* Returns the type according to the element schema | ||
* For elements that refer to a node {@see NodeAggregateIds} will be returned. | ||
*/ | ||
public function get(string $name): mixed | ||
{ | ||
return $this->elementValues[$name] ?? null; | ||
} | ||
|
||
/** | ||
* @internal returns values formatted by the internal format used for the Ui | ||
* @return \Traversable<int|string, mixed> | ||
*/ | ||
public function serialized(): \Traversable | ||
{ | ||
yield from $this->serializedValues; | ||
} | ||
|
||
/** | ||
* @return \Traversable<string,mixed> | ||
*/ | ||
public function getIterator(): \Traversable | ||
{ | ||
yield from $this->elementValues; | ||
} | ||
} |
Oops, something went wrong.