"partially" named routes

Hii there,

I’m trying to cleanup my app a bit and I wanted to start using named routes.
For this, I have written the current route in my routes.php:

Router::scope('/api',['_namePrefix' => 'api:'], function($routes) {
  // V1 API
  $routes->scope('/v1', ['_namePrefix' => 'v1:'], function($routes) {
    // Projects
    $routes->scope('/projects',function($routes) {
      $routes->get('/edit-release', ['controller' => 'ProjectsRest', 'action' => 'getProjects']);
      $routes->get('/edit-release/:release', ['controller' => 'ProjectsRest', 'action' => 'getProjects'])
        ->setPass(['release']);
    ]);
  ]);
]);

Now I wanted to have the route in my view (for the ajax on the page) be something like this:

$this->Url->build(['_name' => 'api:v1:edit-release']);

However, this obviously doesn’t work since the route itself isn’t also named like this:

$routes->get('/edit-release', ['controller' => 'ProjectsRest', 'action' => 'getProjects'], 'edit-release');

Now before you ask: why I have the route in there twice, this is because the route builder refuses to give the appropriate route if I wanted to call it without a release (as the :release variable is defined in the JavaScript on the page).

So now my question is: how can I make these “partial” named routes work?
All I really care about is the api:v1 part.

My question is…

Why do you want to complicate the code, isn’t life complicated enough?

Should hit you hard :smiley:

Regarding your question, I am not sure if hierarchical routes is possible.
But you can definately break it down into plugins and then do your thing.
Sounds easy?

But then what is your suggested way of doingsomething like this? :stuck_out_tongue:

Haha

I would suggest breaking the app down into plugins. As opposed to Zend Framework. CakePHP has a Hierarchical system but the workaround is via plugins…
Just enable bootstrap and routes in your plugin and it will be able to accomplish the nested routes!

Well, nesting the routes works perfectly fine, it’s just that naming like this doesn’t work like I hoped.

Also reverse calling wont work either.

Just to accomplish that, I would suggest breaking it down into plugins… that is… if your client has enough budget and you, enough time.

you can create one route with pattern that accepts empty string

$routes->get('/edit-release/:release', ['controller' => 'ProjectsRest', 'action' => 'getProjects'], 'edit-release')
                ->setPass(['release'])
                ->setPatterns(['release' => '[a-z]{0,3}']);

gotcha is you need to suply release param even when its empty

<?= $this->Html->link('test1', ['_name' => 'api:v1:edit-release', 'release' => '']) ?>
<?= $this->Html->link('test2', ['_name' => 'api:v1:edit-release', 'release' => 'a']) ?>

Well… considering it’s my own website, I think I have plenty of budget for it XD

Hmm… I was afraid I had to do this yes… I’ll open an issue on the CakePHP repo to see if maybe they could add something that prevents these cases (because I doubt that I’m the only one that ever has ran into this).
Thanks anyways, I’ll have a closer look into it.

if you dont need any pattern checking you might also use greedy one

$routes->get('/edit-release/*', ['controller' => 'ProjectsRest', 'action' => 'getProjects'], 'edit-release');
<?= $this->Html->link('test1', ['_name' => 'api:v1:edit-release']) ?>
<?= $this->Html->link('test2', ['_name' => 'api:v1:edit-release', 'aa']) ?>

and in controller

$this->request->getParam('pass.0');

my function looks like this:

public function editRelease($release = null) {
}

But I suppose that with the greedy route, this won’t work?

little sidenote: the action I want to use is actually called editRelease (I just spotted this issue in my code when testing some stuff lol)

i think it should work IIRC you just lose ability to use ->setPattern this could be annoying if you tried to pass 2 params in one url segment ie /:id-:slug but should still work if you give multiple arguments

public function editRelease($arg1 = null, $arg2 = null) {
}

https://book.cakephp.org/3.0/en/development/routing.html#routes-configuration

The trailing /* tells the router to pass any additional segments as method arguments. For example, /users/view/123 would map to UsersController->view(123)

Hmm… I see.
Well, considering the app requires specific params at specific places anyways that isn’t too much of an issue.
I’ll have a go at it when I’m home again :slight_smile:

Curious though… What are you making?

trying to clean-up some stuff (mainly my API) :slight_smile: