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

WIP: Make Queries work with ESCR (Neos 9.0 compatibility) #64

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,24 @@

namespace Sitegeist\Archaeopteryx\Application\GetChildrenForTreeNode;

use Neos\ContentRepository\Domain\NodeAggregate\NodeAggregateIdentifier;
use Neos\ContentRepository\Domain\NodeType\NodeTypeName;
use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint;
use Neos\ContentRepository\Core\NodeType\NodeTypeNames;
use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId;
use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId;
use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName;
use Neos\Flow\Annotations as Flow;
use Sitegeist\Archaeopteryx\Application\Shared\NodeTypeNames;

/**
* @internal
*/
#[Flow\Proxy(false)]
final class GetChildrenForTreeNodeQuery
{
/**
* @param array<string,array<int,string>> $dimensionValues
*/
public function __construct(
public readonly string $workspaceName,
public readonly array $dimensionValues,
public readonly NodeAggregateIdentifier $treeNodeId,
public readonly ContentRepositoryId $contentRepositoryId,
public readonly WorkspaceName $workspaceName,
public readonly DimensionSpacePoint $dimensionSpacePoint,
public readonly NodeAggregateId $treeNodeId,
public readonly string $nodeTypeFilter,
public readonly NodeTypeNames $linkableNodeTypes,
) {
Expand All @@ -40,6 +40,11 @@ public function __construct(
*/
public static function fromArray(array $array): self
{
isset($array['contentRepositoryId'])
or throw new \InvalidArgumentException('Content Repository Id must be set');
is_string($array['contentRepositoryId'])
or throw new \InvalidArgumentException('Content Repository Id must be a string');

isset($array['workspaceName'])
or throw new \InvalidArgumentException('Workspace name must be set');
is_string($array['workspaceName'])
Expand All @@ -62,25 +67,12 @@ public static function fromArray(array $array): self
or throw new \InvalidArgumentException('Linkable node types must be an array');

return new self(
workspaceName: $array['workspaceName'],
dimensionValues: $array['dimensionValues'],
treeNodeId: NodeAggregateIdentifier::fromString($array['treeNodeId']),
contentRepositoryId: ContentRepositoryId::fromString($array['contentRepositoryId']),
workspaceName: WorkspaceName::fromString($array['workspaceName']),
dimensionSpacePoint: DimensionSpacePoint::fromLegacyDimensionArray($array['dimensionValues']),
treeNodeId: NodeAggregateId::fromString($array['treeNodeId']),
nodeTypeFilter: $array['nodeTypeFilter'] ?? '',
linkableNodeTypes: NodeTypeNames::fromArray($array['linkableNodeTypes'] ?? []),
);
}

/**
* @return array<string,string>
*/
public function getTargetDimensionValues(): array
{
$result = [];

foreach ($this->dimensionValues as $dimensionName => $fallbackChain) {
$result[$dimensionName] = $fallbackChain[0] ?? '';
}

return $result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@

namespace Sitegeist\Archaeopteryx\Application\GetChildrenForTreeNode;

use Neos\ContentRepository\Domain\Model\Node;
use Neos\ContentRepository\Domain\Service\NodeTypeManager;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\NodeType\NodeTypeCriteria;
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
use Neos\Flow\Annotations as Flow;
use Neos\Neos\Domain\Service\ContentContextFactory;
use Sitegeist\Archaeopteryx\Application\Shared\NodeWasNotFound;
use Sitegeist\Archaeopteryx\Application\Shared\TreeNodeBuilder;
use Sitegeist\Archaeopteryx\Application\Shared\TreeNodes;
use Sitegeist\Archaeopteryx\Infrastructure\ContentRepository\NodeTypeFilter;
use Sitegeist\Archaeopteryx\Infrastructure\ESCR\NodeService;
use Sitegeist\Archaeopteryx\Infrastructure\ESCR\NodeServiceFactory;
use Sitegeist\Archaeopteryx\Infrastructure\ESCR\NodeTypeService;
use Sitegeist\Archaeopteryx\Infrastructure\ESCR\NodeTypeServiceFactory;

/**
* @internal
Expand All @@ -28,50 +28,44 @@
final class GetChildrenForTreeNodeQueryHandler
{
#[Flow\Inject]
protected ContentContextFactory $contentContextFactory;
protected NodeServiceFactory $nodeServiceFactory;

#[Flow\Inject]
protected NodeTypeManager $nodeTypeManager;
protected NodeTypeServiceFactory $nodeTypeServiceFactory;

public function handle(GetChildrenForTreeNodeQuery $query): GetChildrenForTreeNodeQueryResult
{
$contentContext = $this->contentContextFactory->create([
'workspaceName' => $query->workspaceName,
'dimensions' => $query->dimensionValues,
'targetDimensions' => $query->getTargetDimensionValues(),
'invisibleContentShown' => true,
'removedContentShown' => false,
'inaccessibleContentShown' => true
]);
$nodeService = $this->nodeServiceFactory->create(
contentRepositoryId: $query->contentRepositoryId,
workspaceName: $query->workspaceName,
dimensionSpacePoint: $query->dimensionSpacePoint,
);
$nodeTypeService = $this->nodeTypeServiceFactory->create(
contentRepositoryId: $query->contentRepositoryId,
);

$node = $contentContext->getNodeByIdentifier((string) $query->treeNodeId);
if (!$node instanceof Node) {
throw NodeWasNotFound::becauseNodeWithGivenIdentifierDoesNotExistInContext(
nodeAggregateIdentifier: $query->treeNodeId,
contentContext: $contentContext,
);
}
$node = $nodeService->requireNodeById($query->treeNodeId);

return new GetChildrenForTreeNodeQueryResult(
children: $this->createTreeNodesFromChildrenOfNode($node, $query),
children: $this->createTreeNodesFromChildrenOfNode($nodeService, $nodeTypeService, $node, $query),
);
}

private function createTreeNodesFromChildrenOfNode(Node $node, GetChildrenForTreeNodeQuery $query): TreeNodes
private function createTreeNodesFromChildrenOfNode(NodeService $nodeService, NodeTypeService $nodeTypeService, Node $node, GetChildrenForTreeNodeQuery $query): TreeNodes
{
$linkableNodeTypesFilter = NodeTypeFilter::fromNodeTypeNames(
nodeTypeNames: $query->linkableNodeTypes,
nodeTypeManager: $this->nodeTypeManager
$linkableNodeTypesFilter = $nodeTypeService->createNodeTypeFilterFromNodeTypeNames(
nodeTypeNames: $query->linkableNodeTypes
);

$items = [];
$nodeTypeCriteria = NodeTypeCriteria::fromFilterString($query->nodeTypeFilter);

foreach ($node->getChildNodes($query->nodeTypeFilter) as $childNode) {
foreach ($nodeService->findChildNodes($node, $nodeTypeCriteria) as $childNode) {
/** @var Node $childNode */
$items[] = TreeNodeBuilder::forNode($childNode)
$items[] = $nodeService->createTreeNodeBuilderForNode($childNode)
->setIsMatchedByFilter(true)
->setIsLinkable($linkableNodeTypesFilter->isSatisfiedByNode($childNode))
->setHasUnloadedChildren($childNode->getNumberOfChildNodes($query->nodeTypeFilter) > 0)
->setHasUnloadedChildren($nodeService->getNumberOfChildNodes($childNode, $nodeTypeCriteria) > 0)
->build();
}

Expand Down
41 changes: 17 additions & 24 deletions Classes/Application/GetNodeSummary/GetNodeSummaryQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@

namespace Sitegeist\Archaeopteryx\Application\GetNodeSummary;

use Neos\ContentRepository\Domain\NodeAggregate\NodeAggregateIdentifier;
use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint;
use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId;
use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId;
use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName;
use Neos\Flow\Annotations as Flow;

/**
Expand All @@ -21,13 +24,11 @@
#[Flow\Proxy(false)]
final class GetNodeSummaryQuery
{
/**
* @param array<string,array<int,string>> $dimensionValues
*/
public function __construct(
public readonly string $workspaceName,
public readonly array $dimensionValues,
public readonly NodeAggregateIdentifier $nodeId,
public readonly ContentRepositoryId $contentRepositoryId,
public readonly WorkspaceName $workspaceName,
public readonly DimensionSpacePoint $dimensionSpacePoint,
public readonly NodeAggregateId $nodeId,
) {
}

Expand All @@ -36,6 +37,11 @@ public function __construct(
*/
public static function fromArray(array $array): self
{
isset($array['contentRepositoryId'])
or throw new \InvalidArgumentException('Content Repository Id must be set');
is_string($array['contentRepositoryId'])
or throw new \InvalidArgumentException('Content Repository Id must be a string');

isset($array['workspaceName'])
or throw new \InvalidArgumentException('Workspace name must be set');
is_string($array['workspaceName'])
Expand All @@ -52,23 +58,10 @@ public static function fromArray(array $array): self
or throw new \InvalidArgumentException('Node id must be a string');

return new self(
workspaceName: $array['workspaceName'],
dimensionValues: $array['dimensionValues'],
nodeId: NodeAggregateIdentifier::fromString($array['nodeId']),
contentRepositoryId: ContentRepositoryId::fromString($array['contentRepositoryId']),
workspaceName: WorkspaceName::fromString($array['workspaceName']),
dimensionSpacePoint: DimensionSpacePoint::fromLegacyDimensionArray($array['dimensionValues']),
nodeId: NodeAggregateId::fromString($array['nodeId']),
);
}

/**
* @return array<string,string>
*/
public function getTargetDimensionValues(): array
{
$result = [];

foreach ($this->dimensionValues as $dimensionName => $fallbackChain) {
$result[$dimensionName] = $fallbackChain[0] ?? '';
}

return $result;
}
}
56 changes: 23 additions & 33 deletions Classes/Application/GetNodeSummary/GetNodeSummaryQueryHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@
namespace Sitegeist\Archaeopteryx\Application\GetNodeSummary;

use GuzzleHttp\Psr7\Uri;
use Neos\ContentRepository\Domain\Model\Node;
use Neos\ContentRepository\Domain\Service\NodeTypeManager;
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
use Neos\Flow\Annotations as Flow;
use Neos\Neos\Domain\Service\ContentContextFactory;
use Sitegeist\Archaeopteryx\Application\Shared\NodeWasNotFound;
use Sitegeist\Archaeopteryx\Infrastructure\ESCR\NodeService;
use Sitegeist\Archaeopteryx\Infrastructure\ESCR\NodeServiceFactory;

/**
* @internal
Expand All @@ -26,46 +25,35 @@
final class GetNodeSummaryQueryHandler
{
#[Flow\Inject]
protected ContentContextFactory $contentContextFactory;

#[Flow\Inject]
protected NodeTypeManager $nodeTypeManager;
protected NodeServiceFactory $nodeServiceFactory;

public function handle(GetNodeSummaryQuery $query): GetNodeSummaryQueryResult
{
$contentContext = $this->contentContextFactory->create([
'workspaceName' => $query->workspaceName,
'dimensions' => $query->dimensionValues,
'targetDimensions' => $query->getTargetDimensionValues(),
'invisibleContentShown' => true,
'removedContentShown' => false,
'inaccessibleContentShown' => true
]);
$nodeService = $this->nodeServiceFactory->create(
contentRepositoryId: $query->contentRepositoryId,
workspaceName: $query->workspaceName,
dimensionSpacePoint: $query->dimensionSpacePoint,
);

$node = $contentContext->getNodeByIdentifier((string) $query->nodeId);
if (!$node instanceof Node) {
throw NodeWasNotFound::becauseNodeWithGivenIdentifierDoesNotExistInContext(
nodeAggregateIdentifier: $query->nodeId,
contentContext: $contentContext,
);
}
$node = $nodeService->requireNodeById($query->nodeId);
$nodeType = $nodeService->requireNodeTypeByName($node->nodeTypeName);

return new GetNodeSummaryQueryResult(
icon: $node->getNodeType()->getConfiguration('ui.icon'),
label: $node->getLabel(),
uri: new Uri('node://' . $node->getNodeAggregateIdentifier()),
breadcrumbs: $this->createBreadcrumbsForNode($node)
icon: $nodeType->getConfiguration('ui.icon'),
label: $nodeService->getLabelForNode($node),
uri: new Uri('node://' . $node->aggregateId->value),
breadcrumbs: $this->createBreadcrumbsForNode($nodeService, $node),
);
}

private function createBreadcrumbsForNode(Node $node): Breadcrumbs
private function createBreadcrumbsForNode(NodeService $nodeService, Node $node): Breadcrumbs
{
$items = [];

while ($node) {
/** @var Node $node */
$items[] = $this->createBreadcrumbForNode($node);
$node = $node->getParent();
$items[] = $this->createBreadcrumbForNode($nodeService, $node);
$node = $nodeService->findParentNode($node);
}

$items = array_slice($items, 0, -2);
Expand All @@ -74,11 +62,13 @@ private function createBreadcrumbsForNode(Node $node): Breadcrumbs
return new Breadcrumbs(...$items);
}

private function createBreadcrumbForNode(Node $node): Breadcrumb
private function createBreadcrumbForNode(NodeService $nodeService, Node $node): Breadcrumb
{
$nodeType = $nodeService->requireNodeTypeByName($node->nodeTypeName);

return new Breadcrumb(
icon: $node->getNodeType()->getConfiguration('ui.icon') ?? 'questionmark',
label: $node->getLabel(),
icon: $nodeType->getConfiguration('ui.icon') ?? 'questionmark',
label: $nodeService->getLabelForNode($node),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

namespace Sitegeist\Archaeopteryx\Application\GetNodeTypeFilterOptions;

use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\NodeType\NodeTypeCriteria;
use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId;
use Neos\Flow\Annotations as Flow;

/**
Expand All @@ -21,7 +23,8 @@
final class GetNodeTypeFilterOptionsQuery
{
public function __construct(
public readonly string $baseNodeTypeFilter,
public readonly ContentRepositoryId $contentRepositoryId,
public readonly NodeTypeCriteria $baseNodeTypeFilter,
) {
}

Expand All @@ -30,13 +33,19 @@ public function __construct(
*/
public static function fromArray(array $array): self
{
isset($array['contentRepositoryId'])
or throw new \InvalidArgumentException('Content Repository Id must be set');
is_string($array['contentRepositoryId'])
or throw new \InvalidArgumentException('Content Repository Id must be a string');

isset($array['baseNodeTypeFilter'])
or throw new \InvalidArgumentException('Base node type filter must be set');
is_string($array['baseNodeTypeFilter'])
or throw new \InvalidArgumentException('Base node type filter must be a string');

return new self(
baseNodeTypeFilter: $array['baseNodeTypeFilter'],
contentRepositoryId: ContentRepositoryId::fromString($array['contentRepositoryId']),
baseNodeTypeFilter: NodeTypeCriteria::fromFilterString($array['baseNodeTypeFilter']),
);
}
}
Loading
Loading