Files
lucent-laravel/src/Query/Graph.php
T

108 lines
3.1 KiB
PHP

<?php
namespace Lucent\Query;
use Lucent\Edge\Edge;
use Lucent\Primitive\Collection;
use Lucent\Record\QueryRecord;
final class Graph
{
/**
* @param Collection<QueryRecord> $records
* @param Collection<Edge> $edges
* */
public function __construct(
public Collection $records,
public Collection $edges,
public Collection $parentEdges,
public QueryOptions $queryOptions,
public ?int $total = null,
)
{
}
/**
* @return Collection<QueryRecord>
* */
public function getRootRecords(): Collection
{
return $this->records->where("isRoot", true)->values();
}
public function hasResults(): bool
{
return !empty($this->records);
}
public function tree(): Collection
{
return $this->getRootRecords()
->map(fn($r) => $this->findParents($r))
->map(fn($r) => $this->findChildren($r));
}
public function findChildren(QueryRecord $record, int $depth = 1): QueryRecord
{
if ($this->queryOptions->childrenDepth < $depth) {
return $record;
}
$recordEdges = $this->edges
->filter(fn(Edge $ed) => $ed->source === $record->id)
->unique(fn(Edge $ed) => $ed->field . $ed->target . $ed->source)
->sort(fn($a, $b) => $a->rank <=> $b->rank)->values();
$groupRecordEdges = [];
foreach ($recordEdges as $element) {
$groupRecordEdges[$element->field][] = $element;
}
$children = [];
foreach ($groupRecordEdges as $field => $edges) {
$children[$field] = [];
foreach ($edges as $anEdge) {
$aRecord = $this->records->filter(fn(QueryRecord $rec) => $rec->id == $anEdge->target)->values();
if (empty($aRecord[0])) {
continue;
}
$children[$field][] = $this->findChildren($aRecord[0], $depth + 1);
}
}
$record->_children = $children;
return $record;
}
public function findParents(QueryRecord $record, int $depth = 1): QueryRecord
{
if ($this->queryOptions->parentsDepth < $depth) {
return $record;
}
$recordEdges = $this->parentEdges->filter(fn(Edge $ed) => $ed->target === $record->id)->where("depth", $depth)->values()->sort(fn($a, $b) => $a->rank <=> $b->rank)->values();
$groupRecordEdges = [];
foreach ($recordEdges as $element) {
$groupRecordEdges[$element->field][] = $element;
}
$parents = [];
foreach ($groupRecordEdges as $field => $edges) {
$parents[$field] = [];
foreach ($edges as $anEdge) {
$aRecord = $this->records->filter(fn(QueryRecord $rec) => $rec->id == $anEdge->source)->values();
if (empty($aRecord[0])) {
continue;
}
$parents[$field][] = $this->findParents($aRecord[0], $depth + 1);
}
}
$record->_parents = $parents;
return $record;
}
}