1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace mdm\admin\models; |
4
|
|
|
|
5
|
|
|
use Exception; |
6
|
|
|
use mdm\admin\components\Configs; |
7
|
|
|
use mdm\admin\components\Helper; |
8
|
|
|
use mdm\admin\components\RouteRule; |
9
|
|
|
use Yii; |
10
|
|
|
use yii\caching\TagDependency; |
11
|
|
|
use yii\helpers\VarDumper; |
12
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* Description of Route |
15
|
|
|
* |
16
|
|
|
* @author Misbahul D Munir <[email protected]> |
17
|
|
|
* @since 1.0 |
18
|
|
|
*/ |
19
|
|
|
class Route extends \yii\base\Object |
20
|
|
|
{ |
21
|
|
|
const CACHE_TAG = 'mdm.admin.route'; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* Assign or remove items |
25
|
|
|
* @param array $routes |
26
|
|
|
* @return array |
27
|
|
|
*/ |
28
|
|
|
public function addNew($routes) |
29
|
|
|
{ |
30
|
|
|
$manager = Configs::authManager(); |
31
|
|
|
foreach ($routes as $route) { |
32
|
|
|
try { |
33
|
|
|
$r = explode('&', $route); |
34
|
|
|
$item = $manager->createPermission('/' . trim($route, '/')); |
35
|
|
|
if (count($r) > 1) { |
36
|
|
|
$action = '/' . trim($r[0], '/'); |
37
|
|
|
if (($itemAction = $manager->getPermission($action)) === null) { |
38
|
|
|
$itemAction = $manager->createPermission($action); |
39
|
|
|
$manager->add($itemAction); |
40
|
|
|
} |
41
|
|
|
unset($r[0]); |
42
|
|
View Code Duplication |
foreach ($r as $part) { |
|
|
|
|
43
|
|
|
$part = explode('=', $part); |
44
|
|
|
$item->data['params'][$part[0]] = isset($part[1]) ? $part[1] : ''; |
45
|
|
|
} |
46
|
|
|
$this->setDefaultRule(); |
47
|
|
|
$item->ruleName = RouteRule::RULE_NAME; |
48
|
|
|
$manager->add($item); |
49
|
|
|
$manager->addChild($item, $itemAction); |
50
|
|
|
} else { |
51
|
|
|
$manager->add($item); |
52
|
|
|
} |
53
|
|
|
} catch (Exception $exc) { |
54
|
|
|
Yii::error($exc->getMessage(), __METHOD__); |
55
|
|
|
} |
56
|
|
|
} |
57
|
|
|
Helper::invalidate(); |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* Assign or remove items |
62
|
|
|
* @param array $routes |
63
|
|
|
* @return array |
64
|
|
|
*/ |
65
|
|
|
public function remove($routes) |
66
|
|
|
{ |
67
|
|
|
$manager = Configs::authManager(); |
68
|
|
|
foreach ($routes as $route) { |
69
|
|
|
try { |
70
|
|
|
$item = $manager->createPermission('/' . trim($route, '/')); |
71
|
|
|
$manager->remove($item); |
72
|
|
|
} catch (Exception $exc) { |
73
|
|
|
Yii::error($exc->getMessage(), __METHOD__); |
74
|
|
|
} |
75
|
|
|
} |
76
|
|
|
Helper::invalidate(); |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* Get available and assigned routes |
81
|
|
|
* @return array |
82
|
|
|
*/ |
83
|
|
|
public function getRoutes() |
84
|
|
|
{ |
85
|
|
|
$manager = Configs::authManager(); |
86
|
|
|
$routes = $this->getAppRoutes(); |
87
|
|
|
$exists = []; |
88
|
|
|
foreach (array_keys($manager->getPermissions()) as $name) { |
89
|
|
|
if ($name[0] !== '/') { |
90
|
|
|
continue; |
91
|
|
|
} |
92
|
|
|
$exists[] = $name; |
93
|
|
|
unset($routes[$name]); |
94
|
|
|
} |
95
|
|
|
return [ |
96
|
|
|
'available' => array_keys($routes), |
97
|
|
|
'assigned' => $exists, |
98
|
|
|
]; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* Get list of application routes |
103
|
|
|
* @return array |
104
|
|
|
*/ |
105
|
|
|
public function getAppRoutes($module = null) |
106
|
|
|
{ |
107
|
|
|
if ($module === null) { |
108
|
|
|
$module = Yii::$app; |
109
|
|
|
} elseif (is_string($module)) { |
110
|
|
|
$module = Yii::$app->getModule($module); |
111
|
|
|
} |
112
|
|
|
$key = [__METHOD__, $module->getUniqueId()]; |
113
|
|
|
$cache = Configs::instance()->cache; |
114
|
|
|
if ($cache === null || ($result = $cache->get($key)) === false) { |
115
|
|
|
$result = []; |
116
|
|
|
$this->getRouteRecursive($module, $result); |
117
|
|
|
if ($cache !== null) { |
118
|
|
|
$cache->set($key, $result, Configs::instance()->cacheDuration, new TagDependency([ |
119
|
|
|
'tags' => self::CACHE_TAG, |
120
|
|
|
])); |
121
|
|
|
} |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
return $result; |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* Get route(s) recursive |
129
|
|
|
* @param \yii\base\Module $module |
130
|
|
|
* @param array $result |
131
|
|
|
*/ |
132
|
|
|
protected function getRouteRecursive($module, &$result) |
133
|
|
|
{ |
134
|
|
|
$token = "Get Route of '" . get_class($module) . "' with id '" . $module->uniqueId . "'"; |
135
|
|
|
Yii::beginProfile($token, __METHOD__); |
136
|
|
|
try { |
137
|
|
|
foreach ($module->getModules() as $id => $child) { |
138
|
|
|
if (($child = $module->getModule($id)) !== null) { |
139
|
|
|
$this->getRouteRecursive($child, $result); |
140
|
|
|
} |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
foreach ($module->controllerMap as $id => $type) { |
144
|
|
|
$this->getControllerActions($type, $id, $module, $result); |
|
|
|
|
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
$namespace = trim($module->controllerNamespace, '\\') . '\\'; |
148
|
|
|
$this->getControllerFiles($module, $namespace, '', $result); |
149
|
|
|
$all = '/' . ltrim($module->uniqueId . '/*', '/'); |
150
|
|
|
$result[$all] = $all; |
151
|
|
|
} catch (\Exception $exc) { |
152
|
|
|
Yii::error($exc->getMessage(), __METHOD__); |
153
|
|
|
} |
154
|
|
|
Yii::endProfile($token, __METHOD__); |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
/** |
158
|
|
|
* Get list controller under module |
159
|
|
|
* @param \yii\base\Module $module |
160
|
|
|
* @param string $namespace |
161
|
|
|
* @param string $prefix |
162
|
|
|
* @param mixed $result |
163
|
|
|
* @return mixed |
164
|
|
|
*/ |
165
|
|
|
protected function getControllerFiles($module, $namespace, $prefix, &$result) |
166
|
|
|
{ |
167
|
|
|
$path = Yii::getAlias('@' . str_replace('\\', '/', $namespace), false); |
168
|
|
|
$token = "Get controllers from '$path'"; |
169
|
|
|
Yii::beginProfile($token, __METHOD__); |
170
|
|
|
try { |
171
|
|
|
if (!is_dir($path)) { |
172
|
|
|
return; |
173
|
|
|
} |
174
|
|
|
foreach (scandir($path) as $file) { |
175
|
|
|
if ($file == '.' || $file == '..') { |
176
|
|
|
continue; |
177
|
|
|
} |
178
|
|
|
if (is_dir($path . '/' . $file) && preg_match('%^[a-z0-9_/]+$%i', $file . '/')) { |
179
|
|
|
$this->getControllerFiles($module, $namespace . $file . '\\', $prefix . $file . '/', $result); |
180
|
|
|
} elseif (strcmp(substr($file, -14), 'Controller.php') === 0) { |
181
|
|
|
$baseName = substr(basename($file), 0, -14); |
182
|
|
|
$name = strtolower(preg_replace('/(?<![A-Z])[A-Z]/', ' \0', $baseName)); |
183
|
|
|
$id = ltrim(str_replace(' ', '-', $name), '-'); |
184
|
|
|
$className = $namespace . $baseName . 'Controller'; |
185
|
|
|
if (strpos($className, '-') === false && class_exists($className) && is_subclass_of($className, 'yii\base\Controller')) { |
186
|
|
|
$this->getControllerActions($className, $prefix . $id, $module, $result); |
187
|
|
|
} |
188
|
|
|
} |
189
|
|
|
} |
190
|
|
|
} catch (\Exception $exc) { |
191
|
|
|
Yii::error($exc->getMessage(), __METHOD__); |
192
|
|
|
} |
193
|
|
|
Yii::endProfile($token, __METHOD__); |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
/** |
197
|
|
|
* Get list action of controller |
198
|
|
|
* @param mixed $type |
199
|
|
|
* @param string $id |
200
|
|
|
* @param \yii\base\Module $module |
201
|
|
|
* @param string $result |
202
|
|
|
*/ |
203
|
|
|
protected function getControllerActions($type, $id, $module, &$result) |
204
|
|
|
{ |
205
|
|
|
$token = "Create controller with cofig=" . VarDumper::dumpAsString($type) . " and id='$id'"; |
206
|
|
|
Yii::beginProfile($token, __METHOD__); |
207
|
|
|
try { |
208
|
|
|
/* @var $controller \yii\base\Controller */ |
209
|
|
|
$controller = Yii::createObject($type, [$id, $module]); |
|
|
|
|
210
|
|
|
$this->getActionRoutes($controller, $result); |
|
|
|
|
211
|
|
|
$all = "/{$controller->uniqueId}/*"; |
212
|
|
|
$result[$all] = $all; |
213
|
|
|
} catch (\Exception $exc) { |
214
|
|
|
Yii::error($exc->getMessage(), __METHOD__); |
215
|
|
|
} |
216
|
|
|
Yii::endProfile($token, __METHOD__); |
217
|
|
|
} |
218
|
|
|
|
219
|
|
|
/** |
220
|
|
|
* Get route of action |
221
|
|
|
* @param \yii\base\Controller $controller |
222
|
|
|
* @param array $result all controller action. |
223
|
|
|
*/ |
224
|
|
|
protected function getActionRoutes($controller, &$result) |
225
|
|
|
{ |
226
|
|
|
$token = "Get actions of controller '" . $controller->uniqueId . "'"; |
227
|
|
|
Yii::beginProfile($token, __METHOD__); |
228
|
|
|
try { |
229
|
|
|
$prefix = '/' . $controller->uniqueId . '/'; |
230
|
|
|
foreach ($controller->actions() as $id => $value) { |
231
|
|
|
$result[$prefix . $id] = $prefix . $id; |
232
|
|
|
} |
233
|
|
|
$class = new \ReflectionClass($controller); |
234
|
|
|
foreach ($class->getMethods() as $method) { |
235
|
|
|
$name = $method->getName(); |
|
|
|
|
236
|
|
|
if ($method->isPublic() && !$method->isStatic() && strpos($name, 'action') === 0 && $name !== 'actions') { |
237
|
|
|
$name = strtolower(preg_replace('/(?<![A-Z])[A-Z]/', ' \0', substr($name, 6))); |
238
|
|
|
$id = $prefix . ltrim(str_replace(' ', '-', $name), '-'); |
239
|
|
|
$result[$id] = $id; |
240
|
|
|
} |
241
|
|
|
} |
242
|
|
|
} catch (\Exception $exc) { |
243
|
|
|
Yii::error($exc->getMessage(), __METHOD__); |
244
|
|
|
} |
245
|
|
|
Yii::endProfile($token, __METHOD__); |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
/** |
249
|
|
|
* Ivalidate cache |
250
|
|
|
*/ |
251
|
|
|
public static function invalidate() |
252
|
|
|
{ |
253
|
|
|
if (Configs::cache() !== null) { |
254
|
|
|
TagDependency::invalidate(Configs::cache(), self::CACHE_TAG); |
255
|
|
|
} |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
/** |
259
|
|
|
* Set default rule of parameterize route. |
260
|
|
|
*/ |
261
|
|
|
protected function setDefaultRule() |
262
|
|
|
{ |
263
|
|
|
if (Configs::authManager()->getRule(RouteRule::RULE_NAME) === null) { |
264
|
|
|
Configs::authManager()->add(new RouteRule()); |
265
|
|
|
} |
266
|
|
|
} |
267
|
|
|
} |
268
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.