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

Having a hard time with the routing & url system

Hello,

What I'm trying to achieve is quite simple, but I'm not really able to make it work properly (because of overlapping or error from my logic). I'd like to have a generic routing system, pretty much this logic:

Basic default routing:

  /
  //...
  /:controller
  /:controller/:action
  /:controller/:action/:slug
  /:controller/:action/:int
  /:controller/:action/:slug/:params
  /:controller/:action/:int/:params

Adding modules:

  /:module
  /:module/:controller
  /:module/:controller/:action
  /:module/:controller/:action/:slug
  /:module/:controller/:action/:int
  /:module/:controller/:action/:slug/:params
  /:module/:controller/:action/:int/:params

Adding optionnal locale for basic & module routing:

  /:locale
  /:locale/:controller
  /:locale/:controller/:action
  /:locale/:controller/:action/:slug
  /:locale/:controller/:action/:int
  /:locale/:controller/:action/:slug/:params
  /:locale/:controller/:action/:int/:params

  /:locale/:module
  /:locale/:module/:controller
  /:locale/:module/:controller/:action
  /:locale/:module/:controller/:action/:slug
  /:locale/:module/:controller/:action/:int
  /:locale/:module/:controller/:action/:slug/:params
  /:locale/:module/:controller/:action/:int/:params

The weird part is that when I succeed to match all these generic routes, my "url" service wouldn't work properly and vice-versa. It's one or the other, basically because of my optionnal local field which would move the routing position.

{locale:([a-z]{2,3}([\_\-][[:alnum:]]{1,8})?)?}

For the collision between my default routing and the module name, I was able to fix it by using GroupeRoute and forcing the module name from the prefix.

   $this->setPrefix(($this->locale? '([\/]{0,1}){locale:([a-z]{2,3}([\_\-][[:alnum:]]{1,8})?)?}' : null) . ($this->default ? null : '/' . $module));

    // /backend
    $this->add( '/' . $params, [
        'params' => $prefixPos + 1
    ])->setName($module);

    // /backend/users
    $this->add('/:controller' . $params, [
        'controller' => $prefixPos + 1,
        'params' => $prefixPos + 2
    ])->setName($module . '-controller');

    // /backend/user/list
    $this->add('/:controller/:action' . $params, [
        'controller' => $prefixPos + 1,
        'action' => $prefixPos + 2,
        'params' => $prefixPos + 3
    ])->setName($module . '-controller-action');

    // /backend/user/profile/jturbide
    $this->add( '/:controller/:action/([a-zA-Z0-9\_\-]+)' . $params, [
        'controller' => $prefixPos + 1,
        'action' => $prefixPos + 2,
        'slug' => $prefixPos + 3,
        'params' => $prefixPos + 4
    ])->setName($module . '-controller-action-slug');

    // /backend/user/edit/1
    $this->add( '/:controller/:action/:int' . $params, [
        'controller' => $prefixPos + 1,
        'action' => $prefixPos + 2,
        'int' => $prefixPos + 3,
        'params' => $prefixPos + 4
    ])->setName($module . '-controller-action-int');

Any help would from fixing my logic or giving me hint or the proper way to do it would be appreciated. Thanks,

always defined from less especific to more especific in your case I think your problem is in setPrefix and what about of $params in all yours url definitions?

create a GroupRouter class something like this

class MyRoutes extends \Phalcon\Mvc\Router\Group {
    private $located = false;
    public function __construct(bool $located = false) {
        $this->located = $located;
        parent::__construct();
    }
    public function initialize() {
        if ($this->located === true) {
            $this->setPrefix('/{location:[a-z]{2}}');
        }
        // all yours routes
    }
}

$router = new Phalcon\Mvc\Router(false);
$router->mount(new MyRoutes());
$router->mount(new MyRoutes(true));

What do you think? try that and tell us. Good luck

My problem was about having a conditionnal parameter ("locale") from the prefix... I tried to add it into the patterns but I got the same problem. My only solution was to separate into two different route name.

Matching the route wasn't a problem, the problem was about generating the route. Because of the optionnal parameter it would try to reach the wrong index to generate the uri from the Url service.

edited Jun '18

Hi Julien, if I remember correctly, the only optional parameter is :params and can only be used at the end of the route definition. Docs

Good luck