$records * @param Collection $edges * */ public function __construct( public Collection $records, public Collection $edges, public Collection $parentEdges, public QueryOptions $queryOptions, public ?int $total = null, ) { } /** * @return Collection * */ 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; } }