Completed
Push — master ( 40a2e1...e1bbf2 )
by Tilita
02:00
created
Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
namespace ezTreeBuilder;
3
4
use ezTreeBuilder\Base\Branch;
5
use ezTreeBuilder\Base\Adapter;
6
7
/**
8
 * Tree builder class - generates the enire tree based on \TreeBuilder\Branch
9
 *
10
 * @package ezTreeBuilder
11
 * @author Adrian Tilita <[email protected]>
12
 * @version 1.0
13
 */
14
class Tree
15
{
16
    /**
17
     * Set the build mode simple and add a depth field for branches
18
     * @const int
19
     */
20
    const BUILD_MODE_DEPTH = 0;
21
22
    /**
23
     * Builds simple mode and add left->right fields
24
     * @const int
25
     */
26
    const BUILD_MODE_LEFT_RIGHT = 1;
27
28
    /**
29
     * Builds the full type off tree, containing all off the above
30
     * @const int
31
     */
32
    const BUILD_MODE_COMPLETE = 2;
33
34
    /**
35
     * Wheather to log debug details
36
     * @var boolean
37
     */
38
    private $debug = false;
39
40
    /**
41
     * Collected debug data if enabled
42
     * @var string
43
     */
44
    private $debugData;
45
46
    /**
47
     * "Dirty" flag - weather to build the tree if it wasn't compiled allready
48
     * @var boolean
49
     */
50
    private $compiled = false;
51
52
    /**
53
     * Store all tree items
54
     * @var array - array([ID] => TreeBuilder\Branch, [ID] => TreeBuilder\Branch)
55
     */
56
    private $branches = array();
57
58
    /**
59
     * Stores the compiled tree
60
     * @var array
61
     */
62
    private $compiledTree = array();
63
64
    /**
65
     * A delagated adapter for the output
66
     * @var Adapter
67
     */
68
    private $delegatedAdapter;
69
70
    /**
71
     * Defines the build mode off the tree
72
     * @var int
73
     */
74
    private $buildMode;
75
76
    /**
77
     * Enables debug mode
78
     */
79
    public function enableDebug()
80
    {
81
        $this->debug = true;
82
    }
83
84
    /**
85
     * Show debug state
86
     * @return boolean
87
     */
88
    public function isDebugEnabled()
89
    {
90
        return $this->debug;
91
    }
92
93
    /**
94
     * Get debug data
95
     * @return string
96
     * @throws \Exception
97
     */
98
    public function getDebugData()
99
    {
100
        if ($this->isDebugEnabled() === false) {
101
            throw new \Exception('Debug is not enabled!');
102
        }
103
        return $this->debugData;
104
    }
105
106
    /**
107
     * Delegate an adapter for the wanted output
108
     * @param Adapter $adapter
109
     * @return \TreeBuilder\Tree
110
     */
111
    public function registerAdapter(Adapter $adapter)
112
    {
113
        $this->delegatedAdapter = $adapter;
114
        return $this;
115
    }
116
117
    /**
118
     * Set the build mode identified by local constants
119
     * @param int $value
120
     * @return \TreeBuilder\Tree
121
     */
122
    public function setBuildMode($value)
123
    {
124
        $this->buildMode = $value;
125
        return $this;
126
    }
127
128
    /**
129
     * Add a new TreeItem
130
     * @param Branch $item
131
     */
132
    public function addBranch(Branch $item)
133
    {
134
        $this->branches[$item->getId()] = $item;
135
        $this->compiled = false;
136
    }
137
138
    /**
139
     * Returns the builded tree
140
     * @return array
141
     */
142
    public function getTree()
143
    {
144
        if ($this->compiled === false) {
145
            $this->buildTree();
146
        }
147
        if ($this->delegatedAdapter != null) {
148
            $this->delegatedAdapter->setRawData($this->branches);
149
            $this->delegatedAdapter->setTree($this->compiledTree);
150
            return $this->delegatedAdapter->adapt();
151
        }
152
        return $this->compiledTree;
153
    }
154
155
    /**
156
     * Return a branch by it's id
157
     * @param int $id
158
     * @return \TreeBuilder\Base\Branch
159
     * @throws \Exception
160
     */
161
    public function getBranchById($id)
162
    {
163
        if (isset($this->branches[$id])) {
164
            if ($this->delegatedAdapter != null) {
165
                $this->delegatedAdapter->setRawData($this->branches);
166
                $this->delegatedAdapter->setTree(array($this->branches[$id]));
167
                $adaptedData = $this->delegatedAdapter->adapt();
168
                return isset($adaptedData[0]) ? $adaptedData[0] : $adaptedData;
169
            }
170
            return $this->branches[$id];
171
        }
172
        throw new \Exception("Could not find branch with id {$id}!");
173
    }
174
175
    /**
176
     * Return all leaf branches
177
     * @return  array
178
     */
179
    public function getLeafs() {
180
        $items = array();
181
        foreach ($this->branches as $item) {
182
            if ($item->isLeaf() === true) {
183
                $items[] = $item;
184
            }
185
        }
186
        return $items;
187
    }
188
189
    /**
190
     * Build the tree
191
     */
192
    public function buildTree()
193
    {
194
        // reset compiled tree
195
        $this->compiledTree = array();
196
        if ($this->isDebugEnabled()) {
197
            list($start_usec, $start_sec) = explode(" ", microtime());
198
        }
199
        // build for simple mode
200
        foreach ($this->branches as $id => $item) {
201
            $this->buildBranchReference($id, $item);
202
        }
203
        // build according to the required build mode
204
        if (!empty($this->compiledTree)) {
205
            switch ($this->buildMode) {
206
                case (self::BUILD_MODE_DEPTH):
207
                    $this->addDepth($this->compiledTree);
208
                    break;
209
                case (self::BUILD_MODE_LEFT_RIGHT):
210
                    $this->addLeftRight($this->compiledTree);
211
                    break;
212
                case (self::BUILD_MODE_COMPLETE):
213
                    $this->addDepth($this->compiledTree);
214
                    $this->addLeftRight($this->compiledTree);
215
                    $this->markLeafs($this->compiledTree);
216
                    break;
217
            }
218
        }
219
        if ($this->isDebugEnabled()) {
220
            if (count($this->compiledTree)) {
221
                $this->logDebug("No root branch declared!");
222
            }
223
            list($end_usec, $end_sec) = explode(" ", microtime());
224
            $diff_sec = intval($end_sec) - intval($start_sec);
0 ignored issues
show
The variable $start_sec does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
225
            $diff_usec = floatval($end_usec) - floatval($start_usec);
0 ignored issues
show
The variable $start_usec does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
226
            $this->logDebug("Compiled tree in " . floatval($diff_sec) + $diff_usec);
227
        }
228
        $this->compiled = true;
229
    }
230
231
    /**
232
     * Build the tree parent->child references
233
     * @param int $id
234
     * @param Branch $item
235
     */
236
    private function buildBranchReference($id, Branch $item)
237
    {
238
        if ($item->getParentId() != 0) {
239
            if (isset($this->branches[$item->getParentId()])) {
240
                $this->branches[$id] = $item->setParent($this->branches[$item->getParentId()]);
241
                $this->branches[$item->getParentId()]->addChild($item);
242
            } else {
243
                if ($this->isDebugEnabled()) {
244
                    $this->logDebug("Parent of {$item->getId()} with id {$item->getParentId()} is not added."
245
                    . "Skipping adding the current branch");
246
                }
247
            }
248
        } else {
249
            $this->compiledTree[] = $item;
250
        }
251
    }
252
253
    /**
254
     * Set the depth filed for items
255
     * @param array $items
256
     * @param int $depth
257
     */
258
    private function addDepth(array $items, $depth = 0)
259
    {
260
        foreach ($items as $item) {
261
            $item->setDepth($depth);
262
            if ($item->hasChildren()) {
263
                $this->addDepth($item->getChildren(), $depth + 1);
264
            }
265
        }
266
    }
267
268
    /**
269
     * Add left->right fields to tree
270
     * @param   array   $items
271
     * @param   int     $left
272
     * @return int
273
     */
274
    private function addLeftRight(array $items, $left = 1)
275
    {
276
        $right = $left+1;
277
        foreach ($items as $item) {
278
            $item->setLeft($left);
279
            if ($item->hasChildren()) {
280
                $right = $this->addLeftRight($item->getChildren(), $left + 1);
281
                $right++;
282
            } else {
283
                $right = $left + 1;
284
            }
285
            $item->setRight($right);
286
            $left = $right + 1;
287
        }
288
        return $right;
289
    }
290
291
    /**
292
     * Mark leaf branches
293
     * @param   array   $items
294
     */
295
    private function markLeafs($items) {
296
        foreach ($items as $item) {
297
            if ($item->hasChildren()) {
298
                $this->markLeafs($item->getChildren());
299
            } else {
300
                $item->setIsLeaf(true);
301
            }
302
        }
303
    }
304
305
    /**
306
     * Add to debug data
307
     * @param string $string
308
     */
309
    private function logDebug($string)
310
    {
311
        $this->debugData .= $string . '<br/>';
312
    }
313
}
314