Passed
Pull Request — master (#59)
by Wilmer
03:00
created

Normalizer::headerAttributes()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 2
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 5
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Widgets\Helper;
6
7
use InvalidArgumentException;
8
use Yiisoft\Html\Html;
9
use Yiisoft\Html\Tag\I;
10
use Yiisoft\Html\Tag\Span;
11
12
final class Normalizer
13
{
14
    /**
15
     * Normalize the given array of items for the dropdown.
16
     */
17
    public static function dropdown(array $items): array
18
    {
19
        /**
20
         * @psalm-var array[] $items
21
         * @psalm-suppress RedundantConditionGivenDocblockType
22
         */
23
        foreach ($items as $i => $child) {
24
            if (is_array($child)) {
25
                $items[$i]['label'] = self::renderLabel(
26
                    self::label($child),
27
                    self::icon($child),
28
                    self::iconAttributes($child),
29
                    self::iconClass($child),
30
                    self::iconContainerAttributes($child),
31
                );
32
                $items[$i]['active'] = self::active($child, '', '', false);
33
                $items[$i]['disabled'] = self::disabled($child);
34
                $items[$i]['enclose'] = self::enclose($child);
35
                $items[$i]['headerAttributes'] = self::headerAttributes($child);
36
                $items[$i]['itemContainerAttributes'] = self::itemContainerAttributes($child);
37
                $items[$i]['link'] = self::link($child, '/');
38
                $items[$i]['linkAttributes'] = self::linkAttributes($child);
39
                $items[$i]['toggleAttributes'] = self::toggleAttributes($child);
40
                $items[$i]['visible'] = self::visible($child);
41
42
                if (isset($child['items']) && is_array($child['items'])) {
43
                    $items[$i]['items'] = self::dropdown($child['items']);
44
                } else {
45
                    $items[$i]['items'] = [];
46
                }
47
            }
48
        }
49
50
        return $items;
51
    }
52
53
    /**
54
     * Normalize the given array of items for the menu.
55
     */
56
    public static function menu(
57
        array $items,
58
        string $currentPath,
59
        bool $activateItems,
60
        array $iconContainerAttributes = []
61
    ): array {
62
        /**
63
         * @psalm-var array[] $items
64
         * @psalm-suppress RedundantConditionGivenDocblockType
65
         */
66
        foreach ($items as $i => $child) {
67
            if (is_array($child)) {
68
                if (isset($child['items']) && is_array($child['items'])) {
69
                    $items[$i]['items'] = self::menu(
70
                        $child['items'],
71
                        $currentPath,
72
                        $activateItems,
73
                        $iconContainerAttributes,
74
                    );
75
                } else {
76
                    $items[$i]['link'] = self::link($child);
77
                    $items[$i]['linkAttributes'] = self::linkAttributes($child);
78
                    $items[$i]['active'] = self::active(
79
                        $child,
80
                        $items[$i]['link'],
81
                        $currentPath,
82
                        $activateItems
83
                    );
84
                    $items[$i]['disabled'] = self::disabled($child);
85
                    $items[$i]['visible'] = self::visible($child);
86
                    $items[$i]['label'] = self::renderLabel(
87
                        self::label($child),
88
                        self::icon($child),
89
                        self::iconAttributes($child),
90
                        self::iconClass($child),
91
                        self::iconContainerAttributes($child, $iconContainerAttributes),
92
                    );
93
                }
94
            }
95
        }
96
97
        return $items;
98
    }
99
100
    private static function active(array $item, string $link, string $currentPath, bool $activateItems): bool
101
    {
102
        if (!array_key_exists('active', $item)) {
103
            return self::isItemActive($link, $currentPath, $activateItems);
104
        }
105
106
        return is_bool($item['active']) ? $item['active'] : false;
107
    }
108
109
    private static function disabled(array $item): bool
110
    {
111
        return array_key_exists('disabled', $item) && is_bool($item['disabled']) ? $item['disabled'] : false;
112
    }
113
114
    private static function enclose(array $item): bool
115
    {
116
        return array_key_exists('enclose', $item) && is_bool($item['enclose']) ? $item['enclose'] : true;
117
    }
118
119
    private static function headerAttributes(array $item): array
120
    {
121
        return array_key_exists('headerAttributes', $item) && is_array($item['headerAttributes'])
122
            ? $item['headerAttributes']
123
            : [];
124
    }
125
126
    private static function icon(array $item): string
127
    {
128
        return array_key_exists('icon', $item) && is_string($item['icon']) ? $item['icon'] : '';
129
    }
130
131
    private static function iconAttributes(array $item): array
132
    {
133
        return array_key_exists('iconAttributes', $item) && is_array($item['iconAttributes'])
134
            ? $item['iconAttributes'] : [];
135
    }
136
137
    private static function iconClass(array $item): string
138
    {
139
        return array_key_exists('iconClass', $item) && is_string($item['iconClass']) ? $item['iconClass'] : '';
140
    }
141
142
    private static function iconContainerAttributes(array $item, array $iconContainerAttributes = []): array
143
    {
144
        return array_key_exists('iconContainerAttributes', $item) && is_array($item['iconContainerAttributes'])
145
            ? $item['iconContainerAttributes'] : $iconContainerAttributes;
146
    }
147
148
    /**
149
     * Checks whether a menu item is active.
150
     *
151
     * This is done by checking match that specified in the `url` option of the menu item.
152
     *
153
     * @param string $link The link of the menu item.
154
     * @param string $currentPath The current path.
155
     * @param bool $activateItems Whether to activate items having no link.
156
     *
157
     * @return bool Whether the menu item is active.
158
     */
159
    private static function isItemActive(string $link, string $currentPath, bool $activateItems): bool
160
    {
161
        return $link === $currentPath && $activateItems;
162
    }
163
164
    private static function itemContainerAttributes(array $item): array
165
    {
166
        return array_key_exists('itemContainerAttributes', $item) && is_array($item['itemContainerAttributes'])
167
            ? $item['itemContainerAttributes'] : [];
168
    }
169
170
    private static function label(array $item): string
171
    {
172
        if (!isset($item['label'])) {
173
            throw new InvalidArgumentException('The "label" option is required.');
174
        }
175
176
        if (!is_string($item['label'])) {
177
            throw new InvalidArgumentException('The "label" option must be a string.');
178
        }
179
180
        if ($item['label'] === '' && !isset($item['icon'])) {
181
            throw new InvalidArgumentException('The "label" cannot be an empty string.');
182
        }
183
184
        /** @var bool */
185
        $encode = $item['encode'] ?? true;
186
187
        return $encode ? Html::encode($item['label']) : $item['label'];
188
    }
189
190
    private static function link(array $item, string $defaultValue = ''): string
191
    {
192
        return array_key_exists('link', $item) && is_string($item['link']) ? $item['link'] : $defaultValue;
193
    }
194
195
    private static function linkAttributes(array $item): array
196
    {
197
        return array_key_exists('linkAttributes', $item) && is_array($item['linkAttributes'])
198
            ? $item['linkAttributes'] : [];
199
    }
200
201
    private static function renderLabel(
202
        string $label,
203
        string $icon,
204
        array $iconAttributes,
205
        string $iconClass,
206
        array $iconContainerAttributes
207
    ): string {
208
        $html = '';
209
210
        if ($iconClass !== '') {
211
            Html::addCssClass($iconAttributes, $iconClass);
212
        }
213
214
        if ($icon !== '' || $iconAttributes !== [] || $iconClass !== '') {
215
            $i = I::tag()->addAttributes($iconAttributes)->content($icon);
216
            $html = Span::tag()->addAttributes($iconContainerAttributes)->content($i)->encode(false)->render();
217
        }
218
219
        if ($label !== '') {
220
            $html .= $label;
221
        }
222
223
        return $html;
224
    }
225
226
    private static function toggleAttributes(array $item): array
227
    {
228
        return array_key_exists('toggleAttributes', $item) && is_array($item['toggleAttributes'])
229
            ? $item['toggleAttributes'] : [];
230
    }
231
232
    private static function visible(array $item): bool
233
    {
234
        return array_key_exists('visible', $item) && is_bool($item['visible']) ? $item['visible'] : true;
235
    }
236
}
237