Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.88% covered (success)
98.88%
88 / 89
97.44% covered (success)
97.44%
38 / 39
CRAP
0.00% covered (danger)
0.00%
0 / 1
Nav
98.88% covered (success)
98.88%
88 / 89
97.44% covered (success)
97.44%
38 / 39
58
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 returnFalse
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setTree
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 addBranch
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 addLeaf
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 setConfig
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
4
 setAcl
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setRole
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 addRole
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 addRoles
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 setAclStrict
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setIndent
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setBaseUrl
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setParentLevel
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 incrementParentLevel
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 decrementParentLevel
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setChildLevel
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 incrementChildLevel
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 decrementChildLevel
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 isReturnFalse
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isAclStrict
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getTree
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getConfig
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getAcl
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasRoles
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasRole
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getRoles
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getRole
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 getIndent
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getBaseUrl
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getParentLevel
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getChildLevel
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getNav
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 nav
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 build
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 rebuild
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 render
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 __toString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 traverseTree
90.91% covered (success)
90.91%
10 / 11
0.00% covered (danger)
0.00%
0 / 1
8.05
1<?php
2/**
3 * Pop PHP Framework (http://www.popphp.org/)
4 *
5 * @link       https://github.com/popphp/popphp-framework
6 * @author     Nick Sagona, III <dev@nolainteractive.com>
7 * @copyright  Copyright (c) 2009-2023 NOLA Interactive, LLC. (http://www.nolainteractive.com)
8 * @license    http://www.popphp.org/license     New BSD License
9 */
10
11/**
12 * @namespace
13 */
14namespace Pop\Nav;
15
16use Pop\Acl\Acl;
17use Pop\Acl\AclRole;
18use Pop\Dom\Child;
19
20/**
21 * Nav class
22 *
23 * @category   Pop
24 * @package    Pop\Nav
25 * @author     Nick Sagona, III <dev@nolainteractive.com>
26 * @copyright  Copyright (c) 2009-2023 NOLA Interactive, LLC. (http://www.nolainteractive.com)
27 * @license    http://www.popphp.org/license     New BSD License
28 * @version    3.3.0
29 */
30class Nav
31{
32
33    /**
34     * Nav tree
35     * @var array
36     */
37    protected $tree = [];
38
39    /**
40     * Nav config
41     * @var array
42     */
43    protected $config = [];
44
45    /**
46     * Acl object
47     * @var Acl
48     */
49    protected $acl = null;
50
51    /**
52     * AclRole role objects
53     * @var array
54     */
55    protected $roles = [];
56
57    /**
58     * Acl strict flag
59     * @var boolean
60     */
61    protected $aclStrict = false;
62
63    /**
64     * Indentation
65     * @var string
66     */
67    protected $indent = null;
68
69    /**
70     * Base URL
71     * @var string
72     */
73    protected $baseUrl = null;
74
75    /**
76     * Nav parent level
77     * @var int
78     */
79    protected $parentLevel = 1;
80
81    /**
82     * Nav child level
83     * @var int
84     */
85    protected $childLevel = 1;
86
87    /**
88     * Return false flag
89     * @var boolean
90     */
91    protected $returnFalse = false;
92
93    /**
94     * Parent nav element
95     * @var Child
96     */
97    protected $nav = null;
98
99    /**
100     * Constructor
101     *
102     * Instantiate the nav object
103     *
104     * @param  array $tree
105     * @param  array $config
106     */
107    public function __construct(array $tree = null, array $config = null)
108    {
109        $this->setTree($tree);
110        $this->setConfig($config);
111    }
112
113    /**
114     * Set the return false flag
115     *
116     * @param  boolean $return
117     * @return Nav
118     */
119    public function returnFalse($return)
120    {
121        $this->returnFalse = (bool)$return;
122        return $this;
123    }
124
125    /**
126     * Set the nav tree
127     *
128     * @param  array $tree
129     * @return Nav
130     */
131    public function setTree(array $tree = null)
132    {
133        $this->tree = (null !== $tree) ? $tree : [];
134        return $this;
135    }
136
137    /**
138     * Add to a nav tree branch
139     *
140     * @param  array   $branch
141     * @param  boolean $prepend
142     * @return Nav
143     */
144    public function addBranch(array $branch, $prepend = false)
145    {
146        if (isset($branch['name'])) {
147            $branch = [$branch];
148        }
149        $this->tree = ($prepend) ? array_merge($branch, $this->tree) : array_merge($this->tree, $branch);
150        return $this;
151    }
152
153    /**
154     * Add to a leaf to nav tree branch
155     *
156     * @param  string  $branch
157     * @param  array   $leaf
158     * @param  int     $pos
159     * @param  boolean $prepend
160     * @return Nav
161     */
162    public function addLeaf($branch, array $leaf, $pos = null, $prepend = false)
163    {
164        $this->tree        = $this->traverseTree($this->tree, $branch, $leaf, $pos, $prepend);
165        $this->parentLevel = 1;
166        $this->childLevel  = 1;
167        return $this;
168    }
169
170    /**
171     * Set the nav tree
172     *
173     * @param  array $config
174     * @return Nav
175     */
176    public function setConfig(array $config = null)
177    {
178        if (null === $config) {
179            $this->config = [
180                'top'    => [
181                    'node'  => 'nav'
182                ],
183                'parent' => [
184                    'node'  => 'nav'
185                ],
186                'child' => [
187                    'node'  => 'nav'
188                ]
189            ];
190        } else {
191            $this->config = $config;
192        }
193
194        if (isset($config['indent'])) {
195            $this->setIndent($config['indent']);
196        }
197
198        if (isset($config['baseUrl'])) {
199            $this->setBaseUrl($config['baseUrl']);
200        }
201
202        return $this;
203    }
204
205    /**
206     * Set the Acl object
207     *
208     * @param  Acl $acl
209     * @return Nav
210     */
211    public function setAcl(Acl $acl = null)
212    {
213        $this->acl = $acl;
214        return $this;
215    }
216
217    /**
218     * Set a AclRole object (alias method)
219     *
220     * @param  AclRole $role
221     * @return Nav
222     */
223    public function setRole(AclRole $role = null)
224    {
225        $this->roles[$role->getName()] = $role;
226        return $this;
227    }
228
229    /**
230     * Add a AclRole object
231     *
232     * @param  AclRole $role
233     * @return Nav
234     */
235    public function addRole(AclRole $role = null)
236    {
237        return $this->setRole($role);
238    }
239
240    /**
241     * Add AclRole objects
242     *
243     * @param  array $roles
244     * @return Nav
245     */
246    public function addRoles(array $roles)
247    {
248        foreach ($roles as $role) {
249            $this->setRole($role);
250        }
251
252        return $this;
253    }
254
255    /**
256     * Set the Acl object as strict evaluation
257     *
258     * @param  boolean $strict
259     * @return Nav
260     */
261    public function setAclStrict($strict)
262    {
263        $this->aclStrict = (bool)$strict;
264        return $this;
265    }
266
267    /**
268     * Set the indent
269     *
270     * @param  string $indent
271     * @return Nav
272     */
273    public function setIndent($indent)
274    {
275        $this->indent = $indent;
276        return $this;
277    }
278
279    /**
280     * Set the base URL
281     *
282     * @param  string $baseUrl
283     * @return Nav
284     */
285    public function setBaseUrl($baseUrl)
286    {
287        $this->baseUrl = $baseUrl;
288        return $this;
289    }
290
291    /**
292     * Set parent level
293     *
294     * @param  int $level
295     * @return Nav
296     */
297    public function setParentLevel($level)
298    {
299        $this->parentLevel = (int)$level;
300        return $this;
301    }
302
303    /**
304     * Increment parent level
305     *
306     * @return Nav
307     */
308    public function incrementParentLevel()
309    {
310        $this->parentLevel++;
311        return $this;
312    }
313
314    /**
315     * Decrement parent level
316     *
317     * @return Nav
318     */
319    public function decrementParentLevel()
320    {
321        $this->parentLevel--;
322        return $this;
323    }
324
325    /**
326     * Set child level
327     *
328     * @param  int $level
329     * @return Nav
330     */
331    public function setChildLevel($level)
332    {
333        $this->childLevel = (int)$level;
334        return $this;
335    }
336
337    /**
338     * Increment child level
339     *
340     * @return Nav
341     */
342    public function incrementChildLevel()
343    {
344        $this->childLevel++;
345        return $this;
346    }
347
348    /**
349     * Decrement child level
350     *
351     * @return Nav
352     */
353    public function decrementChildLevel()
354    {
355        $this->childLevel--;
356        return $this;
357    }
358
359    /**
360     * Set the return false flag
361     *
362     * @return boolean
363     */
364    public function isReturnFalse()
365    {
366        return $this->returnFalse;
367    }
368
369    /**
370     * Determine if the Acl object is set as strict evaluation
371     *
372     * @return boolean
373     */
374    public function isAclStrict()
375    {
376        return $this->aclStrict;
377    }
378
379    /**
380     * Get the nav tree
381     *
382     * @return array
383     */
384    public function getTree()
385    {
386        return $this->tree;
387    }
388
389    /**
390     * Get the config
391     *
392     * @return array
393     */
394    public function getConfig()
395    {
396        return $this->config;
397    }
398
399    /**
400     * Get the Acl object
401     *
402     * @return Acl
403     */
404    public function getAcl()
405    {
406        return $this->acl;
407    }
408
409    /**
410     * Determine if there are roles
411     *
412     * @return boolean
413     */
414    public function hasRoles()
415    {
416        return (count($this->roles) > 0);
417    }
418
419    /**
420     * Determine if there is a certain role
421     *
422     * @param  string $name
423     * @return boolean
424     */
425    public function hasRole($name)
426    {
427        return (isset($this->roles[$name]));
428    }
429
430    /**
431     * Get the AclRole objects
432     *
433     * @return array
434     */
435    public function getRoles()
436    {
437        return $this->roles;
438    }
439
440    /**
441     * Get a AclRole object
442     *
443     * @param  string $name
444     * @return AclRole
445     */
446    public function getRole($name)
447    {
448        return (isset($this->roles[$name])) ? $this->roles[$name] : null;
449    }
450
451    /**
452     * Get the indent
453     *
454     * @return string
455     */
456    public function getIndent()
457    {
458        return $this->indent;
459    }
460
461    /**
462     * Get the base URL
463     *
464     * @return string
465     */
466    public function getBaseUrl()
467    {
468        return $this->baseUrl;
469    }
470
471    /**
472     * Get parent level
473     *
474     * @return int
475     */
476    public function getParentLevel()
477    {
478        return $this->parentLevel;
479    }
480
481    /**
482     * Get child level
483     *
484     * @return int
485     */
486    public function getChildLevel()
487    {
488        return $this->childLevel;
489    }
490
491    /**
492     * Get the nav object
493     *
494     * @return Child
495     */
496    public function getNav()
497    {
498        if (null === $this->nav) {
499            $this->nav = NavBuilder::build($this, $this->tree);
500        }
501        return $this->nav;
502    }
503
504    /**
505     * Get the nav object (alias)
506     *
507     * @return Child
508     */
509    public function nav()
510    {
511        return $this->getNav();
512    }
513
514    /**
515     * Build the nav object
516     *
517     * @return Nav
518     */
519    public function build()
520    {
521        if (null === $this->nav) {
522            $this->nav = NavBuilder::build($this, $this->tree);
523        }
524        return $this;
525    }
526
527    /**
528     * Re-build the nav object
529     *
530     * @return Nav
531     */
532    public function rebuild()
533    {
534        $this->parentLevel = 1;
535        $this->childLevel  = 1;
536        $this->nav         = NavBuilder::build($this, $this->tree);
537        return $this;
538    }
539
540    /**
541     * Render the nav object
542     *
543     * @return string
544     */
545    public function render()
546    {
547        if (null === $this->nav) {
548            $this->nav = NavBuilder::build($this, $this->tree);
549        }
550
551        $result = ($this->nav->hasChildren()) ? $this->nav->render() : '';
552        return $result;
553    }
554
555    /**
556     * Render Nav object to string
557     *
558     * @return string
559     */
560    public function __toString()
561    {
562        return $this->render();
563    }
564
565    /**
566     * Traverse tree to insert new leaf
567     *
568     * @param  array   $tree
569     * @param  string  $branch
570     * @param  array   $newLeaf
571     * @param  int     $pos
572     * @param  boolean $prepend
573     * @param  int     $depth
574     * @return array
575     */
576    protected function traverseTree($tree, $branch, $newLeaf, $pos = null, $prepend = false, $depth = 0)
577    {
578        $t = [];
579        foreach ($tree as $leaf) {
580            if (((null === $pos) || ($pos == $depth)) && ($leaf['name'] == $branch)) {
581                if (isset($leaf['children'])) {
582                    $leaf['children'] = ($prepend) ?
583                        array_merge([$newLeaf], $leaf['children']) : array_merge($leaf['children'], [$newLeaf]);
584                } else {
585                    $leaf['children'] = [$newLeaf];
586                }
587            }
588            if (isset($leaf['children'])) {
589                $leaf['children'] = $this->traverseTree($leaf['children'], $branch, $newLeaf, $pos, $prepend, ($depth + 1));
590            }
591            $t[] = $leaf;
592        }
593
594        return $t;
595    }
596
597}