2023-10-02 23:10:49 +03:00
|
|
|
<?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,
|
2023-10-13 21:06:23 +03:00
|
|
|
public Collection $parentEdges,
|
2023-10-02 23:10:49 +03:00
|
|
|
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 getRootRecordsWithChildren(): Collection
|
|
|
|
|
// {
|
|
|
|
|
// $rootRecords = $this->records->where("isRoot", true)->values();
|
|
|
|
|
// return $rootRecords->map([$this, 'findChildren']);
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// public function findChildren(QueryRecord $record): QueryRecord
|
|
|
|
|
// {
|
|
|
|
|
// $recordEdges = $this->edges
|
|
|
|
|
// ->where("source", $record->id)
|
|
|
|
|
// ->values()
|
|
|
|
|
// ->sortBy("rank")
|
|
|
|
|
// ->groupBy("field")->toArray();
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// foreach ($recordEdges as $field => $edges) {
|
|
|
|
|
// $recordEdges[$field] = [];
|
|
|
|
|
// foreach ($edges as $anEdge) {
|
|
|
|
|
// $aRecord = $this->records->where("id", $anEdge->target)->first();
|
|
|
|
|
// if (empty($aRecord)) {
|
|
|
|
|
// continue;
|
|
|
|
|
// }
|
|
|
|
|
// $recordEdges[$field][] = $this->findChildren($aRecord);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// $record->_children = new Collection($recordEdges);
|
|
|
|
|
// return $record;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
public function tree(): Collection
|
|
|
|
|
{
|
2023-10-13 21:06:23 +03:00
|
|
|
return $this->getRootRecords()
|
|
|
|
|
->map([$this, 'findParents'])
|
|
|
|
|
->map([$this, 'findChildren'])
|
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
return $rootRecords;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-10-02 23:10:49 +03:00
|
|
|
return $this->records->filter(function (QueryRecord $record) {
|
|
|
|
|
return $this->edges->filter(fn(Edge $ed) => $ed->target == $record->id)->isEmpty();
|
|
|
|
|
})->values()
|
|
|
|
|
->map([$this, 'findChildren']);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function findChildren(QueryRecord $record): QueryRecord
|
|
|
|
|
{
|
|
|
|
|
$recordEdges = $this->edges->filter(fn(Edge $ed) => $ed->source === $record->id)->values()->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]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$record->_children = $children;
|
|
|
|
|
return $record;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-13 21:06:23 +03:00
|
|
|
|
|
|
|
|
public function findParents(QueryRecord $record): QueryRecord
|
|
|
|
|
{
|
|
|
|
|
$recordEdges = $this->parentEdges->filter(fn(Edge $ed) => $ed->target === $record->id)->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]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$record->_parents = $parents;
|
|
|
|
|
return $record;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-02 23:10:49 +03:00
|
|
|
}
|