1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* CakeCMS Core |
4
|
|
|
* |
5
|
|
|
* This file is part of the of the simple cms based on CakePHP 3. |
6
|
|
|
* For the full copyright and license information, please view the LICENSE |
7
|
|
|
* file that was distributed with this source code. |
8
|
|
|
* |
9
|
|
|
* @package Core |
10
|
|
|
* @license MIT |
11
|
|
|
* @copyright MIT License http://www.opensource.org/licenses/mit-license.php |
12
|
|
|
* @link https://github.com/CakeCMS/Core". |
13
|
|
|
* @author Sergey Kalistratov <[email protected]> |
14
|
|
|
*/ |
15
|
|
|
|
16
|
|
|
namespace Core; |
17
|
|
|
|
18
|
|
|
use Cake\Log\Log; |
19
|
|
|
use Cake\Utility\Hash; |
20
|
|
|
use Cake\Utility\Inflector; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* Class Nav |
24
|
|
|
* |
25
|
|
|
* @package Core |
26
|
|
|
*/ |
27
|
|
|
class Nav |
28
|
|
|
{ |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* Current active menu. |
32
|
|
|
* |
33
|
|
|
* @see CroogoNav::activeMenu() |
34
|
|
|
*/ |
35
|
|
|
protected static $_activeMenu = 'sidebar'; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* Menu items. |
39
|
|
|
* |
40
|
|
|
* @var array |
41
|
|
|
*/ |
42
|
|
|
protected static $_items = ['sidebar' => []]; |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* Default params. |
46
|
|
|
* |
47
|
|
|
* @var array |
48
|
|
|
*/ |
49
|
|
|
protected static $_defaults = [ |
50
|
|
|
'icon' => '', |
51
|
|
|
'title' => false, |
52
|
|
|
'url' => '#', |
53
|
|
|
'weight' => 9999, |
54
|
|
|
'before' => false, |
55
|
|
|
'after' => false, |
56
|
|
|
'access' => [], |
57
|
|
|
'children' => [], |
58
|
|
|
'htmlAttributes' => [], |
59
|
|
|
]; |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* Getter/setter for activeMenu |
63
|
|
|
* |
64
|
|
|
* @param null $menu |
65
|
|
|
* @return null|string |
66
|
|
|
*/ |
67
|
|
|
public static function activeMenu($menu = null) |
68
|
|
|
{ |
69
|
|
|
if ($menu === null) { |
70
|
|
|
$activeMenu = self::$_activeMenu; |
71
|
|
|
} else { |
72
|
|
|
$activeMenu = $menu; |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
if (!array_key_exists($activeMenu, self::$_items)) { |
76
|
|
|
self::$_items[$activeMenu] = []; |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
self::$_activeMenu = $activeMenu; |
80
|
|
|
return $activeMenu; |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Add a menu item. |
85
|
|
|
* |
86
|
|
|
* @param $menu |
87
|
|
|
* @param $path |
88
|
|
|
* @param array $options |
89
|
|
|
*/ |
90
|
|
|
public static function add($menu, $path, $options = []) |
91
|
|
|
{ |
92
|
|
|
// Juggle argument for backward compatibility |
93
|
|
|
if (is_array($path)) { |
94
|
|
|
$options = $path; |
95
|
|
|
$path = $menu; |
96
|
|
|
$menu = self::activeMenu(); |
97
|
|
|
} else { |
98
|
|
|
self::activeMenu($menu); |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
$pathE = explode('.', $path); |
102
|
|
|
$pathE = array_splice($pathE, 0, count($pathE) - 2); |
103
|
|
|
$parent = join('.', $pathE); |
104
|
|
|
|
105
|
|
|
if (!empty($parent) && !Hash::check(self::$_items[$menu], $parent)) { |
106
|
|
|
$title = Inflector::humanize(end($pathE)); |
107
|
|
|
$opt = ['title' => $title]; |
108
|
|
|
self::_setupOptions($opt); |
109
|
|
|
self::add($parent, $opt); |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
self::_setupOptions($options); |
113
|
|
|
$current = Hash::extract(self::$_items[$menu], $path); |
114
|
|
|
|
115
|
|
|
if (!empty($current)) { |
116
|
|
|
self::_replace(self::$_items[$menu], $path, $options); |
117
|
|
|
} else { |
118
|
|
|
self::$_items[$menu] = Hash::insert(self::$_items[$menu], $path, $options); |
119
|
|
|
} |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* Clear all menus. |
124
|
|
|
* |
125
|
|
|
* @param string $menu |
126
|
|
|
* @return void |
127
|
|
|
*/ |
128
|
|
|
public static function clear($menu = 'sidebar') |
129
|
|
|
{ |
130
|
|
|
if ($menu) { |
131
|
|
|
self::_clear($menu); |
132
|
|
|
} else { |
133
|
|
|
self::$_items = []; |
134
|
|
|
} |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
/** |
138
|
|
|
* Gets default settings for menu items. |
139
|
|
|
* |
140
|
|
|
* @return array |
141
|
|
|
*/ |
142
|
|
|
public static function getDefaults() |
143
|
|
|
{ |
144
|
|
|
return self::$_defaults; |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
/** |
148
|
|
|
* Sets or returns menu data in array. |
149
|
|
|
* |
150
|
|
|
* @param string $menu |
151
|
|
|
* @param null $items |
152
|
|
|
* @return array |
153
|
|
|
*/ |
154
|
|
|
public static function items($menu = 'sidebar', $items = null) |
155
|
|
|
{ |
156
|
|
|
if (!is_string($menu)) { |
157
|
|
|
throw new \UnexpectedValueException('Menu id is not a string'); |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
if (!empty($items)) { |
161
|
|
|
self::$_items[$menu] = $items; |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
if (!array_key_exists($menu, self::$_items)) { |
165
|
|
|
Log::error('Invalid menu: ' . $menu); |
166
|
|
|
return []; |
167
|
|
|
} |
168
|
|
|
|
169
|
|
|
return self::$_items[$menu]; |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* Get menus. |
174
|
|
|
* |
175
|
|
|
* @return array |
176
|
|
|
*/ |
177
|
|
|
public static function menus() |
178
|
|
|
{ |
179
|
|
|
return array_keys(self::$_items); |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* Remove a menu item. |
184
|
|
|
* |
185
|
|
|
* @param string $path dot separated path in the array. |
186
|
|
|
* @return void |
187
|
|
|
*/ |
188
|
|
|
public static function remove($path) |
189
|
|
|
{ |
190
|
|
|
self::$_items = Hash::remove(self::$_items, $path); |
|
|
|
|
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
/** |
194
|
|
|
* Clear menu items. |
195
|
|
|
* |
196
|
|
|
* @param $menu |
197
|
|
|
* @throws \UnexpectedValueException |
198
|
|
|
*/ |
199
|
|
|
protected static function _clear($menu) |
200
|
|
|
{ |
201
|
|
|
if (array_key_exists($menu, self::$_items)) { |
202
|
|
|
self::$_items[$menu] = []; |
203
|
|
|
} else { |
204
|
|
|
throw new \UnexpectedValueException('Invalid menu: ' . $menu); |
205
|
|
|
} |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
/** |
209
|
|
|
* Merge $firstArray with $secondArray. |
210
|
|
|
* |
211
|
|
|
* Similar to Hash::merge, except duplicates are removed |
212
|
|
|
* @param array $firstArray |
213
|
|
|
* @param array $secondArray |
214
|
|
|
* @return array |
215
|
|
|
*/ |
216
|
|
|
protected static function _merge($firstArray, $secondArray) |
217
|
|
|
{ |
218
|
|
|
$merged = Hash::merge($firstArray, $secondArray); |
219
|
|
|
foreach ($merged as $key => $val) { |
220
|
|
|
if (is_array($val) && is_int(key($val))) { |
221
|
|
|
$merged[$key] = array_unique($val); |
222
|
|
|
} |
223
|
|
|
} |
224
|
|
|
return $merged; |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
/** |
228
|
|
|
* Replace a menu element. |
229
|
|
|
* |
230
|
|
|
* @param array $target pointer to start of array |
231
|
|
|
* @param string $path path to search for in dot separated format |
232
|
|
|
* @param array $options data to replace with |
233
|
|
|
* @return void |
234
|
|
|
*/ |
235
|
|
|
protected static function _replace(&$target, $path, $options) |
236
|
|
|
{ |
237
|
|
|
$pathE = explode('.', $path); |
238
|
|
|
$path = array_shift($pathE); |
239
|
|
|
$fragment = join('.', $pathE); |
240
|
|
|
|
241
|
|
|
if (!empty($pathE)) { |
242
|
|
|
self::_replace($target[$path], $fragment, $options); |
243
|
|
|
} else { |
244
|
|
|
$target[$path] = self::_merge($target[$path], $options); |
245
|
|
|
} |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
/** |
249
|
|
|
* Setup options. |
250
|
|
|
* |
251
|
|
|
* @param array $options |
252
|
|
|
* @return void |
253
|
|
|
*/ |
254
|
|
|
protected static function _setupOptions(&$options) |
255
|
|
|
{ |
256
|
|
|
$options = self::_merge(self::$_defaults, $options); |
257
|
|
|
foreach ($options['children'] as &$child) { |
258
|
|
|
self::_setupOptions($child); |
259
|
|
|
} |
260
|
|
|
} |
261
|
|
|
} |
262
|
|
|
|
Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.
Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.
To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.
The function can be called with either null or an array for the parameter
$needle
but will only accept an array as$haystack
.