Completed
Push — master ( 0fcd81...02a1e8 )
by Hong
03:12
created

Tree::addNode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 6
rs 9.4285
cc 1
eloc 4
nc 1
nop 2
1
<?php
2
/**
3
 * Phossa Project
4
 *
5
 * PHP version 5.4
6
 *
7
 * @category  Library
8
 * @package   Phossa2\Shared
9
 * @copyright Copyright (c) 2016 phossa.com
10
 * @license   http://mit-license.org/ MIT License
11
 * @link      http://www.phossa.com/
12
 */
13
/*# declare(strict_types=1); */
14
15
namespace Phossa2\Shared\Tree;
16
17
use Phossa2\Shared\Base\ObjectAbstract;
18
19
/**
20
 * Dealing with tree structure
21
 *
22
 * @package Phossa2\Shared
23
 * @author  Hong Zhang <[email protected]>
24
 * @version 2.0.3
25
 * @since   2.0.3 added
26
 * @since   2.0.5 added deleteNode()
27
 */
28
class Tree extends ObjectAbstract
29
{
30
    /**
31
     * node splitter
32
     *
33
     * @var    string
34
     * @access protected
35
     */
36
    protected $splitter = '.';
37
38
    /**
39
     * the result tree
40
     *
41
     * @var    array
42
     * @access protected
43
     */
44
    protected $tree;
45
46
    /**
47
     * construct a tree
48
     *
49
     * @param  array $data
50
     * @param  string $splitter
51
     * @access public
52
     * @api
53
     */
54
    public function __construct(array $data = [], /*# string */ $splitter = '.')
55
    {
56
        $this->splitter = $splitter;
57
        $this->tree = $this->fixTree($data);
58
    }
59
60
    /**
61
     * return the whole tree
62
     *
63
     * @return array
64
     * @access public
65
     * @api
66
     */
67
    public function getTree()/*# : array */
68
    {
69
        return $this->tree;
70
    }
71
72
    /**
73
     * Get one node, NULL if not found
74
     *
75
     * @param  string $nodeName
76
     * @return mixed
77
     * @access public
78
     * @api
79
     */
80
    public function &getNode(/*# string */ $nodeName)
81
    {
82
        if ('' === $nodeName) {
83
            $result = &$this->tree;
84
        } else {
85
            $result = &$this->searchNode($nodeName, $this->tree, false);
86
        }
87
        return $result;
88
    }
89
90
    /**
91
     * Has node in tree or not
92
     *
93
     * @param  string $nodeName
94
     * @return bool
95
     * @access public
96
     * @api
97
     */
98
    public function hasNode(/*# string */ $nodeName)/*# : bool */
99
    {
100
        if (null === $this->getNode($nodeName)) {
101
            return false;
102
        } else {
103
            return true;
104
        }
105
    }
106
107
    /**
108
     * Add one node
109
     *
110
     * @param  string $nodeName
111
     * @param  mixed $data
112
     * @return $this
113
     * @access public
114
     * @api
115
     */
116
    public function addNode(/*# string */ $nodeName, $data)
117
    {
118
        $node = &$this->searchNode($nodeName, $this->tree, true);
119
        $node = $this->fixTree($data);
120
        return $this;
121
    }
122
123
    /**
124
     * Delete one node if exists
125
     *
126
     * @param  string $nodeName
127
     * @return $this
128
     * @access public
129
     * @since  2.0.5
130
     * @api
131
     */
132
    public function deleteNode(/*# string */ $nodeName)
133
    {
134
        if ('' === $nodeName) {
135
            $this->tree = [];
136
        } else {
137
            $current = &$this->getNode($nodeName);
138
            if (null !== $current) {
139
                $split = explode($this->splitter, $nodeName);
140
                $name  = array_pop($split);
141
                $upper = &$this->getNode(join($this->splitter, $split));
142
                unset($upper[$name]);
143
            }
144
        }
145
        return $this;
146
    }
147
148
    /**
149
     * Fix array, convert flat name to tree node name
150
     *
151
     * @param  array $data
152
     * @return array
153
     * @access protected
154
     */
155
    protected function fixTree(array $data)/*# : array */
156
    {
157
        $result = [];
158
        foreach ($data as $k => $v) {
159
            $res = &$this->searchNode($k, $result);
160
            $res = is_array($v) ? $this->fixTree($v) : $v;
161
        }
162
        return $result;
163
    }
164
165
    /**
166
     * Search a node in the $data
167
     *
168
     * @param  string $key
169
     * @param  array &$data
170
     * @param  bool $create
171
     * @access protected
172
     */
173
    protected function &searchNode(
174
        /*# string */ $key,
175
        array &$data,
176
        /*# bool */ $create = true
177
    ) {
178
        $found = &$data;
179
        foreach (explode($this->splitter, $key) as $k) {
180
            if (isset($found[$k])) {
181
                $found = &$found[$k];
182
            } elseif ($create) {
183
                $found[$k] = [];
184
                $found = &$found[$k];
185
            } else {
186
                $found = null;
187
                break;
188
            }
189
        }
190
        return $found;
191
    }
192
}
193