Completed
Push — master ( 538e23...cf71ed )
by Bao
51:15 queued 49:13
created

TreeParser::setIndentation()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
crap 1
1
<?php
2
3
namespace BaoPham\TreeParser;
4
5
class TreeParser
6
{
7
    private $indentation = 2;
8
9
    /**
10
     * @var string
11
     */
12
    private $tree;
13
14
    /**
15
     * @var int
16
     */
17
    private $initialSpaces;
18
19
    /**
20
     * @var array
21
     */
22
    private $structure;
23
24
    /**
25
     * @var array
26
     */
27
    private $orderedNodes;
28
29
    /**
30
     * TreeParser constructor.
31
     * @param string $tree
32
     *
33
     * <<<TREE
34
     *  Root
35
     *    |- Level 1 - Order 1
36
     *      |- Level 2 - Order 2
37
     *        |- Level 3 - Order 3
38
     *        |- Level 3 - Order 4
39
     *      |- Level 2 - Order 5
40
     *    |- Level 1 - Order 6
41
     *      |- Level 2 - Order 7
42
     *        |- Level 3 - Order 8
43
     *          |- Level 4 - Order 9
44
     * TREE;
45
     */
46 12
    public function __construct($tree)
47
    {
48 12
        $this->tree = $tree;
49 12
    }
50
51 12
    public function parse()
52
    {
53 12
        $lines = explode(PHP_EOL, $this->tree);
54
55 12
        $this->setStructureAndOrderedNodes($lines);
56
57 9
        $root = $this->structure[TreeNode::ROOT_LEVEL][TreeNode::ROOT_ORDER];
58
59 9
        foreach ($this->orderedNodes as $node) {
60 9
            if ($node->isRoot) {
61 9
                continue;
62
            }
63
64 9
            $parent = $this->getParentForNode($node);
65
66 9
            $parent->children[] = $node;
67
68 9
            $node->parent = $parent;
69 9
        }
70
71 9
        return $root;
72
    }
73
74
    public function setTree($tree)
75
    {
76
        $this->tree = $tree;
77
    }
78
79
    public function getTree()
80
    {
81
        return $this->tree;
82
    }
83
84
    /**
85
     * @return array
86
     */
87 3
    public function getOrderedNodes()
88
    {
89 3
        return $this->orderedNodes;
90
    }
91
92
    /**
93
     * @return array
94
     */
95
    public function getStructure()
96
    {
97
        return $this->structure;
98
    }
99
100
    /**
101
     * @param int $indentation
102
     * @return TreeParser
103
     */
104 3
    public function setIndentation($indentation)
105
    {
106 3
        $this->indentation = $indentation;
107 3
        return $this;
108
    }
109
110
    /**
111
     * @param TreeNode $node
112
     * @return TreeNode|null
113
     */
114 9
    public function getParentForNode(TreeNode $node)
115
    {
116 9
        if ($node->level === TreeNode::ROOT_LEVEL) {
117
            return null;
118
        }
119
120 9
        $parentLevel = $node->level - 1;
121
122 9
        $candidates = $this->structure[$parentLevel];
123
124 9
        $order = $node->order - 1;
125
126 9
        while ($order >= TreeNode::ROOT_ORDER) {
127 9
            if (isset($candidates[$order])) {
128 9
                return $candidates[$order];
129
            }
130
131 6
            --$order;
132 6
        }
133
    }
134
135
    /**
136
     * @param $line
137
     * @return int
138
     */
139 12
    private function numberOfSpaces($line)
140
    {
141 12
        return strspn($line, ' ');
142
    }
143
144
    /**
145
     * @param $numberOfSpaces
146
     * @return int
147
     * @throws InvalidNumberOfSpaces
148
     */
149 12
    private function spacesToLevel($numberOfSpaces)
150
    {
151 12
        if ($numberOfSpaces === $this->initialSpaces) {
152 12
            return 0;
153
        }
154
155 12
        if (($numberOfSpaces - $this->initialSpaces) % $this->indentation !== 0) {
156 3
            throw new InvalidNumberOfSpaces(
157 3
                "Make sure children's leading spaces being a multiple of {$this->indentation}"
158 3
            );
159
        }
160
161 9
        return (int) ($numberOfSpaces - $this->initialSpaces) / $this->indentation;
162
    }
163
164 12
    private function lineToNode($line)
165
    {
166 12
        $line = trim($line);
167 12
        $line = ltrim($line, '|-');
168 12
        $line = trim($line);
169
170 12
        $node = new TreeNode();
171
172 12
        $node->name = $line;
173
174 12
        return $node;
175
    }
176
177 12
    private function setStructureAndOrderedNodes(array $lines)
178
    {
179 12
        $this->orderedNodes = [];
180
181 12
        $this->initialSpaces = null;
182
183 12
        $this->structure = [];
184
185 12
        foreach ($lines as $order => $line) {
186 12
            $node = $this->lineToNode($line);
187
188 12
            if ($this->initialSpaces === null) {
189 12
                $this->initialSpaces = $this->numberOfSpaces($line);
190 12
                $node->isRoot = true;
191 12
            }
192
193 12
            $node->order = (int) $order;
194
195 12
            $node->level = $this->spacesToLevel($this->numberOfSpaces($line));
196
197 12
            $this->structure[$node->level][$node->order] = $node;
198
199 12
            $this->orderedNodes[] = $node;
200 12
        }
201 9
    }
202
}
203