Completed
Push — master ( 180145...18ce01 )
by Andrii
06:54
created

Menu   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 152
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 36
lcom 1
cbo 5
dl 0
loc 152
ccs 0
cts 93
cp 0
rs 8.8
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
B guessModule() 0 19 6
A getModuleName() 0 15 3
C renderItems() 0 38 12
B renderItem() 0 13 9
A iconClass() 0 4 2
A normalizeItems() 0 10 4
1
<?php
2
/**
3
 * Menus for Yii2.
4
 *
5
 * @link      https://github.com/hiqdev/yii2-menus
6
 * @package   yii2-menus
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2016-2017, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hiqdev\yii2\menus\widgets;
12
13
use Closure;
14
use Yii;
15
use yii\helpers\ArrayHelper;
16
use yii\helpers\Html;
17
use yii\helpers\Url;
18
19
/**
20
 * Enhanced menu widget with icons, visible callback.
21
 */
22
class Menu extends \yii\widgets\Menu
23
{
24
    /**
25
     * @var string Class that will be added for parents "li"
26
     */
27
    public $treeClass = 'treeview';
28
29
    /**
30
     * @var boolean activate parents by default
31
     */
32
    public $activateParents = true;
33
34
    /**
35
     * @var string default icon class
36
     */
37
    public $defaultIcon = null;
38
39
    /**
40
     * {@inheritdoc}
41
     */
42
    public $linkTemplate = '<a href="{url}" {linkOptions}>{icon}{iconSpace}{label}</a>';
43
44
    /**
45
     * {@inheritdoc}
46
     */
47
    public $labelTemplate = '{icon}{iconSpace}{label}';
48
49
    /**
50
     * Try to guess which module is parent for current page
51
     * and remain sidebarmenu accordion opened.
52
     * @param array $item
53
     * @return bool
54
     */
55
    protected function guessModule(array $item, $parentUrl = null)
56
    {
57
        $result = false;
58
        $moduleId = Yii::$app->controller->module->id;
59
        $parentModuleId = $this->getModuleName($parentUrl);
60
        if (!empty($item['items'])) {
61
            foreach ($item['items'] as $i) {
62
                if (isset($i['url'])) {
63
                    $itemModuleName = $this->getModuleName(reset($i['url']));
64
                    if ($itemModuleName === $moduleId && $parentModuleId === $moduleId) {
65
                        $result = true;
66
                        break;
67
                    }
68
                }
69
            }
70
        }
71
72
        return $result;
73
    }
74
75
    /**
76
     * Get module id from url string.
77
     * @param $route (like '/dns/zone/index')
78
     * @return null|string (like 'dns')
79
     */
80
    private function getModuleName($route)
81
    {
82
        if ($route) {
83
            if (strpos($route, '/') !== false) {
84
                list($id, $route) = explode('/', ltrim($route, '/'), 2);
0 ignored issues
show
Unused Code introduced by
The assignment to $route is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
85
            } else {
86
                $id = $route;
87
                $route = '';
0 ignored issues
show
Unused Code introduced by
$route is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
88
            }
89
90
            return $id;
91
        }
92
93
        return null;
94
    }
95
96
    /**
97
     * {@inheritdoc}
98
     */
99
    protected function renderItems($items)
100
    {
101
        $n = count($items);
102
        $lines = [];
103
        foreach ($items as $i => $item) {
104
            $options = array_merge($this->itemOptions, ArrayHelper::getValue($item, 'options', []));
105
            $tag = ArrayHelper::remove($options, 'tag', 'li');
106
            $class = [];
107
            $parentModuleUrl = isset($item['items']) ? $item : null;
108
            $isAccordionOpen = $this->guessModule($item, $parentModuleUrl['url'][0]);
109
            if ($item['active'] || $isAccordionOpen) {
110
                $class[] = $this->activeCssClass;
111
            }
112
            if ($i === 0 && $this->firstItemCssClass !== null) {
113
                $class[] = $this->firstItemCssClass;
114
            }
115
            if ($i === $n - 1 && $this->lastItemCssClass !== null) {
116
                $class[] = $this->lastItemCssClass;
117
            }
118
            $menu = $this->renderItem($item);
119
            if (!empty($item['items'])) {
120
                $class[] = $this->treeClass;
121
                $menu .= strtr($this->submenuTemplate, [
122
                    '{items}' => $this->renderItems($item['items']),
123
                ]);
124
            }
125
            if (!empty($class)) {
126
                if (empty($options['class'])) {
127
                    $options['class'] = implode(' ', $class);
128
                } else {
129
                    $options['class'] .= ' ' . implode(' ', $class);
130
                }
131
            }
132
            $lines[] = Html::tag($tag, $menu, $options);
133
        }
134
135
        return implode("\n", $lines);
136
    }
137
138
    /**
139
     * {@inheritdoc}
140
     */
141
    protected function renderItem($item)
142
    {
143
        $no_icon = $item['icon'] === false || empty($item['url']) || empty($this->defaultIcon);
144
145
        return strtr(ArrayHelper::getValue($item, 'template', isset($item['url']) ? $this->linkTemplate : $this->labelTemplate), [
146
            '{url}' => isset($item['url']) ? Url::to($item['url']) : null,
147
            '{icon}' => $no_icon ? '' : sprintf('<i class="%s"></i>', static::iconClass($item['icon'] ?: $this->defaultIcon)),
148
            '{iconSpace}' => $no_icon ? '' : '&nbsp;',
149
            '{label}' => $item['label'],
150
            '{arrow}' => !empty($item['items']) ? '<i class="fa pull-right fa-angle-left"></i>' : '',
151
            '{linkOptions}' => Html::renderTagAttributes(ArrayHelper::getValue($item, 'linkOptions', [])),
152
        ]);
153
    }
154
155
    public static function iconClass($icon)
156
    {
157
        return (substr($icon, 0, 3) === 'fa-' ? 'fa fa-fw ' : '') . $icon;
158
    }
159
160
    /**
161
     * {@inheritdoc}
162
     */
163
    protected function normalizeItems($items, &$active)
164
    {
165
        foreach ($items as &$item) {
166
            if (isset($item['visible']) && $item['visible'] instanceof Closure) {
167
                $item['visible'] = call_user_func($item['visible']);
168
            }
169
        }
170
171
        return parent::normalizeItems($items, $active);
172
    }
173
}
174