We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

On error, see if another route matches

I have a use case where I'd like to do the following: I have two modules:

  • apiv1
  • apiv2

Here's a couple example routes I'd have in my application:

  • /:module
  • /:controller

So if I visit /user I'd like the application to try and detect a not found when /:module matches and then automatically move to the next route match of /:controller and if neither of those routes redirect and no other routes match, then we error out.

So ideally, customers would automatically use the api version I specify if they access the url without specifing the module aka apiv1. Otherwise if they specify the module then we give them access to that.

Any suggestions?



2.1k

could you post some examples? i have no idea what you want specifically. It isnt quite clear at all.

but lets try answering all the same.

$di['router'] = function () {

    $router = new Router();
    $router->setDefaultModule('apiv2');
    $router->removeExtraSlashes(true);
    return $router;
};

by default if no module is specified it will always attempt to find the controller in apiv2.

localhost/controller/action // will go to localhost/apiv2/controller/action localhost/apiv1/controller/action // will go to apiv1

edited Jan '15

I think you've correctly understood what I'm trying to achieve. So the issue must be arrising then because I'm using custom routes so that I can do camelizing for the module and the action:

    $router->add('/:controller/([a-zA-Z\-]+)/:params', array(
            'module'        => 'apiV1',
            'controller'    => 1,
            'action'        => 2,
            'params'        => 3
        ))->convert('action', function ($action)  {
            if(!empty($action) && strpos($action, '-') !== False)
            {
                return lcfirst(Phalcon\Text::camelize($action));
            }
            else
            {
                return $action;
            }
        })->setName('C');

        $router->add('/:module/:controller[/]', array(
            'controller' => 2,
            'module' => 1,
        ))->convert('module', function ($module) {
            if(!empty($module) && strpos($module, '-') !== False)
            {
                return lcfirst(Phalcon\Text::camelize($module));
            }
            else
            {
                return $module;
            }
        })->setName('B');

        $router->add('/:module[/]', array(
            //'controller' => 'index',
            'module' => 1
        ))->convert('module', function ($module) {
            if(!empty($module) && strpos($module, '-') !== False)
            {
                return lcfirst(Phalcon\Text::camelize($module));
            }
            else
            {
                return $module;
            }
        })->setName('A');

        $router->add('/:module/:controller/([a-zA-Z\-]+)/:params', array(
            'module'        => 1,
            'controller'    => 2,
            'action'        => 3,
            'params'        => 4
        ))->convert('action', function ($action)  {
            if(!empty($action) && strpos($action, '-') !== False)
            {
                return lcfirst(Phalcon\Text::camelize($action));
            }
            else
            {
                return $action;
            }
        })->convert('module', function ($module) {
            if(!empty($module) && strpos($module, '-') !== False)
            {
                return lcfirst(Phalcon\Text::camelize($module));
            }
            else
            {
                return $module;
            }
        })->setName('D');


2.1k
//services
$di->set('dispatcher', function() {

    //Create an EventsManager
    $eventsManager = new EventsManager();

    //Camelize actions
    $eventsManager->attach("dispatch:beforeDispatchLoop", function($event, $dispatcher) {
        $dispatcher->setActionName(Text::camelize($dispatcher->getActionName()));
         $dispatcher->setControllerName(Text::camelize($dispatcher->getControllerName()));
          $dispatcher->setModuleName(Text::camelize($dispatcher->getModuleName()));
    });

    $dispatcher = new MvcDispatcher();
    $dispatcher->setEventsManager($eventsManager);

    return $dispatcher;
});
$di['router'] = function () {

    $router = new Router();
    $router->setDefaultModule('defaultModule');
    $router->removeExtraSlashes(true);
    return $router;
};

//bootstrap
foreach ($application->getModules() as $key => $module) {
    $router->add('/'.$key.'/:params', array(
            'module' => $key,
            'controller' => 'index',
            'action' => 'index',
            'params' => 1
    ))->setName($key);
    $router->add('/'.$key.'/:controller/:params', array(
            'module' => $key,
            'controller' => 1,
            'action' => 'index',
            'params' => 2
    ));
    $router->add('/'.$key.'/:controller/:action/:params', array(
            'module' => $key,
            'controller' => 1,
            'action' => 2,
            'params' => 3
    ));
}


717
Accepted
answer

Pretty close, I had to do this:

function default_routes (&$group)
{
    $group->add('/', array(
        'controller' => 'index',
        'action'    => 'index'
    ));

    $group->add('/:controller', array(
        'controller'    => 1,
        'aciton'        => 'index',

    ));

    $group->add('/:controller/:action', array(
        'controller'    => 1,
        'action'        => 2,
    ));

    $group->add('/:controller/:action/:params', array(
        'controller'    => 1,
        'action'        => 2,
        'params'        => 3
    ));
}

$group = new Phalcon\Mvc\Router\Group(array(
    'module' => $config->application->defaultModule,
    'controller' => 'index'
));
$group->setPrefix('/');
default_routes($group);
$router->mount($group);

foreach ($application->getModules() as $key => $module)
{
    $key_cool = str_replace('_', '-', Phalcon\Text::uncamelize($key));
    $group = new Phalcon\Mvc\Router\Group(array(
        'module' => $key,
        'controller' => 'index'
    ));
    $group->setPrefix('/' . $key_cool);
    default_routes($group);
    $router->mount($group);
}

Had to setup some default routes first then I could add the default routes for each module. That allowed me to run routes like /default-route/user/ and /user/ both resolving to the same module, controller and action.

Thanks for helping 7thcubic!