1
|
|
|
<?php
|
2
|
|
|
/**
|
3
|
|
|
* @author Sergey Glagolev <[email protected]>
|
4
|
|
|
* @link https://github.com/shogodev/argilla/
|
5
|
|
|
* @copyright Copyright © 2003-2014 Shogo
|
6
|
|
|
* @license http://argilla.ru/LICENSE
|
7
|
|
|
* @package backend.components
|
8
|
|
|
*
|
9
|
|
|
* Класс для работы с модулями бэкенда.
|
10
|
|
|
* Методы используются для построения меню групп, для построения меню отдельных групп
|
11
|
|
|
*/
|
12
|
|
|
Yii::import('backend.modules.brac.components.AccessHelper');
|
13
|
|
|
Yii::import('backend.modules.brac.models');
|
14
|
|
|
|
15
|
|
|
class BMenu extends CComponent
|
16
|
|
|
{
|
17
|
|
|
public $groupNames = array(
|
18
|
|
|
'content' => 'Контент',
|
19
|
|
|
'seo' => 'SEO',
|
20
|
|
|
'settings' => 'Настройки',
|
21
|
|
|
'help' => 'Помощь',
|
22
|
|
|
);
|
23
|
|
|
|
24
|
|
|
private $groups = array();
|
25
|
|
|
|
26
|
|
|
private $modules;
|
27
|
|
|
|
28
|
|
|
private $submodules = array();
|
29
|
|
|
|
30
|
|
|
/**
|
31
|
|
|
* @var BController
|
32
|
|
|
*/
|
33
|
|
|
private $controller;
|
34
|
|
|
|
35
|
|
|
/**
|
36
|
|
|
* @var BModule
|
37
|
|
|
*/
|
38
|
|
|
private $currentModule;
|
39
|
|
|
|
40
|
|
|
/**
|
41
|
|
|
* @var string
|
42
|
|
|
*/
|
43
|
|
|
private $currentGroup;
|
44
|
|
|
|
45
|
|
|
public function init()
|
46
|
|
|
{
|
47
|
|
|
$this->controller = Yii::app()->controller;
|
48
|
|
|
$this->currentModule = $this->controller->module;
|
49
|
|
|
|
50
|
|
|
if( $this->currentModule && !empty($this->currentModule->group) )
|
51
|
|
|
$this->currentGroup = $this->currentModule->group;
|
52
|
|
|
|
53
|
|
|
$this->buildStructure(Yii::app()->getModules());
|
54
|
|
|
|
55
|
|
|
$this->sort();
|
56
|
|
|
}
|
57
|
|
|
|
58
|
|
|
public function getGroups()
|
59
|
|
|
{
|
60
|
|
|
return $this->groups;
|
61
|
|
|
}
|
62
|
|
|
|
63
|
|
|
public function getModules($hideOneModule = true)
|
64
|
|
|
{
|
65
|
|
|
$modules = Arr::get($this->modules, $this->currentGroup, array());
|
66
|
|
|
return count($modules) < 2 && $hideOneModule ? array() : $modules;
|
67
|
|
|
}
|
68
|
|
|
|
69
|
|
|
/**
|
70
|
|
|
* @param bool $hideOneController - не строим подменю, если контроллер единственный
|
71
|
|
|
*
|
72
|
|
|
* @return array
|
73
|
|
|
*/
|
74
|
|
|
public function getSubmodules($hideOneController = true)
|
75
|
|
|
{
|
76
|
|
|
return count($this->submodules) < 2 && $hideOneController ? array() : $this->submodules;
|
77
|
|
|
}
|
78
|
|
|
|
79
|
|
|
public function getDefaultRout($default = '')
|
80
|
|
|
{
|
81
|
|
|
if( $groups = $this->getGroups() )
|
82
|
|
|
{
|
83
|
|
|
return Arr::reset($groups)['route'];
|
84
|
|
|
}
|
85
|
|
|
|
86
|
|
|
return $default;
|
87
|
|
|
}
|
88
|
|
|
|
89
|
|
|
/**
|
90
|
|
|
* @param array $filteredModules
|
91
|
|
|
* @param $parent
|
92
|
|
|
*
|
93
|
|
|
* @return BModule[]
|
94
|
|
|
* @throws CException
|
95
|
|
|
* @throws ClassNotFoundException
|
96
|
|
|
*/
|
97
|
|
|
private function getAllowedModules(array $filteredModules, $parent)
|
98
|
|
|
{
|
99
|
|
|
$modules = array();
|
100
|
|
|
|
101
|
|
|
foreach($filteredModules as $moduleId => $moduleConfig)
|
102
|
|
|
{
|
103
|
|
|
if( empty($moduleConfig['autoloaded']) || $moduleConfig['autoloaded'] == false )
|
104
|
|
|
continue;
|
105
|
|
|
|
106
|
|
|
Yii::import($moduleConfig['class']);
|
107
|
|
|
$moduleClassName = ucfirst($moduleId).'Module';
|
108
|
|
|
|
109
|
|
|
if( !class_exists($moduleClassName) )
|
110
|
|
|
{
|
111
|
|
|
throw new ClassNotFoundException($moduleClassName, $moduleConfig['class']);
|
112
|
|
|
}
|
113
|
|
|
|
114
|
|
|
$modules[$moduleId] = new $moduleClassName($moduleId, $parent);
|
115
|
|
|
|
116
|
|
|
if( !empty($moduleConfig['modules']) )
|
117
|
|
|
{
|
118
|
|
|
$modules[$moduleId]->setModules($moduleConfig['modules']);
|
119
|
|
|
}
|
120
|
|
|
}
|
121
|
|
|
|
122
|
|
|
return $modules;
|
123
|
|
|
}
|
124
|
|
|
|
125
|
|
|
/**
|
126
|
|
|
* @param array $modules
|
127
|
|
|
* @param BModule $parent|null
|
|
|
|
|
128
|
|
|
* @throws CException
|
129
|
|
|
*/
|
130
|
|
|
private function buildStructure(array $modules, $parent = null)
|
131
|
|
|
{
|
132
|
|
|
$filteredModules = AccessHelper::filterModulesByAccess($modules);
|
133
|
|
|
|
134
|
|
|
$allowedModules = $this->getAllowedModules($filteredModules, $parent);
|
135
|
|
|
|
136
|
|
|
foreach($allowedModules as $moduleId => $module)
|
137
|
|
|
{
|
138
|
|
|
if( !$this->allowedModule($module) )
|
139
|
|
|
continue;
|
140
|
|
|
|
141
|
|
|
if( $this->isModuleActive($module) )
|
142
|
|
|
{
|
143
|
|
|
$this->createSubmodulesMenu($module);
|
144
|
|
|
}
|
145
|
|
|
|
146
|
|
|
if( $this->needCreateModulesMenu($module) )
|
147
|
|
|
{
|
148
|
|
|
if( $this->createGroupsMenu($module) )
|
149
|
|
|
{
|
150
|
|
|
if( !$this->createFakeModulesMenu($module) )
|
|
|
|
|
151
|
|
|
$this->createModulesMenu($module);
|
152
|
|
|
}
|
153
|
|
|
}
|
154
|
|
|
|
155
|
|
|
if( $module->getModules() )
|
156
|
|
|
{
|
157
|
|
|
$this->buildStructure($module->getModules(), $module);
|
158
|
|
|
}
|
159
|
|
|
}
|
160
|
|
|
}
|
161
|
|
|
|
162
|
|
|
/**
|
163
|
|
|
* @param BModule $module
|
164
|
|
|
*
|
165
|
|
|
* @return bool
|
166
|
|
|
*/
|
167
|
|
|
private function isModuleActive(BModule $module)
|
168
|
|
|
{
|
169
|
|
|
if( !$this->currentModule )
|
170
|
|
|
return false;
|
171
|
|
|
|
172
|
|
|
if( $this->currentModule->getName() == $module->getName() )
|
|
|
|
|
173
|
|
|
return true;
|
174
|
|
|
|
175
|
|
|
if( $currentModuleParents = $this->currentModule->getParents() )
|
176
|
|
|
{
|
177
|
|
|
if( isset($currentModuleParents[$module->getName()]) )
|
|
|
|
|
178
|
|
|
return true;
|
179
|
|
|
}
|
180
|
|
|
|
181
|
|
|
if( $parents = $module->getParents() )
|
182
|
|
|
{
|
183
|
|
|
if( isset($parents[$this->currentModule->getName()]) )
|
|
|
|
|
184
|
|
|
return true;
|
185
|
|
|
}
|
186
|
|
|
|
187
|
|
|
if( array_intersect(array_keys($currentModuleParents), array_keys($parents)))
|
188
|
|
|
return true;
|
189
|
|
|
|
190
|
|
|
return false;
|
191
|
|
|
}
|
192
|
|
|
|
193
|
|
|
/**
|
194
|
|
|
* @param BModule $module
|
195
|
|
|
*
|
196
|
|
|
* @return bool
|
197
|
|
|
*/
|
198
|
|
|
private function needCreateModulesMenu(BModule $module)
|
199
|
|
|
{
|
200
|
|
|
return !$module->getParentModule();
|
201
|
|
|
}
|
202
|
|
|
|
203
|
|
|
/**
|
204
|
|
|
* @param BModule $module
|
205
|
|
|
*
|
206
|
|
|
* @return bool
|
207
|
|
|
*/
|
208
|
|
|
private function createGroupsMenu($module)
|
209
|
|
|
{
|
210
|
|
|
if( !isset($this->groups[$module->group]) )
|
211
|
|
|
{
|
212
|
|
|
if( !$controllerClass = $this->getAllowedControllerClass($module) )
|
213
|
|
|
return false;
|
214
|
|
|
|
215
|
|
|
$controllerId = $module->getControllerId($controllerClass);
|
216
|
|
|
|
217
|
|
|
$this->groups[$module->group] = array(
|
218
|
|
|
'label' => Arr::get($this->groupNames, $module->group, $module->group),
|
219
|
|
|
'url' => $module->createUrl($controllerId),
|
220
|
|
|
'route' => implode('/', array($module->getName(), $controllerId)),
|
|
|
|
|
221
|
|
|
'active' => $this->currentGroup == $module->group,
|
222
|
|
|
'itemOptions' => array('class' => $module->group)
|
223
|
|
|
);
|
224
|
|
|
}
|
225
|
|
|
|
226
|
|
|
return true;
|
227
|
|
|
}
|
228
|
|
|
|
229
|
|
|
/**
|
230
|
|
|
* @param BModule $module
|
231
|
|
|
*
|
232
|
|
|
* @return bool
|
233
|
|
|
* @throws CHttpException
|
234
|
|
|
*/
|
235
|
|
|
private function createModulesMenu($module)
|
236
|
|
|
{
|
237
|
|
|
if( !$controllerClass = $this->getAllowedControllerClass($module) )
|
238
|
|
|
return false;
|
239
|
|
|
|
240
|
|
|
$controllerId = $module->getControllerId($controllerClass);
|
241
|
|
|
|
242
|
|
|
$this->modules[$module->group][$module->getName()] = array(
|
|
|
|
|
243
|
|
|
'label' => $module->name,
|
244
|
|
|
'url' => $module->createUrl($controllerId),
|
245
|
|
|
'active' => $this->isModuleActive($module),
|
246
|
|
|
'itemOptions' => array('class' => $module->id),
|
247
|
|
|
'position' => $module->position,
|
248
|
|
|
'module' => $module
|
249
|
|
|
);
|
250
|
|
|
}
|
251
|
|
|
|
252
|
|
|
/**
|
253
|
|
|
* Добавляет в меню виртуальные контроллеры модуля
|
254
|
|
|
*
|
255
|
|
|
* @param BModule $module
|
256
|
|
|
*
|
257
|
|
|
* @return bool
|
258
|
|
|
* @throws CHttpException
|
259
|
|
|
*/
|
260
|
|
|
private function createFakeModulesMenu($module)
|
261
|
|
|
{
|
262
|
|
|
if( $fakeMenu = $module->getMenuControllers() )
|
263
|
|
|
{
|
264
|
|
|
foreach($fakeMenu as $key => $menuItem)
|
265
|
|
|
{
|
266
|
|
|
$subMenu = Arr::cut($menuItem, 'menu', array());
|
|
|
|
|
267
|
|
|
|
268
|
|
|
foreach($subMenu as $controllerName)
|
|
|
|
|
269
|
|
|
{
|
270
|
|
|
$controllerClass = $controllerName.'Controller';
|
271
|
|
|
|
272
|
|
|
if( AccessHelper::checkAccessByNameClasses(get_class($module), $controllerClass) )
|
273
|
|
|
{
|
274
|
|
|
$controllerId = $module->getControllerId($controllerClass);
|
275
|
|
|
|
276
|
|
|
if( !isset($this->modules[$module->group][$key]) )
|
277
|
|
|
{
|
278
|
|
|
$this->modules[$module->group][$key] = $menuItem;
|
279
|
|
|
$this->modules[$module->group][$key]['url'] = $module->createUrl($controllerId);
|
280
|
|
|
}
|
281
|
|
|
|
282
|
|
|
$this->modules[$module->group][$key]['menu'][$controllerId] = $controllerName;
|
283
|
|
|
}
|
284
|
|
|
}
|
285
|
|
|
}
|
286
|
|
|
|
287
|
|
|
if( isset($this->controller->moduleMenu) )
|
288
|
|
|
$this->modules[$module->group][$this->controller->moduleMenu]['active'] = true;
|
289
|
|
|
|
290
|
|
|
return true;
|
291
|
|
|
}
|
292
|
|
|
}
|
293
|
|
|
|
294
|
|
|
/**
|
295
|
|
|
* @param BModule $module
|
296
|
|
|
*
|
297
|
|
|
* @return array
|
298
|
|
|
*/
|
299
|
|
|
private function createSubmodulesMenu($module)
|
300
|
|
|
{
|
301
|
|
|
foreach($module->controllerMap as $id => $controllerClass)
|
302
|
|
|
{
|
303
|
|
|
if( !AccessHelper::checkAccessByNameClasses(get_class($module), $controllerClass) )
|
304
|
|
|
continue;
|
305
|
|
|
|
306
|
|
|
/**
|
307
|
|
|
* @var BController $controller
|
308
|
|
|
*/
|
309
|
|
|
$controller = new $controllerClass($id, null);
|
310
|
|
|
|
311
|
|
|
if( !$controller->showInMenu )
|
312
|
|
|
continue;
|
313
|
|
|
|
314
|
|
|
// Убираем ненужные виртуальные контроллеры, которые уже отобразились в меню
|
315
|
|
|
if( $fakeControllers = $module->getMenuControllers() )
|
316
|
|
|
{
|
317
|
|
|
if( !(isset($controller->moduleMenu, $this->controller->moduleMenu) && in_array(BApplication::CLASS_PREFIX.ucfirst($controller->id), $fakeControllers[$this->controller->moduleMenu]['menu'])) )
|
318
|
|
|
continue;
|
319
|
|
|
}
|
320
|
|
|
|
321
|
|
|
if( !isset($controller->enabled) || $controller->enabled === true )
|
322
|
|
|
{
|
323
|
|
|
$this->submodules[$id] = array(
|
324
|
|
|
'label' => $controller->name,
|
325
|
|
|
'url' => $module->createUrl($controller->id),
|
326
|
|
|
'active' => $this->controller->id === $id || ucfirst($this->controller->id) === BApplication::CLASS_PREFIX.ucfirst($id),
|
327
|
|
|
'position' => $controller->position,
|
328
|
|
|
'itemOptions' => array('class' => $id),
|
329
|
|
|
);
|
330
|
|
|
}
|
331
|
|
|
}
|
332
|
|
|
}
|
333
|
|
|
|
334
|
|
|
private function getAllowedControllerClass(BModule $module)
|
335
|
|
|
{
|
336
|
|
|
$defaultController = $module->defaultController.'Controller';
|
337
|
|
|
|
338
|
|
|
if( !class_exists($defaultController) )
|
339
|
|
|
throw new CHttpException(500, 'Не удалось найти defaultController '.$defaultController);
|
340
|
|
|
|
341
|
|
|
if( AccessHelper::checkAccessByNameClasses(get_class($module), $defaultController) )
|
342
|
|
|
return $defaultController;
|
343
|
|
|
|
344
|
|
|
foreach($module->controllerMap as $controller)
|
345
|
|
|
{
|
346
|
|
|
if( AccessHelper::checkAccessByNameClasses(get_class($module), $controller) )
|
347
|
|
|
return $controller;
|
348
|
|
|
}
|
349
|
|
|
|
350
|
|
|
return null;
|
351
|
|
|
}
|
352
|
|
|
|
353
|
|
|
private function sort()
|
354
|
|
|
{
|
355
|
|
|
$this->sortGroups();
|
|
|
|
|
356
|
|
|
$this->sortModules();
|
357
|
|
|
$this->sortSubmodiles();
|
358
|
|
|
}
|
359
|
|
|
|
360
|
|
|
private function sortGroups()
|
361
|
|
|
{
|
362
|
|
|
}
|
363
|
|
|
|
364
|
|
|
private function sortModules()
|
365
|
|
|
{
|
366
|
|
|
if( empty($this->modules) )
|
367
|
|
|
return;
|
368
|
|
|
|
369
|
|
|
foreach($this->modules as $key => $data)
|
370
|
|
|
{
|
371
|
|
|
uasort($this->modules[$key], function($a, $b) {
|
372
|
|
|
return $a['label'] > $b['label'];
|
373
|
|
|
});
|
374
|
|
|
}
|
375
|
|
|
}
|
376
|
|
|
|
377
|
|
|
private function sortSubmodiles()
|
378
|
|
|
{
|
379
|
|
|
uasort($this->submodules, function($a, $b) {
|
380
|
|
|
return $a['position'] > $b['position'];
|
381
|
|
|
});
|
382
|
|
|
}
|
383
|
|
|
|
384
|
|
|
/**
|
385
|
|
|
* @param BModule $module
|
386
|
|
|
*
|
387
|
|
|
* @return bool
|
388
|
|
|
*/
|
389
|
|
|
private function allowedModule($module)
|
390
|
|
|
{
|
391
|
|
|
return $module instanceof BModule && !empty($module->group) && $module->enabled;
|
392
|
|
|
}
|
393
|
|
|
} |
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.
Consider the following example. The parameter
$ireland
is not defined by the methodfinale(...)
.The most likely cause is that the parameter was changed, but the annotation was not.