Skip to content

Commit

Permalink
Merge pull request #5157 from mhsdesign/task/5102-use-collection-valu…
Browse files Browse the repository at this point in the history
…e-objects-in-content-graph

TASK: Use collection value objects in content graph instead of `iterable`
  • Loading branch information
mhsdesign authored Jul 8, 2024
2 parents 121791e + 6503744 commit 071abba
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint;
use Neos\ContentRepository\Core\NodeType\NodeTypeManager;
use Neos\ContentRepository\Core\NodeType\NodeTypeName;
use Neos\ContentRepository\Core\NodeType\NodeTypeNames;
use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphInterface;
use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphWithRuntimeCaches\ContentSubgraphWithRuntimeCaches;
use Neos\ContentRepository\Core\Projection\ContentGraph\ContentSubgraphInterface;
Expand Down Expand Up @@ -132,6 +133,9 @@ public function findRootNodeAggregateByType(
foreach ($rootNodeAggregates as $rootNodeAggregate) {
$ids[] = $rootNodeAggregate->nodeAggregateId->value;
}

// We throw if multiple root node aggregates of the given $nodeTypeName were found,
// as this would lead to nondeterministic results. Must not happen.
throw new \RuntimeException(sprintf(
'More than one root node aggregate of type "%s" found (IDs: %s).',
$nodeTypeName->value,
Expand All @@ -151,12 +155,12 @@ public function findRootNodeAggregates(
FindRootNodeAggregatesFilter $filter,
): NodeAggregates {
$rootNodeAggregateQueryBuilder = $this->nodeQueryBuilder->buildFindRootNodeAggregatesQuery($this->contentStreamId, $filter);
return NodeAggregates::fromArray(iterator_to_array($this->mapQueryBuilderToNodeAggregates($rootNodeAggregateQueryBuilder)));
return $this->mapQueryBuilderToNodeAggregates($rootNodeAggregateQueryBuilder);
}

public function findNodeAggregatesByType(
NodeTypeName $nodeTypeName
): iterable {
): NodeAggregates {
$queryBuilder = $this->nodeQueryBuilder->buildBasicNodeAggregateQuery();
$queryBuilder
->andWhere('n.nodetypename = :nodeTypeName')
Expand Down Expand Up @@ -190,12 +194,10 @@ public function findNodeAggregateById(
* Parent node aggregates can have a greater dimension space coverage than the given child.
* Thus, it is not enough to just resolve them from the nodes and edges connected to the given child node aggregate.
* Instead, we resolve all parent node aggregate ids instead and fetch the complete aggregates from there.
*
* @return iterable<NodeAggregate>
*/
public function findParentNodeAggregates(
NodeAggregateId $childNodeAggregateId
): iterable {
): NodeAggregates {
$queryBuilder = $this->nodeQueryBuilder->buildBasicNodeAggregateQuery()
->innerJoin('n', $this->nodeQueryBuilder->tableNames->hierarchyRelation(), 'ch', 'ch.parentnodeanchor = n.relationanchorpoint')
->innerJoin('ch', $this->nodeQueryBuilder->tableNames->node(), 'cn', 'cn.relationanchorpoint = ch.childnodeanchor')
Expand All @@ -209,12 +211,9 @@ public function findParentNodeAggregates(
return $this->mapQueryBuilderToNodeAggregates($queryBuilder);
}

/**
* @return iterable<NodeAggregate>
*/
public function findChildNodeAggregates(
NodeAggregateId $parentNodeAggregateId
): iterable {
): NodeAggregates {
$queryBuilder = $this->nodeQueryBuilder->buildChildNodeAggregateQuery($parentNodeAggregateId, $this->contentStreamId);
return $this->mapQueryBuilderToNodeAggregates($queryBuilder);
}
Expand Down Expand Up @@ -252,7 +251,7 @@ public function findParentNodeAggregateByChildOriginDimensionSpacePoint(NodeAggr
);
}

public function findTetheredChildNodeAggregates(NodeAggregateId $parentNodeAggregateId): iterable
public function findTetheredChildNodeAggregates(NodeAggregateId $parentNodeAggregateId): NodeAggregates
{
$queryBuilder = $this->nodeQueryBuilder->buildChildNodeAggregateQuery($parentNodeAggregateId, $this->contentStreamId)
->andWhere('cn.classification = :tetheredClassification')
Expand Down Expand Up @@ -319,12 +318,12 @@ public function countNodes(): int
}
}

public function findUsedNodeTypeNames(): iterable
public function findUsedNodeTypeNames(): NodeTypeNames
{
return array_map(
return NodeTypeNames::fromArray(array_map(
static fn (array $row) => NodeTypeName::fromString($row['nodetypename']),
$this->fetchRows($this->nodeQueryBuilder->buildFindUsedNodeTypeNamesQuery())
);
));
}

private function createQueryBuilder(): QueryBuilder
Expand All @@ -344,9 +343,8 @@ private function mapQueryBuilderToNodeAggregate(QueryBuilder $queryBuilder): ?No

/**
* @param QueryBuilder $queryBuilder
* @return iterable<NodeAggregate>
*/
private function mapQueryBuilderToNodeAggregates(QueryBuilder $queryBuilder): iterable
private function mapQueryBuilderToNodeAggregates(QueryBuilder $queryBuilder): NodeAggregates
{
return $this->nodeFactory->mapNodeRowsToNodeAggregates(
$this->fetchRows($queryBuilder),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
use Neos\ContentRepository\Core\Projection\ContentGraph\DimensionSpacePointsBySubtreeTags;
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate;
use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregates;
use Neos\ContentRepository\Core\Projection\ContentGraph\Nodes;
use Neos\ContentRepository\Core\Projection\ContentGraph\NodeTags;
use Neos\ContentRepository\Core\Projection\ContentGraph\OriginByCoverage;
Expand Down Expand Up @@ -233,16 +234,21 @@ public function mapNodeRowsToNodeAggregate(
}

/**
* @param iterable<int,array<string,string>> $nodeRows
* @return iterable<int,NodeAggregate>
* @param array<int,array<string,string>> $nodeRows
* @throws NodeTypeNotFound
*/
public function mapNodeRowsToNodeAggregates(
iterable $nodeRows,
array $nodeRows,
WorkspaceName $workspaceName,
ContentStreamId $contentStreamId,
VisibilityConstraints $visibilityConstraints
): iterable {
): NodeAggregates {
if (empty($nodeRows)) {
return NodeAggregates::createEmpty();
}

$nodeAggregates = [];

$nodeTypeNames = [];
$nodeNames = [];
$occupiedDimensionSpacePointsByNodeAggregate = [];
Expand Down Expand Up @@ -308,7 +314,7 @@ public function mapNodeRowsToNodeAggregates(

foreach ($nodesByOccupiedDimensionSpacePointsByNodeAggregate as $rawNodeAggregateId => $nodes) {
/** @var string $rawNodeAggregateId */
yield NodeAggregate::create(
$nodeAggregates[] = NodeAggregate::create(
$this->contentRepositoryId,
$workspaceName,
NodeAggregateId::fromString($rawNodeAggregateId),
Expand All @@ -334,6 +340,8 @@ public function mapNodeRowsToNodeAggregates(
$contentStreamId,
);
}

return NodeAggregates::fromArray($nodeAggregates);
}

public static function extractNodeTagsFromJson(string $subtreeTagsJson): NodeTags
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint;
use Neos\ContentRepository\Core\NodeType\NodeTypeManager;
use Neos\ContentRepository\Core\NodeType\NodeTypeName;
use Neos\ContentRepository\Core\NodeType\NodeTypeNames;
use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphInterface;
use Neos\ContentRepository\Core\Projection\ContentGraph\ContentSubgraphInterface;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindRootNodeAggregatesFilter;
Expand Down Expand Up @@ -127,13 +128,10 @@ public function findRootNodeAggregates(
throw new \BadMethodCallException('method findRootNodeAggregates is not implemented yet.', 1645782874);
}

/**
* @return \Iterator<int,NodeAggregate>
*/
public function findNodeAggregatesByType(
NodeTypeName $nodeTypeName
): \Iterator {
return new \Generator();
): NodeAggregates {
return NodeAggregates::createEmpty();
}

public function findNodeAggregateById(
Expand Down Expand Up @@ -188,12 +186,9 @@ public function findParentNodeAggregateByChildOriginDimensionSpacePoint(
);
}

/**
* @return iterable<NodeAggregate>
*/
public function findParentNodeAggregates(
NodeAggregateId $childNodeAggregateId
): iterable {
): NodeAggregates {
$query = HypergraphParentQuery::create($this->contentStreamId, $this->tableNamePrefix);
$query = $query->withChildNodeAggregateId($childNodeAggregateId);

Expand All @@ -205,12 +200,9 @@ public function findParentNodeAggregates(
);
}

/**
* @return iterable<NodeAggregate>
*/
public function findChildNodeAggregates(
NodeAggregateId $parentNodeAggregateId
): iterable {
): NodeAggregates {
$query = HypergraphChildQuery::create(
$this->contentStreamId,
$parentNodeAggregateId,
Expand Down Expand Up @@ -244,12 +236,9 @@ public function findChildNodeAggregateByName(
);
}

/**
* @return iterable<NodeAggregate>
*/
public function findTetheredChildNodeAggregates(
NodeAggregateId $parentNodeAggregateId
): iterable {
): NodeAggregates {
$query = HypergraphChildQuery::create(
$this->contentStreamId,
$parentNodeAggregateId,
Expand Down Expand Up @@ -298,12 +287,9 @@ public function countNodes(): int
return $this->dbal->executeQuery($query)->fetchOne();
}

/**
* @return iterable<int,NodeTypeName>
*/
public function findUsedNodeTypeNames(): iterable
public function findUsedNodeTypeNames(): NodeTypeNames
{
return [];
return NodeTypeNames::createEmpty();
}

public function getContentStreamId(): ContentStreamId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
use Neos\ContentRepository\Core\Projection\ContentGraph\DimensionSpacePointsBySubtreeTags;
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate;
use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregates;
use Neos\ContentRepository\Core\Projection\ContentGraph\Nodes;
use Neos\ContentRepository\Core\Projection\ContentGraph\NodeTags;
use Neos\ContentRepository\Core\Projection\ContentGraph\OriginByCoverage;
Expand Down Expand Up @@ -252,15 +253,15 @@ public function mapNodeRowsToNodeAggregate(

/**
* @param array<int,array<string,mixed>> $nodeRows
* @return iterable<int,\Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate>
*/
public function mapNodeRowsToNodeAggregates(array $nodeRows, VisibilityConstraints $visibilityConstraints): iterable
public function mapNodeRowsToNodeAggregates(array $nodeRows, VisibilityConstraints $visibilityConstraints): NodeAggregates
{
$nodeAggregates = [];
if (empty($nodeRows)) {
return $nodeAggregates;
return NodeAggregates::createEmpty();
}

$nodeAggregates = [];

$contentStreamId = null;
/** @var NodeAggregateId[] $nodeAggregateIds */
$nodeAggregateIds = [];
Expand Down Expand Up @@ -330,7 +331,7 @@ public function mapNodeRowsToNodeAggregates(array $nodeRows, VisibilityConstrain
}

foreach ($nodeAggregateIds as $key => $nodeAggregateId) {
yield NodeAggregate::create(
$nodeAggregates[] = NodeAggregate::create(
$this->contentRepositoryId,
WorkspaceName::fromString('missing'), // todo
$nodeAggregateId,
Expand All @@ -348,6 +349,8 @@ public function mapNodeRowsToNodeAggregates(array $nodeRows, VisibilityConstrain
$contentStreamId,
);
}

return NodeAggregates::fromArray($nodeAggregates);
}

private static function parseDateTimeString(string $string): \DateTimeImmutable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet;
use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint;
use Neos\ContentRepository\Core\NodeType\NodeTypeName;
use Neos\ContentRepository\Core\NodeType\NodeTypeNames;
use Neos\ContentRepository\Core\Projection\ProjectionStateInterface;
use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId;
use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregatesTypeIsAmbiguous;
Expand Down Expand Up @@ -58,11 +59,7 @@ public function getSubgraph(
): ContentSubgraphInterface;

/**
* Throws exception if no root aggregate found, because a Content Repository needs at least
* one root node to function.
*
* Also throws exceptions if multiple root node aggregates of the given $nodeTypeName were found,
* as this would lead to nondeterministic results in your code.
* Throws exception if no root aggregate of the given type found.
*
* @throws RootNodeAggregateDoesNotExist
* @api
Expand All @@ -79,12 +76,11 @@ public function findRootNodeAggregates(
): NodeAggregates;

/**
* @return iterable<NodeAggregate>
* @api
*/
public function findNodeAggregatesByType(
NodeTypeName $nodeTypeName
): iterable;
): NodeAggregates;

/**
* @throws NodeAggregatesTypeIsAmbiguous
Expand All @@ -97,10 +93,9 @@ public function findNodeAggregateById(
/**
* Returns all node types in use, from the graph projection
*
* @return iterable<NodeTypeName>
* @api
*/
public function findUsedNodeTypeNames(): iterable;
public function findUsedNodeTypeNames(): NodeTypeNames;

/**
* @internal only for consumption inside the Command Handler
Expand All @@ -111,20 +106,18 @@ public function findParentNodeAggregateByChildOriginDimensionSpacePoint(
): ?NodeAggregate;

/**
* @return iterable<NodeAggregate>
* @internal only for consumption inside the Command Handler
*/
public function findParentNodeAggregates(
NodeAggregateId $childNodeAggregateId
): iterable;
): NodeAggregates;

/**
* @return iterable<NodeAggregate>
* @internal only for consumption inside the Command Handler
*/
public function findChildNodeAggregates(
NodeAggregateId $parentNodeAggregateId
): iterable;
): NodeAggregates;

/**
* A node aggregate can have no or exactly one child node aggregate with a given name as enforced by constraint checks
Expand All @@ -137,12 +130,11 @@ public function findChildNodeAggregateByName(
): ?NodeAggregate;

/**
* @return iterable<NodeAggregate>
* @internal only for consumption inside the Command Handler
*/
public function findTetheredChildNodeAggregates(
NodeAggregateId $parentNodeAggregateId
): iterable;
): NodeAggregates;

/**
* @internal only for consumption inside the Command Handler
Expand Down

0 comments on commit 071abba

Please sign in to comment.