-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
FEATURE: Create query endpoints for node tree
- Loading branch information
Showing
16 changed files
with
1,002 additions
and
0 deletions.
There are no files selected for viewing
42 changes: 42 additions & 0 deletions
42
Classes/Application/GetChildrenForTreeNode/Controller/GetChildrenForTreeNodeController.php
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,42 @@ | ||
<?php | ||
|
||
/* | ||
* This script belongs to the package "Sitegeist.Archaeopteryx". | ||
* | ||
* 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. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Sitegeist\Archaeopteryx\Application\GetChildrenForTreeNode\Controller; | ||
|
||
use Neos\Flow\Annotations as Flow; | ||
use Neos\Flow\Mvc\ActionRequest; | ||
use Neos\Flow\Mvc\ActionResponse; | ||
use Neos\Flow\Mvc\Controller\ControllerInterface; | ||
use Sitegeist\Archaeopteryx\Application\GetChildrenForTreeNode\GetChildrenForTreeNodeQuery; | ||
use Sitegeist\Archaeopteryx\Application\GetChildrenForTreeNode\GetChildrenForTreeNodeQueryHandler; | ||
|
||
#[Flow\Scope("singleton")] | ||
final class GetChildrenForTreeNodeController implements ControllerInterface | ||
{ | ||
#[Flow\Inject] | ||
protected GetChildrenForTreeNodeQueryHandler $queryHandler; | ||
|
||
public function processRequest(ActionRequest $request, ActionResponse $response) | ||
{ | ||
$request->setDispatched(true); | ||
|
||
$query = $request->getArguments(); | ||
$query = GetChildrenForTreeNodeQuery::fromArray($query); | ||
|
||
$queryResult = $this->queryHandler->handle($query); | ||
|
||
$response->setContentType('application/json'); | ||
$response->setContent(json_encode([ | ||
'success' => $queryResult | ||
], JSON_THROW_ON_ERROR)); | ||
} | ||
} |
80 changes: 80 additions & 0 deletions
80
Classes/Application/GetChildrenForTreeNode/GetChildrenForTreeNodeQuery.php
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,80 @@ | ||
<?php | ||
|
||
/* | ||
* This script belongs to the package "Sitegeist.Archaeopteryx". | ||
* | ||
* 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. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Sitegeist\Archaeopteryx\Application\GetChildrenForTreeNode; | ||
|
||
use Neos\ContentRepository\Domain\NodeAggregate\NodeAggregateIdentifier; | ||
use Neos\ContentRepository\Domain\NodeType\NodeTypeName; | ||
use Neos\Flow\Annotations as Flow; | ||
|
||
/** | ||
* @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 string $nodeTypeFilter, | ||
) { | ||
} | ||
|
||
/** | ||
* @param array<string,mixed> $array | ||
*/ | ||
public static function fromArray(array $array): self | ||
{ | ||
isset($array['workspaceName']) | ||
or throw new \Exception('Workspace name must be set'); | ||
is_string($array['workspaceName']) | ||
or throw new \Exception('Workspace name must be a string'); | ||
|
||
isset($array['dimensionValues']) | ||
or throw new \Exception('Dimension values must be set'); | ||
is_array($array['dimensionValues']) | ||
or throw new \Exception('Dimension values must be an array'); | ||
|
||
isset($array['treeNodeId']) | ||
or throw new \Exception('Tree node id must be set'); | ||
is_string($array['treeNodeId']) | ||
or throw new \Exception('Tree node id must be a string'); | ||
|
||
!isset($array['nodeTypeFilter']) or is_string($array['nodeTypeFilter']) | ||
or throw new \Exception('Node type filter must be a string'); | ||
|
||
return new self( | ||
workspaceName: $array['workspaceName'], | ||
dimensionValues: $array['dimensionValues'], | ||
treeNodeId: NodeAggregateIdentifier::fromString($array['treeNodeId']), | ||
nodeTypeFilter: $array['nodeTypeFilter'] ?? '', | ||
); | ||
} | ||
|
||
/** | ||
* @return array<string,string> | ||
*/ | ||
public function getTargetDimensionValues(): array | ||
{ | ||
$result = []; | ||
|
||
foreach ($this->dimensionValues as $dimensionName => $fallbackChain) { | ||
$result[$dimensionName] = $fallbackChain[0] ?? ''; | ||
} | ||
|
||
return $result; | ||
} | ||
} |
107 changes: 107 additions & 0 deletions
107
Classes/Application/GetChildrenForTreeNode/GetChildrenForTreeNodeQueryHandler.php
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,107 @@ | ||
<?php | ||
|
||
/* | ||
* This script belongs to the package "Sitegeist.Archaeopteryx". | ||
* | ||
* 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. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Sitegeist\Archaeopteryx\Application\GetChildrenForTreeNode; | ||
|
||
use GuzzleHttp\Psr7\Uri; | ||
use Neos\ContentRepository\Domain\Model\Node; | ||
use Neos\ContentRepository\Domain\Model\NodeType; | ||
use Neos\ContentRepository\Domain\NodeType\NodeTypeName; | ||
use Neos\ContentRepository\Domain\Service\NodeTypeManager; | ||
use Neos\Flow\Annotations as Flow; | ||
use Neos\Neos\Domain\Service\ContentContextFactory; | ||
use Sitegeist\Archaeopteryx\Application\Shared\NodeTypeFilterOptions; | ||
use Sitegeist\Archaeopteryx\Application\Shared\TreeNode; | ||
use Sitegeist\Archaeopteryx\Application\Shared\TreeNodes; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
#[Flow\Scope("singleton")] | ||
final class GetChildrenForTreeNodeQueryHandler | ||
{ | ||
#[Flow\Inject] | ||
protected ContentContextFactory $contentContextFactory; | ||
|
||
#[Flow\Inject] | ||
protected NodeTypeManager $nodeTypeManager; | ||
|
||
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 | ||
]); | ||
|
||
$node = $contentContext->getNodeByIdentifier((string) $query->treeNodeId); | ||
if (!$node instanceof Node) { | ||
throw new \Exception('Forget it!'); | ||
} | ||
|
||
return new GetChildrenForTreeNodeQueryResult( | ||
children: $children = $this->createTreeNodesFromChildrenOfNode($node, $query), | ||
additionalNodeTypeFilterOptions: NodeTypeFilterOptions::fromTreeNodes($children, $this->nodeTypeManager) | ||
); | ||
} | ||
|
||
private function createTreeNodesFromChildrenOfNode(Node $node, GetChildrenForTreeNodeQuery $query): TreeNodes | ||
{ | ||
$items = []; | ||
|
||
foreach ($node->getChildNodes($query->nodeTypeFilter) as $childNode) { | ||
/** @var Node $childNode */ | ||
$items[] = $this->createTreeNodeFromNode($childNode, $query); | ||
} | ||
|
||
return new TreeNodes(...$items); | ||
} | ||
|
||
private function createTreeNodeFromNode(Node $node, GetChildrenForTreeNodeQuery $query): TreeNode | ||
{ | ||
return new TreeNode( | ||
nodeAggregateIdentifier: $node->getNodeAggregateIdentifier(), | ||
uri: new Uri('node://' . $node->getNodeAggregateIdentifier()), | ||
icon: $node->getNodeType()->getConfiguration('ui.icon'), | ||
label: $node->getLabel(), | ||
isMatchedByFilter: true, | ||
isDisabled: $node->isHidden(), | ||
isHiddenInMenu: $node->isHiddenInIndex(), | ||
hasScheduledDisabledState: | ||
$node->getHiddenBeforeDateTime() !== null | ||
|| $node->getHiddenAfterDateTime() !== null, | ||
hasUnloadedChildren: $node->getNumberOfChildNodes($query->nodeTypeFilter) > 0, | ||
nodeTypeNames: iterator_to_array( | ||
$this->getAllNonAbstractSuperTypesOf($node->getNodeType()), | ||
false | ||
), | ||
children: new TreeNodes(), | ||
); | ||
} | ||
|
||
/** | ||
* @return \Traversable<int,NodeTypeName> | ||
*/ | ||
private function getAllNonAbstractSuperTypesOf(NodeType $nodeType): \Traversable | ||
{ | ||
if (!$nodeType->isAbstract()) { | ||
yield NodeTypeName::fromString($nodeType->getName()); | ||
} | ||
|
||
foreach ($nodeType->getDeclaredSuperTypes() as $superType) { | ||
yield from $this->getAllNonAbstractSuperTypesOf($superType); | ||
} | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
Classes/Application/GetChildrenForTreeNode/GetChildrenForTreeNodeQueryResult.php
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,35 @@ | ||
<?php | ||
|
||
/* | ||
* This script belongs to the package "Sitegeist.Archaeopteryx". | ||
* | ||
* 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. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Sitegeist\Archaeopteryx\Application\GetChildrenForTreeNode; | ||
|
||
use Neos\Flow\Annotations as Flow; | ||
use Sitegeist\Archaeopteryx\Application\Shared\NodeTypeFilterOptions; | ||
use Sitegeist\Archaeopteryx\Application\Shared\TreeNodes; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
#[Flow\Proxy(false)] | ||
final class GetChildrenForTreeNodeQueryResult implements \JsonSerializable | ||
{ | ||
public function __construct( | ||
public readonly TreeNodes $children, | ||
public readonly NodeTypeFilterOptions $additionalNodeTypeFilterOptions, | ||
) { | ||
} | ||
|
||
public function jsonSerialize(): mixed | ||
{ | ||
return get_object_vars($this); | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
Classes/Application/GetTree/Controller/GetTreeController.php
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,42 @@ | ||
<?php | ||
|
||
/* | ||
* This script belongs to the package "Sitegeist.Archaeopteryx". | ||
* | ||
* 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. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Sitegeist\Archaeopteryx\Application\GetTree\Controller; | ||
|
||
use Neos\Flow\Annotations as Flow; | ||
use Neos\Flow\Mvc\ActionRequest; | ||
use Neos\Flow\Mvc\ActionResponse; | ||
use Neos\Flow\Mvc\Controller\ControllerInterface; | ||
use Sitegeist\Archaeopteryx\Application\GetTree\GetTreeQuery; | ||
use Sitegeist\Archaeopteryx\Application\GetTree\GetTreeQueryHandler; | ||
|
||
#[Flow\Scope("singleton")] | ||
final class GetTreeController implements ControllerInterface | ||
{ | ||
#[Flow\Inject] | ||
protected GetTreeQueryHandler $queryHandler; | ||
|
||
public function processRequest(ActionRequest $request, ActionResponse $response) | ||
{ | ||
$request->setDispatched(true); | ||
|
||
$query = $request->getArguments(); | ||
$query = GetTreeQuery::fromArray($query); | ||
|
||
$queryResult = $this->queryHandler->handle($query); | ||
|
||
$response->setContentType('application/json'); | ||
$response->setContent(json_encode([ | ||
'success' => $queryResult | ||
], JSON_THROW_ON_ERROR)); | ||
} | ||
} |
Oops, something went wrong.