BiFace_Server_Lite/vendor/yii2mod/yii2-rbac/models/RouteModel.php
2020-03-27 10:13:51 +07:00

294 lines
8.2 KiB
PHP

<?php
namespace yii2mod\rbac\models;
use Yii;
use yii\base\BaseObject;
use yii\base\Controller;
use yii\base\Module;
use yii\caching\TagDependency;
use yii\helpers\VarDumper;
/**
* Class RouteModel
*
* @package yii2mod\rbac\models
*/
class RouteModel extends BaseObject
{
/**
* @var string cache tag
*/
const CACHE_TAG = 'yii2mod.rbac.route';
/**
* @var \yii\caching\Cache
*/
public $cache;
/**
* @var int cache duration
*/
public $cacheDuration = 3600;
/**
* @var array list of module IDs that will be excluded
*/
public $excludeModules = [];
/**
* @var \yii\rbac\ManagerInterface
*/
protected $manager;
/**
* RouteModel constructor.
*
* @param array $config
*/
public function __construct(array $config = [])
{
$this->cache = Yii::$app->cache;
$this->manager = Yii::$app->authManager;
parent::__construct($config);
}
/**
* Assign items
*
* @param array $routes
*
* @return bool
*/
public function addNew(array $routes): bool
{
foreach ($routes as $route) {
$this->manager->add($this->manager->createPermission('/' . trim($route, ' /')));
}
$this->invalidate();
return true;
}
/**
* Remove items
*
* @param array $routes
*
* @return bool
*/
public function remove(array $routes): bool
{
foreach ($routes as $route) {
$item = $this->manager->createPermission('/' . trim($route, '/'));
$this->manager->remove($item);
}
$this->invalidate();
return true;
}
/**
* Get available and assigned routes
*
* @return array
*/
public function getAvailableAndAssignedRoutes(): array
{
$routes = $this->getAppRoutes();
$exists = [];
foreach (array_keys($this->manager->getPermissions()) as $name) {
if ($name[0] !== '/') {
continue;
}
$exists[] = $name;
unset($routes[$name]);
}
return [
'available' => array_keys($routes),
'assigned' => $exists,
];
}
/**
* Get list of application routes
*
* @param null|string $module
*
* @return array
*/
public function getAppRoutes(string $module = null): array
{
if ($module === null) {
$module = Yii::$app;
} else {
$module = Yii::$app->getModule($module);
}
$key = [__METHOD__, $module->getUniqueId()];
$result = (($this->cache !== null) ? $this->cache->get($key) : false);
if ($result === false) {
$result = [];
$this->getRouteRecursive($module, $result);
if ($this->cache !== null) {
$this->cache->set($key, $result, $this->cacheDuration, new TagDependency([
'tags' => self::CACHE_TAG,
]));
}
}
return $result;
}
/**
* Invalidate the cache
*/
public function invalidate()
{
if ($this->cache !== null) {
TagDependency::invalidate($this->cache, self::CACHE_TAG);
}
}
/**
* Get route(s) recursive
*
* @param Module $module
* @param array $result
*/
protected function getRouteRecursive(Module $module, &$result)
{
if (!in_array($module->id, $this->excludeModules)) {
$token = "Get Route of '" . get_class($module) . "' with id '" . $module->uniqueId . "'";
Yii::beginProfile($token, __METHOD__);
try {
foreach ($module->getModules() as $id => $child) {
if (($child = $module->getModule($id)) !== null) {
$this->getRouteRecursive($child, $result);
}
}
foreach ($module->controllerMap as $id => $type) {
$this->getControllerActions($type, $id, $module, $result);
}
$namespace = trim($module->controllerNamespace, '\\') . '\\';
$this->getControllerFiles($module, $namespace, '', $result);
$all = '/' . ltrim($module->uniqueId . '/*', '/');
$result[$all] = $all;
} catch (\Exception $exc) {
Yii::error($exc->getMessage(), __METHOD__);
}
Yii::endProfile($token, __METHOD__);
}
}
/**
* Get list controllers under module
*
* @param Module $module
* @param string $namespace
* @param string $prefix
* @param mixed $result
*/
protected function getControllerFiles(Module $module, string $namespace, string $prefix, &$result)
{
$path = Yii::getAlias('@' . str_replace('\\', '/', $namespace), false);
$token = "Get controllers from '$path'";
Yii::beginProfile($token, __METHOD__);
try {
if (!is_dir($path)) {
return;
}
foreach (scandir($path) as $file) {
if ($file == '.' || $file == '..') {
continue;
}
if (is_dir($path . '/' . $file) && preg_match('%^[a-z0-9_/]+$%i', $file . '/')) {
$this->getControllerFiles($module, $namespace . $file . '\\', $prefix . $file . '/', $result);
} elseif (strcmp(substr($file, -14), 'Controller.php') === 0) {
$baseName = substr(basename($file), 0, -14);
$name = strtolower(preg_replace('/(?<![A-Z])[A-Z]/', ' \0', $baseName));
$id = ltrim(str_replace(' ', '-', $name), '-');
$className = $namespace . $baseName . 'Controller';
if (strpos($className, '-') === false && class_exists($className) && is_subclass_of($className, 'yii\base\Controller')) {
$this->getControllerActions($className, $prefix . $id, $module, $result);
}
}
}
} catch (\Exception $exc) {
Yii::error($exc->getMessage(), __METHOD__);
}
Yii::endProfile($token, __METHOD__);
}
/**
* Get list actions of controller
*
* @param mixed $type
* @param string $id
* @param Module $module
* @param mixed $result
*/
protected function getControllerActions($type, $id, Module $module, &$result)
{
$token = 'Create controller with config=' . VarDumper::dumpAsString($type) . " and id='$id'";
Yii::beginProfile($token, __METHOD__);
try {
/* @var $controller Controller */
$controller = Yii::createObject($type, [$id, $module]);
$this->getActionRoutes($controller, $result);
$all = "/{$controller->uniqueId}/*";
$result[$all] = $all;
} catch (\Exception $exc) {
Yii::error($exc->getMessage(), __METHOD__);
}
Yii::endProfile($token, __METHOD__);
}
/**
* Get route of action
*
* @param Controller $controller
* @param array $result all controller action
*/
protected function getActionRoutes(Controller $controller, &$result)
{
$token = "Get actions of controller '" . $controller->uniqueId . "'";
Yii::beginProfile($token, __METHOD__);
try {
$prefix = '/' . $controller->uniqueId . '/';
foreach ($controller->actions() as $id => $value) {
$result[$prefix . $id] = $prefix . $id;
}
$class = new \ReflectionClass($controller);
foreach ($class->getMethods() as $method) {
$name = $method->getName();
if ($method->isPublic() && !$method->isStatic() && strpos($name, 'action') === 0 && $name !== 'actions') {
$name = strtolower(preg_replace('/(?<![A-Z])[A-Z]/', ' \0', substr($name, 6)));
$id = $prefix . ltrim(str_replace(' ', '-', $name), '-');
$result[$id] = $id;
}
}
} catch (\Exception $exc) {
Yii::error($exc->getMessage(), __METHOD__);
}
Yii::endProfile($token, __METHOD__);
}
}