Passed
Push — master ( b8645d...c590b4 )
by Smoren
02:22
created

TreeBuilder   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 103
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 30
dl 0
loc 103
ccs 32
cts 32
cp 1
rs 10
c 0
b 0
f 0
wmc 11

4 Methods

Rating   Name   Duplication   Size   Complexity  
A getParentId() 0 10 2
A wrapItem() 0 13 3
A build() 0 28 4
A getChildrenContainer() 0 7 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Smoren\TreeTools;
6
7
use Smoren\TypeTools\MapAccess;
8
use stdClass;
9
10
class TreeBuilder
11
{
12
    /**
13
     * Builds a tree from given flat collection of items with relations.
14
     *
15
     * @param iterable<mixed> $collection
16
     * @param string $idField
17
     * @param string $parentIdField
18
     * @param string $childrenContainerField
19
     * @param string $itemContainerField
20
     *
21
     * @return array<mixed>
22
     */
23 10
    public static function build(
24
        iterable $collection,
25
        string $idField = 'id',
26
        string $parentIdField = 'parent_id',
27
        string $childrenContainerField = 'children',
28
        string $itemContainerField = 'item'
29
    ): array {
30 10
        $result = [];
31 10
        $map = [];
32
33 10
        foreach($collection as $item) {
34 5
            $map[MapAccess::get($item, $idField)] = static::wrapItem(
35 5
                $item,
36 5
                $childrenContainerField,
37 5
                $itemContainerField
38 5
            );
39
        }
40
41 10
        foreach($map as &$item) {
42 5
            if(($parentId = static::getParentId($item, $parentIdField, $itemContainerField)) !== null) {
43 5
                $childrenContainer = &static::getChildrenContainer($map[$parentId], $childrenContainerField);
44 5
                $childrenContainer[] = &$item;
45
            } else {
46 5
                $result[] = &$item;
47
            }
48
        }
49
50 10
        return $result;
51
    }
52
53
    /**
54
     * Returns value of parent relation.
55
     *
56
     * @param mixed $item
57
     * @param string $parentIdField
58
     * @param string $itemContainerField
59
     *
60
     * @return scalar|null
61
     */
62 5
    protected static function getParentId($item, string $parentIdField, string $itemContainerField)
63
    {
64
        /** @var scalar|null $parentId */
65 5
        $parentId = MapAccess::get($item, $parentIdField);
66
67 5
        if($parentId !== null) {
68 4
            return $parentId;
69
        }
70
71 5
        return MapAccess::get(MapAccess::get($item, $itemContainerField), $parentIdField);
72
    }
73
74
    /**
75
     * Returns children container of given item.
76
     *
77
     * @param mixed $item
78
     * @param string $childrenContainerField
79
     *
80
     * @return array<mixed>
81
     */
82 5
    protected static function &getChildrenContainer(&$item, string $childrenContainerField): array
83
    {
84 5
        if(is_array($item)) {
85 3
            return $item[$childrenContainerField];
86
        }
87
88 2
        return $item->{$childrenContainerField};
89
    }
90
91
    /**
92
     * Wraps collection item for tree representation.
93
     *
94
     * @param mixed $item
95
     * @param string $childrenContainerField
96
     * @param string $itemContainerField
97
     *
98
     * @return array<mixed>|stdClass
99
     */
100 5
    protected static function wrapItem($item, string $childrenContainerField, string $itemContainerField)
101
    {
102 5
        if(is_array($item)) {
103 2
            $item[$childrenContainerField] = [];
104 2
            return $item;
105
        }
106
107 3
        if($item instanceof stdClass) {
108 2
            $item->{$childrenContainerField} = [];
109 2
            return $item;
110
        }
111
112 1
        return [$itemContainerField => &$item, $childrenContainerField => []];
113
    }
114
}
115