Skip to content

Commit

Permalink
Added multi app (frontend/backend) support. (#309)
Browse files Browse the repository at this point in the history
* - Added multi app (frontend/backend) support.

* Bugfix

* Bugfix: Expanded cache key by Yii::$app->id to differenciate between apps (frontend/backend).
I did not notice, that $module->getUniqueId() returns an empty string when $module is the app itself. Therefore the cache could not differenciate between frontend and backend. Thus resulting in the same routes for all indicated apps.

* Filter out empty parent items. Sometimes a menu item is defined by url = # and is used as a container for sub-items. If all the subitems are forbidden then this patch removes the parent entry as well.

* Bugfix: Debug bar disappeared. Thanks to yongtiger (see #309 (comment))
  • Loading branch information
firefox747 authored and mdmunir committed Oct 4, 2017
1 parent cbc143c commit 48298cb
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 27 deletions.
25 changes: 15 additions & 10 deletions components/Configs.php
Expand Up @@ -3,19 +3,19 @@
namespace mdm\admin\components;

use Yii;
use yii\db\Connection;
use yii\caching\Cache;
use yii\rbac\ManagerInterface;
use yii\helpers\ArrayHelper;
use yii\db\Connection;
use yii\di\Instance;
use yii\helpers\ArrayHelper;
use yii\rbac\ManagerInterface;

/**
* Configs
* Used for configure some value. To set config you can use [[\yii\base\Application::$params]]
*
* Used to configure some values. To set config you can use [[\yii\base\Application::$params]]
*
* ```
* return [
*
*
* 'mdm.admin.configs' => [
* 'db' => 'customDb',
* 'menuTable' => '{{%admin_menu}}',
Expand All @@ -26,9 +26,9 @@
* ]
* ];
* ```
*
*
* or use [[\Yii::$container]]
*
*
* ```
* Yii::$container->set('mdm\admin\components\Configs',[
* 'db' => 'customDb',
Expand Down Expand Up @@ -94,10 +94,15 @@ class Configs extends \yii\base\Object
public $strict = true;

/**
* @var array
* @var array
*/
public $options;

/**
* @var array|false
*/
public $advanced;

/**
* @var self Instance of self
*/
Expand All @@ -106,7 +111,7 @@ class Configs extends \yii\base\Object
'db' => 'yii\db\Connection',
'userDb' => 'yii\db\Connection',
'cache' => 'yii\caching\Cache',
'authManager' => 'yii\rbac\ManagerInterface'
'authManager' => 'yii\rbac\ManagerInterface',
];

/**
Expand Down
37 changes: 25 additions & 12 deletions components/Helper.php
Expand Up @@ -2,10 +2,11 @@

namespace mdm\admin\components;

use mdm\admin\models\Route;
use Yii;
use yii\web\User;
use yii\helpers\ArrayHelper;
use yii\caching\TagDependency;
use yii\helpers\ArrayHelper;
use yii\web\User;

/**
* Description of Helper
Expand Down Expand Up @@ -57,7 +58,7 @@ protected static function getDefaultRoutes()
}
if ($cache) {
$cache->set($roles, self::$_defaultRoutes, Configs::cacheDuration(), new TagDependency([
'tags' => Configs::CACHE_TAG
'tags' => Configs::CACHE_TAG,
]));
}
}
Expand Down Expand Up @@ -87,7 +88,7 @@ public static function getRoutesByUser($userId)
self::$_userRoutes[$userId] = $routes;
if ($cache) {
$cache->set([__METHOD__, $userId], $routes, Configs::cacheDuration(), new TagDependency([
'tags' => Configs::CACHE_TAG
'tags' => Configs::CACHE_TAG,
]));
}
}
Expand All @@ -104,7 +105,7 @@ public static function getRoutesByUser($userId)
public static function checkRoute($route, $params = [], $user = null)
{
$config = Configs::instance();
$r = static::normalizeRoute($route);
$r = static::normalizeRoute($route, $config->advanced);
if ($config->onlyRegisteredRoute && !isset(static::getRegisteredRoutes()[$r])) {
return true;
}
Expand Down Expand Up @@ -140,18 +141,30 @@ public static function checkRoute($route, $params = [], $user = null)
}
}

protected static function normalizeRoute($route)
/**
* Normalize route
* @param string $route Plain route string
* @param boolean|array $advanced Array containing the advanced configuration. Defaults to false.
* @return string Normalized route string
*/
protected static function normalizeRoute($route, $advanced = false)
{
if ($route === '') {
return '/' . Yii::$app->controller->getRoute();
$normalized = '/' . Yii::$app->controller->getRoute();
} elseif (strncmp($route, '/', 1) === 0) {
return $route;
$normalized = $route;
} elseif (strpos($route, '/') === false) {
return '/' . Yii::$app->controller->getUniqueId() . '/' . $route;
$normalized = '/' . Yii::$app->controller->getUniqueId() . '/' . $route;
} elseif (($mid = Yii::$app->controller->module->getUniqueId()) !== '') {
return '/' . $mid . '/' . $route;
$normalized = '/' . $mid . '/' . $route;
} else {
$normalized = '/' . $route;
}
// Prefix @app-id to route.
if ($advanced) {
$normalized = Route::PREFIX_ADVANCED . Yii::$app->id . $normalized;
}
return '/' . $route;
return $normalized;
}

/**
Expand Down Expand Up @@ -187,7 +200,7 @@ protected static function filterRecursive($items, $user)
}
$item['items'] = $subItems;
}
if ($allow) {
if ($allow && !($url == '#' && empty($item['items']))) {
$result[$i] = $item;
}
}
Expand Down
83 changes: 78 additions & 5 deletions models/Route.php
Expand Up @@ -20,6 +20,11 @@ class Route extends \yii\base\Object
{
const CACHE_TAG = 'mdm.admin.route';

const PREFIX_ADVANCED = '@';
const PREFIX_BASIC = '/';

private $_routePrefix;

/**
* Assign or remove items
* @param array $routes
Expand All @@ -31,7 +36,7 @@ public function addNew($routes)
foreach ($routes as $route) {
try {
$r = explode('&', $route);
$item = $manager->createPermission('/' . trim($route, '/'));
$item = $manager->createPermission($this->getPermissionName($route));
if (count($r) > 1) {
$action = '/' . trim($r[0], '/');
if (($itemAction = $manager->getPermission($action)) === null) {
Expand Down Expand Up @@ -67,7 +72,7 @@ public function remove($routes)
$manager = Configs::authManager();
foreach ($routes as $route) {
try {
$item = $manager->createPermission('/' . trim($route, '/'));
$item = $manager->createPermission($this->getPermissionName($route));
$manager->remove($item);
} catch (Exception $exc) {
Yii::error($exc->getMessage(), __METHOD__);
Expand All @@ -76,17 +81,85 @@ public function remove($routes)
Helper::invalidate();
}

/**
* Returns route prefix depending on the configuration.
* @return string Route prefix
*/
public function getRoutePrefix()
{
if (!$this->_routePrefix) {
$this->_routePrefix = Configs::instance()->advanced ? self::PREFIX_ADVANCED : self::PREFIX_BASIC;
}
return $this->_routePrefix;
}

/**
* Returns the correct permission name depending on the configuration.
* @param string $route Route
* @return string Permission name
*/
public function getPermissionName($route)
{
if (self::PREFIX_BASIC == $this->routePrefix) {
return self::PREFIX_BASIC . trim($route, self::PREFIX_BASIC);
} else {
return self::PREFIX_ADVANCED . ltrim(trim($route, self::PREFIX_BASIC), self::PREFIX_ADVANCED);
}
}

/**
* Get available and assigned routes
* @return array
*/
public function getRoutes()
{
$manager = Configs::authManager();
$routes = $this->getAppRoutes();
// Get advanced configuration
$advanced = Configs::instance()->advanced;
if ($advanced) {
// Use advanced route scheme.
// Set advanced route prefix.
$this->_routePrefix = self::PREFIX_ADVANCED;
// Create empty routes array.
$routes = [];
// Save original app.
$yiiApp = Yii::$app;
// Step through each configured application
foreach ($advanced as $id => $configPaths) {
// Force correct id string.
$id = $this->routePrefix . ltrim(trim($id), $this->routePrefix);
// Create empty config array.
$config = [];
// Assemble configuration for current app.
foreach ($configPaths as $configPath) {
// Merge every new configuration with the old config array.
$config = yii\helpers\ArrayHelper::merge($config, require (Yii::getAlias($configPath)));
}
// Create new app using the config array.
unset($config['bootstrap']);
$app = new yii\web\Application($config);
// Get all the routes of the newly created app.
$r = $this->getAppRoutes($app);
// Dump new app
unset($app);
// Prepend the app id to all routes.
foreach ($r as $route) {
$routes[$id . $route] = $id . $route;
}
}
// Switch back to original app.
Yii::$app = $yiiApp;
unset($yiiApp);
} else {
// Use basic route scheme.
// Set basic route prefix
$this->_routePrefix = self::PREFIX_BASIC;
// Get basic app routes.
$routes = $this->getAppRoutes();
}
$exists = [];
foreach (array_keys($manager->getPermissions()) as $name) {
if ($name[0] !== '/') {
if ($name[0] !== $this->routePrefix) {
continue;
}
$exists[] = $name;
Expand All @@ -109,7 +182,7 @@ public function getAppRoutes($module = null)
} elseif (is_string($module)) {
$module = Yii::$app->getModule($module);
}
$key = [__METHOD__, $module->getUniqueId()];
$key = [__METHOD__, Yii::$app->id, $module->getUniqueId()];
$cache = Configs::instance()->cache;
if ($cache === null || ($result = $cache->get($key)) === false) {
$result = [];
Expand Down

0 comments on commit 48298cb

Please sign in to comment.