Hi.
Is there a canonical way of encapsulating the urlManager rules within a module itself?
In my case, I have a medium sized application split into six modules with roughly 110 url rules split between them. All modules are not active in all configurations so it seems appropriate to encapsulate a particular module’s URL rules within the module itself.
I’ve tried a few things but since a module’s init() and preinit() normally happen after the request (and the assignment of get/post variables), I can’t reliably use them. So far, the “best” solution I’ve come up with has been to extend CWebModule, implement a static getUrlRules() interface method and call that method inside the application’s onBeginRequest(). See below:
GetUrlRules.php
interface GetUrlRules
{
/**
* Method to return urlManager-parseable url rules
* @return array An array of urlRules for this object
*/
public static function getUrlRules();
}
MyWebModule.php
abstract class MyWebModule extends CWebModule implements GetUrlRules
{
}
main.php
...
'onBeginRequest => array('ModuleManager', 'getUrlRules'),
...
ModuleManager.php
class ModuleManager
{
/**
* Method to add the url rules of each module to the main application rules (intended for
* onBeginRequest)
* @return boolean Returns true if successful
*/
public static function getUrlRules()
{
$method = 'getUrlRules';
$app = Yii::app();
$urlManager = $app->getUrlManager();
foreach ($app->getModules() as $moduleName => $config) {
if (is_callable($moduleName . '::' . $method)) {
$urlManager->addRules($moduleName::$method());
}
}
return TRUE;
}
}
class MyModule extends MyWebModule
{
public static function getUrlRules()
{
return array(
'<module>/users/edit/<id:\d+>' => '<module>/users/edit',
'<module>/users/disable/<id:\d+>' => '<module>/users/disable',
'<module>/users/add' => '<module>/user/add',
);
}
}
While all of this works, it just feels very hack-ish and I’m hoping someone might have an idea of a simpler more elegant way to achieve the same effect. This was based on something I saw months ago (but couldn’t find again today) that used a non-static module method to achieve the same effect. In that instance, the user executed a Yii:app()->getModule($moduleName) inside the ModuleManager and called the getUrlRules method. This looked something like the following:
ModuleManager.php
...
foreach ($app->getModules() as $moduleName => $config) {
$module = Yii::app()->getModule($moduleName);
$urlManager->addRules($module->getUrlRules())
...
Since the getModule() call initializes each module the getUrlRules method is unnecessary; at that point everything for adding url’s could be put inside each module’s init(). In some ways, the adapted approach (using CWebModule::init()), is ideal because we don’t have to check if the getUrlRules method exists. The downside to this approach is that it blows the lazy-intention of the autoloader to pieces by forcing every module to load/instantiate onBeforeRequest.
Are there any ideas out there on the ‘right’ way to approach this issue?