Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TASK: Adjust to changes in Neos removing internal node properties #3735

Merged
merged 5 commits into from May 14, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
311 changes: 168 additions & 143 deletions Classes/Domain/Model/Changes/Property.php
Expand Up @@ -12,6 +12,7 @@
* source code.
*/

use Neos\ContentRepository\Core\CommandHandler\CommandResult;
use Neos\ContentRepository\Core\DimensionSpace\Exception\DimensionSpacePointNotFound;
use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint;
use Neos\ContentRepository\Core\Feature\NodeDisabling\Command\DisableNodeAggregate;
Expand All @@ -24,6 +25,7 @@
use Neos\ContentRepository\Core\Feature\NodeTypeChange\Dto\NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy;
use Neos\ContentRepository\Core\Feature\NodeVariation\Command\CreateNodeVariant;
use Neos\ContentRepository\Core\NodeType\NodeTypeName;
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
use Neos\ContentRepository\Core\SharedModel\Exception\ContentStreamDoesNotExistYet;
use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregatesTypeIsAmbiguous;
use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateIds;
Expand Down Expand Up @@ -72,6 +74,7 @@ class Property extends AbstractChange

/**
* The value, the property will be set to
*
* @var string|array<int|string,mixed>|null
*/
protected string|array|null $value = null;
Expand Down Expand Up @@ -132,7 +135,7 @@ public function getIsInline(): bool
*/
public function canApply(): bool
{
if (is_null($this->subject)) {
if (is_null($this->subject) || is_null($this->subject->nodeType)) {
return false;
}
$nodeType = $this->subject->nodeType;
Expand All @@ -148,158 +151,180 @@ public function canApply(): bool
* @throws ContentStreamDoesNotExistYet
* @throws NodeAggregatesTypeIsAmbiguous
* @throws DimensionSpacePointNotFound
* @throws \Exception
*/
public function apply(): void
{
$subject = $this->subject;
$propertyName = $this->getPropertyName();
if ($this->canApply() && !is_null($subject) && !is_null($propertyName)) {
$contentRepository = $this->contentRepositoryRegistry->get($subject->subgraphIdentity->contentRepositoryId);

$propertyType = $this->getNodeType($subject)->getPropertyType($propertyName);

// Use extra commands for reference handling
if ($propertyType === 'reference' || $propertyType === 'references') {
$value = $this->getValue();
$destinationNodeAggregateIds = [];
if ($propertyType === 'reference') {
if (is_string($value) && !empty($value)) {
$destinationNodeAggregateIds[] = $value;
}
}

if ($propertyType === 'references') {
/** @var array<int,string> $values */
$values = $value;
if (is_array($values)) {
foreach ($values as $singleNodeAggregateId) {
$destinationNodeAggregateIds[] = $singleNodeAggregateId;
}
}
}

$commandResult = $contentRepository->handle(
SetNodeReferences::create(
$subject->subgraphIdentity->contentStreamId,
$subject->nodeAggregateId,
$subject->originDimensionSpacePoint,
ReferenceName::fromString($propertyName),
NodeReferencesToWrite::fromNodeAggregateIds(NodeAggregateIds::fromArray($destinationNodeAggregateIds))
)
);
} else {
$value = $this->nodePropertyConversionService->convert(
$this->getNodeType($subject),
$propertyName,
$this->getValue()
);

if ($propertyName[0] !== '_' || $propertyName === '_hiddenInIndex') {
$originDimensionSpacePoint = $subject->originDimensionSpacePoint;
if (!$subject->subgraphIdentity->dimensionSpacePoint->equals($originDimensionSpacePoint)) {
$originDimensionSpacePoint = OriginDimensionSpacePoint::fromDimensionSpacePoint($subject->subgraphIdentity->dimensionSpacePoint);
// if origin dimension space point != current DSP -> translate transparently (matching old behavior)
$contentRepository->handle(
CreateNodeVariant::create(
$subject->subgraphIdentity->contentStreamId,
$subject->nodeAggregateId,
$subject->originDimensionSpacePoint,
$originDimensionSpacePoint
)
)->block();
}
$commandResult = $contentRepository->handle(
SetNodeProperties::create(
$subject->subgraphIdentity->contentStreamId,
$subject->nodeAggregateId,
$originDimensionSpacePoint,
PropertyValuesToWrite::fromArray(
[
$propertyName => $value
]
)
)
);
} else {
// property starts with "_"
if ($propertyName === '_nodeType') {
$commandResult = $contentRepository->handle(
ChangeNodeAggregateType::create(
$subject->subgraphIdentity->contentStreamId,
$subject->nodeAggregateId,
NodeTypeName::fromString($value),
NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy::STRATEGY_DELETE
)
);
} elseif ($propertyName === '_hidden') {
if ($value === true) {
$commandResult = $contentRepository->handle(
DisableNodeAggregate::create(
$subject->subgraphIdentity->contentStreamId,
$subject->nodeAggregateId,
$subject->originDimensionSpacePoint->toDimensionSpacePoint(),
NodeVariantSelectionStrategy::STRATEGY_ALL_SPECIALIZATIONS
)
);
} else {
// unhide
$commandResult = $contentRepository->handle(
EnableNodeAggregate::create(
$subject->subgraphIdentity->contentStreamId,
$subject->nodeAggregateId,
$subject->originDimensionSpacePoint->toDimensionSpacePoint(),
NodeVariantSelectionStrategy::STRATEGY_ALL_SPECIALIZATIONS
)
);
}
} else {
throw new \Exception("TODO FIX");
}
}
}
if (is_null($subject) || is_null($propertyName) || $this->canApply() === false) {
return;
}

$commandResult->block();

// !!! REMEMBER: we are not allowed to use $node anymore,
// because it may have been modified by the commands above.
// Thus, we need to re-fetch it (as a workaround; until we do not need this anymore)
$subgraph = $this->contentRepositoryRegistry->subgraphForNode($subject);
$originalNodeAggregateId = $subject->nodeAggregateId;
$node = $subgraph->findNodeById($originalNodeAggregateId);
if (is_null($node)) {
throw new \InvalidArgumentException(
'Cannot apply Property on missing node ' . $originalNodeAggregateId->value,
1645560836
);
}
$propertyType = $this->getNodeType($subject)->getPropertyType($propertyName);

$this->updateWorkspaceInfo();
$parentNode = $subgraph->findParentNode($node->nodeAggregateId);

// This might be needed to update node label and other things that we can calculate only on the server
$updateNodeInfo = new UpdateNodeInfo();
$updateNodeInfo->setNode($node);
$this->feedbackCollection->add($updateNodeInfo);

$reloadIfChangedConfigurationPath = sprintf('properties.%s.ui.reloadIfChanged', $propertyName);
if (!$this->getIsInline() && $this->getNodeType($node)->getConfiguration($reloadIfChangedConfigurationPath)) {
if ($this->getNodeDomAddress() && $this->getNodeDomAddress()->getFusionPath()
&& $parentNode
&& $this->getNodeType($parentNode)->isOfType('Neos.Neos:ContentCollection')) {
$reloadContentOutOfBand = new ReloadContentOutOfBand();
$reloadContentOutOfBand->setNode($node);
$reloadContentOutOfBand->setNodeDomAddress($this->getNodeDomAddress());
$this->feedbackCollection->add($reloadContentOutOfBand);
} else {
$this->reloadDocument($node);
}
}
$commandResult = match ($propertyType) {
'reference', 'references' => $this->handleNodeReferenceChange($subject, $propertyName),
'_nodeType' => $this->handleNodeTypeChange($subject, $propertyName),
'_hidden' => $this->handleHiddenPropertyChange($subject, $propertyName),
grebaldi marked this conversation as resolved.
Show resolved Hide resolved
default => $this->handlePropertyChange($subject, $propertyName)
};

$commandResult->block();
$this->createFeedback($subject);
}

private function createFeedback(Node $subject): void
{
$propertyName = $this->getPropertyName();

$reloadPageIfChangedConfigurationPath = sprintf('properties.%s.ui.reloadPageIfChanged', $propertyName);
if (!$this->getIsInline()
&& $this->getNodeType($node)->getConfiguration($reloadPageIfChangedConfigurationPath)) {
// !!! REMEMBER: we are not allowed to use $node anymore,
// because it may have been modified by the commands above.
// Thus, we need to re-fetch it (as a workaround; until we do not need this anymore)
mhsdesign marked this conversation as resolved.
Show resolved Hide resolved
$subgraph = $this->contentRepositoryRegistry->subgraphForNode($subject);
$originalNodeAggregateId = $subject->nodeAggregateId;
$node = $subgraph->findNodeById($originalNodeAggregateId);
if (is_null($node)) {
throw new \InvalidArgumentException(
'Cannot apply Property on missing node ' . $originalNodeAggregateId->value,
1645560836
);
}

$this->updateWorkspaceInfo();
$parentNode = $subgraph->findParentNode($node->nodeAggregateId);

// This might be needed to update node label and other things that we can calculate only on the server
$updateNodeInfo = new UpdateNodeInfo();
$updateNodeInfo->setNode($node);
$this->feedbackCollection->add($updateNodeInfo);

$reloadIfChangedConfigurationPath = sprintf('properties.%s.ui.reloadIfChanged', $propertyName);
if (!$this->getIsInline() && $this->getNodeType($node)->getConfiguration($reloadIfChangedConfigurationPath)) {
if ($this->getNodeDomAddress() && $this->getNodeDomAddress()->getFusionPath()
&& $parentNode
&& $this->getNodeType($parentNode)->isOfType('Neos.Neos:ContentCollection')) {
$reloadContentOutOfBand = new ReloadContentOutOfBand();
$reloadContentOutOfBand->setNode($node);
$reloadContentOutOfBand->setNodeDomAddress($this->getNodeDomAddress());
$this->feedbackCollection->add($reloadContentOutOfBand);
} else {
$this->reloadDocument($node);
}
}

$reloadPageIfChangedConfigurationPath = sprintf('properties.%s.ui.reloadPageIfChanged', $propertyName);
if (!$this->getIsInline()
&& $this->getNodeType($node)->getConfiguration($reloadPageIfChangedConfigurationPath)) {
$this->reloadDocument($node);
}
}

private function handleNodeReferenceChange(Node $subject, string $propertyName): CommandResult
{
$contentRepository = $this->contentRepositoryRegistry->get($subject->subgraphIdentity->contentRepositoryId);
$value = $this->getValue();

if (!is_array($value)) {
$value = [$value];
}

$value = array_filter($value, fn ($v) => is_string($v) && !empty($v));
$destinationNodeAggregateIds = array_values($value);

return $contentRepository->handle(
SetNodeReferences::create(
$subject->subgraphIdentity->contentStreamId,
$subject->nodeAggregateId,
$subject->originDimensionSpacePoint,
ReferenceName::fromString($propertyName),
NodeReferencesToWrite::fromNodeAggregateIds(NodeAggregateIds::fromArray($destinationNodeAggregateIds))
)
);
}

private function handleHiddenPropertyChange(Node $subject, string $propertyName): CommandResult
{
$value = $this->nodePropertyConversionService->convert(
$this->getNodeType($subject),
$propertyName,
$this->getValue()
);

$contentRepository = $this->contentRepositoryRegistry->get($subject->subgraphIdentity->contentRepositoryId);

$command = EnableNodeAggregate::create(
$subject->subgraphIdentity->contentStreamId,
$subject->nodeAggregateId,
$subject->originDimensionSpacePoint->toDimensionSpacePoint(),
NodeVariantSelectionStrategy::STRATEGY_ALL_SPECIALIZATIONS
);

if ($value === true) {
$command = DisableNodeAggregate::create(
$subject->subgraphIdentity->contentStreamId,
$subject->nodeAggregateId,
$subject->originDimensionSpacePoint->toDimensionSpacePoint(),
NodeVariantSelectionStrategy::STRATEGY_ALL_SPECIALIZATIONS
);
}

return $contentRepository->handle($command);
}

private function handleNodeTypeChange(Node $subject, string $propertyName): CommandResult
{
$contentRepository = $this->contentRepositoryRegistry->get($subject->subgraphIdentity->contentRepositoryId);
$value = $this->nodePropertyConversionService->convert(
$this->getNodeType($subject),
$propertyName,
$this->getValue()
);

return $contentRepository->handle(
ChangeNodeAggregateType::create(
$subject->subgraphIdentity->contentStreamId,
$subject->nodeAggregateId,
NodeTypeName::fromString($value),
NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy::STRATEGY_DELETE
)
);
}

private function handlePropertyChange(Node $subject, string $propertyName): CommandResult
{
$contentRepository = $this->contentRepositoryRegistry->get($subject->subgraphIdentity->contentRepositoryId);
$value = $this->nodePropertyConversionService->convert(
$this->getNodeType($subject),
$propertyName,
$this->getValue()
);

$originDimensionSpacePoint = $subject->originDimensionSpacePoint;
if (!$subject->subgraphIdentity->dimensionSpacePoint->equals($originDimensionSpacePoint)) {
$originDimensionSpacePoint = OriginDimensionSpacePoint::fromDimensionSpacePoint($subject->subgraphIdentity->dimensionSpacePoint);
// if origin dimension space point != current DSP -> translate transparently (matching old behavior)
$contentRepository->handle(
CreateNodeVariant::create(
$subject->subgraphIdentity->contentStreamId,
$subject->nodeAggregateId,
$subject->originDimensionSpacePoint,
$originDimensionSpacePoint
)
)->block();
}

return $contentRepository->handle(
SetNodeProperties::create(
$subject->subgraphIdentity->contentStreamId,
$subject->nodeAggregateId,
$originDimensionSpacePoint,
PropertyValuesToWrite::fromArray(
[
$propertyName => $value
]
)
)
);
}
}
2 changes: 0 additions & 2 deletions Classes/Domain/Service/NodePropertyConverterService.php
Expand Up @@ -145,8 +145,6 @@ public function getProperty(Node $node, $propertyName)

return $this->toNodeIdentifierStrings($references);
// Here, the normal property access logic starts.
} elseif ($propertyName[0] === '_' && $propertyName !== '_hiddenInIndex') {
$propertyValue = ObjectAccess::getProperty($node, ltrim($propertyName, '_'));
} else {
$propertyValue = $node->getProperty($propertyName);
}
Expand Down