LTreeBuilder::getNode()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 5
c 2
b 0
f 0
dl 0
loc 9
ccs 6
cts 6
cp 1
rs 10
cc 4
nc 3
nop 3
crap 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Umbrellio\LTree\Helpers;
6
7
use Umbrellio\LTree\Collections\LTreeCollection;
8
use Umbrellio\LTree\Exceptions\LTreeReflectionException;
9
use Umbrellio\LTree\Exceptions\LTreeUndefinedNodeException;
10
11
class LTreeBuilder
12
{
13
    private $pathField;
14
    private $idField;
15
    private $parentIdField;
16
    private $nodes = [];
17
    private $root = null;
18
19 22
    public function __construct(string $pathField, string $idField, string $parentIdField)
20
    {
21 22
        $this->pathField = $pathField;
22 22
        $this->idField = $idField;
23 22
        $this->parentIdField = $parentIdField;
24
    }
25
26 22
    public function build(LTreeCollection $items, bool $usingSort = true): LTreeNode
27
    {
28 22
        if ($usingSort === true) {
29 21
            $items = $items->sortBy($this->pathField, SORT_STRING);
30
        }
31
32 22
        $this->root = new LTreeNode();
33
34 22
        foreach ($items as $item) {
35 22
            $node = new LTreeNode($item);
36 22
            $id = $item->{$this->idField};
37 22
            $this->nodes[$id] = $node;
38
        }
39
40 22
        foreach ($items as $item) {
41 22
            [$id, $parentId, $path] = $this->getNodeIds($item);
42 22
            $node = $this->nodes[$id];
43 22
            $parentNode = $this->getNode($id, $path, $parentId);
44 22
            $parentNode->addChild($node);
45
        }
46 19
        return $this->root;
47
    }
48
49 22
    private function getNodeIds($item): array
50
    {
51 22
        $parentId = $item->{$this->parentIdField};
52 22
        $id = $item->{$this->idField};
53 22
        $path = $item->{$this->pathField};
54
55 22
        if ($id === $parentId) {
56 1
            throw new LTreeReflectionException($id);
57
        }
58 22
        return [$id, $parentId, $path];
59
    }
60
61 22
    private function getNode(int $id, string $path, ?int $parentId): LTreeNode
62
    {
63 22
        if ($parentId === null || $this->hasNoMissingNodes($id, $path)) {
64 22
            return $this->root;
65
        }
66 22
        if (!isset($this->nodes[$parentId])) {
67 2
            throw new LTreeUndefinedNodeException($parentId);
68
        }
69 21
        return $this->nodes[$parentId];
70
    }
71
72 22
    private function hasNoMissingNodes(int $id, string $path): bool
73
    {
74 22
        $subpath = substr($path, 0, -strlen(".{$id}"));
75 22
        $subpathIds = explode('.', $subpath);
76
77 22
        $missingNodes = 0;
78 22
        foreach ($subpathIds as $parentId) {
79 22
            if (!isset($this->nodes[$parentId])) {
80 5
                $missingNodes++;
81
            }
82
        }
83
84 22
        return $subpathIds > 0 && $missingNodes === count($subpathIds);
85
    }
86
}
87