Есть решение для Yii 1:
Сам код нашел в сети, частично допилил его, на предмет кеширования, и на предмет вложенных модулей.
Возможно можно допилить для Yii2
1. В конфиг
/* Правила роутинга для модулей */
'onBeginRequest' => array('ModuleUrlManager', 'collectRules'),
2. Файл ModuleUrlManager
/**
* Класс менеджер путей модулей
* Активирует urlRules параметр активного модуля
* Работает с многоуровневой вложеностью модулей
* Реализовано кеширование urlRules модулей
*/
class ModuleUrlManager {
static function collectRules() {
if (!empty(Yii::app()->modules)) {
$cache = Yii::app()->getCache();
$route = Yii::app()->getRequest()->getPathInfo();
$patharray = explode('/', $route);
$moduleName = substr($route, 0, strpos($route, '/'));
/* Если роут имеет вид module.html */
if (empty($moduleName)) {
$moduleName = substr($route, 0, strpos($route, '.'));
}
if (Yii::app()->hasModule($moduleName)) {
$urlRules = false;
if ($cache)
$urlRules = $cache->get('module.url.rules.' . $moduleName);
if ($urlRules === false) {
$module = Yii::app()->getModule($moduleName);
if (isset($module->urlRules)) {
$urlRules = $module->urlRules;
if ($cache && !empty($urlRules))
$cache->set('module.url.rules.' . $module->id, $urlRules);
}
}
if (!empty($urlRules))
Yii::app()->getUrlManager()->addRules($urlRules);
if (!empty($patharray)) {
foreach ($patharray as $pathUnit) {
$position = strpos($pathUnit, '.html');
if ($position) {
$pathUnit = substr($pathUnit, 0, $position);
}
$urlRules = false;
if ($cache)
$urlRules = $cache->get('module.url.rules.' . $moduleName . '/' . $pathUnit);
if ($urlRules === false) {
$module = Yii::app()->getModule($moduleName);
if ($module->hasModule($pathUnit)) {
$submodule = $module->getModule($pathUnit);
if (isset($submodule->urlRules)) {
$urlRules = $submodule->urlRules;
if ($cache && !empty($urlRules))
$cache->set('module.url.rules.' . $submodule->id, $urlRules);
}
}
}
if (!empty($urlRules))
Yii::app()->getUrlManager()->addRules($urlRules);
}
}
}
return true;
}
}
}