tree-tools-php

Форк
0
/
TreeBuilder.php 
114 строк · 3.0 Кб
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
    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
        $result = [];
31
        $map = [];
32

33
        foreach($collection as $item) {
34
            $map[MapAccess::get($item, $idField)] = static::wrapItem(
35
                $item,
36
                $childrenContainerField,
37
                $itemContainerField
38
            );
39
        }
40

41
        foreach($map as &$item) {
42
            if(($parentId = static::getParentId($item, $parentIdField, $itemContainerField)) !== null) {
43
                $childrenContainer = &static::getChildrenContainer($map[$parentId], $childrenContainerField);
44
                $childrenContainer[] = &$item;
45
            } else {
46
                $result[] = &$item;
47
            }
48
        }
49

50
        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
    protected static function getParentId($item, string $parentIdField, string $itemContainerField)
63
    {
64
        /** @var scalar|null $parentId */
65
        $parentId = MapAccess::get($item, $parentIdField);
66

67
        if($parentId !== null) {
68
            return $parentId;
69
        }
70

71
        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
    protected static function &getChildrenContainer(&$item, string $childrenContainerField): array
83
    {
84
        if(is_array($item)) {
85
            return $item[$childrenContainerField];
86
        }
87

88
        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
    protected static function wrapItem($item, string $childrenContainerField, string $itemContainerField)
101
    {
102
        if(is_array($item)) {
103
            $item[$childrenContainerField] = [];
104
            return $item;
105
        }
106

107
        if($item instanceof stdClass) {
108
            $item->{$childrenContainerField} = [];
109
            return $item;
110
        }
111

112
        return [$itemContainerField => &$item, $childrenContainerField => []];
113
    }
114
}
115

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.