Dynamic namespace

I have this configuration in a multi-module application:

$router->add('[/]?{module:[a-zA-Z0-9_-]*}[/]?{controller:[a-zA-Z0-9_-]*}[/]?{action:[a-zA-Z0-9_-]*}[/]?{params:(/.*)*}', array(
    'module' => 1,
    'controller' => 2,
    'action' => 3,
    'params' => 4
));

$router->add('/', array(
    'module' => 'frontend',
    'controller' => 'index',
    'action' => 'index'
));

$router->notFound(array(
    'module' => 'frontend',
    'controller' => 'Error',
    'action' => 'route404'
));

Can also be made dynamic generation of namespaces? For example:

"namespace" => "Apps \ 1 \ Controllers"
"namespace" => "Apps \: module \ Controllers"

This is the exact question I have as well. It seems like a good feature to have unless there's another more accepted way to accomplish routing to all modules.

How is multi-module routing handled normally? Multiple similar routes for each module?



81.8k
edited Mar '14

You can also set the namespace using the placeholder of the same name:

{namespace:[a-zA-Z0-9\\]*}

However pass the backslash could make your routes look ugly. also, If you don't have a suffix for your controllers it could be a potential security problem.

I ended up extending the default router to choose the namespace based on the module.

use Phalcon\Mvc\Router as PhalconRouter;
use Phalcon\Mvc\RouterInterface;

class Router extends PhalconRouter implements RouterInterface {
    public function getNamespaceName ()
    {
        $module = $this->_module ? $this->_module : $this->_defaultModule;
        return "Site\\Apps\\" . $module . "\\Controllers";
    }
}

Using that instead of the default router seems to do exactly what the OP and I asked about.

edited May '15

I'm doing the same, but it fits only if your controllers namespaces match the getNamespaceName override. For example, I'm trying to add the snowair/debugbar and it uses it's own namespace declaration on routes, wich are overrided with my router :( I'm triying to find a solution that does not involves rewriting the namespace dinamically. (tried the registerServices on Module.php to override it but it does not work.

    public function registerServices(DiInterface $dependencyInjector = NULL)
    {
        $dependencyInjector['dispatcher']->setDefaultNamespace('App\User\Controllers');
        $dependencyInjector['router']->setDefaultNamespace('App\User\Controllers');
    }

I ended up extending the default router to choose the namespace based on the module. Using that instead of the default router seems to do exactly what the OP and I asked about.

edited May '15

It works! and it's easy!

in each one of your modules define the default namespace for controllers.

Do not define a default namespace for the $route on the global routes definition.

    /**
     * Registers the module-only services
     *
     * @param DiInterface $dependencyInjector
     */
    public function registerServices(DiInterface $dependencyInjector = NULL)
    {
        $namespace = 'App\User\Controllers';
         // I use this to set the backend controllers (inside an Admin folder)
        if($dependencyInjector['router']->getParams('admin')) $namespace.="\\Admin";
        $dependencyInjector['dispatcher']->setDefaultNamespace($namespace);
    }