Pass values in routes

I seem to be misunderstanding something.

My understanding is that a params array:

$this->request->getAttribute('params');

can be used to generate urls, for example:

//in a template
$this->Html->link('Destination', $params);

//or in a general sense
Router::url($params);

I’m having a specific failure though. The pass values are not in the resulting url string.

Details about the structure

The params array carries the pass values on the pass node. If I move these values into the first level of the params array I an get the url string result I expect.

//doesn't work
$params = [
  'controller' => 'Articles',
  'action' => 'index',
  'pass' => [
     0 => 44,
     1 => 'A'
  ]
];
Router::url($params);
//produces
//  articles/index

//does work
$params = [
  'controller' => 'Articles',
  'action' => 'index',
  0 => 44,
  1 => 'A'
];
Router::url($params);
//produces
//  articles/index/44/A

Routes?

I fiddled with writing a route to correct this… I’m not clear on the concepts in the Router and can’t give you specifics because I literally spent 2 hours trying every variation I could think of.

Conclusion

What am I not getting? Are params arrays not supposed to work like this?

You don’t have to use pass when building route arrays. You define pass when creating routes for custom urls

If you do not create pass (or there are more parameters than defined) it simply adds like a subfolder

1 Like

Here’s what I’m doing:

  • I want three links to filter page content to active, inactive, or all
  • The links may appear on any number of pages with urls of unknown configuration
  • The links must maintain all the url features, just modifying the active query argument so the same page will re-render with the filter applied
$url = $this->getRequest()->getAttribute('params');

/* prepare url for Inactive */
$url = Hash::insert($url, '?.active', 0);
echo $this->Html->link(
    __('Inactive'),
    $url,
    ['class' => 'button button-outline float-right']);

That code fails to include any existing pass params in the url. And in the case of index will not include the action (the detail that made me think it might be a routes problem).

$url = $this->getRequest()->getAttribute('params');
//change the array to move any pass params up one level
$pass = $url['pass'];
$url = $url + $pass;

/* prepare url for Inactive */
$url = Hash::insert($url, '?.active', 0);
echo $this->Html->link(
    __('Inactive'),
    $url,
    ['class' => 'button button-outline float-right']);

I’m not trying to build the ‘pass’. It already exists as part of the params and I have to un-build it to get the result I want. This is the core of my question. It feels like the params array should both produce and be produced by the url with no modifications necessary.

You want to set up query params, not route params.

Try this code:

$query = Hash::insert($this->getRequest()->getQueryParams(), 'active', true);
echo $this->Html->link('active', ['?' => $query]);
echo $this->Html->link('active', [
    'controller' => 'Items',
    'action' => 'index',
    '?' => $query,
]); 

both should be the same link (assuming you are on ItemsController::index), while the second one is best to use when its on a navbar or global layout.

In the case where the current page/request url is

domain.com/tenants/index/33?foo=bar

the code you propose (in both versions) preserves the query args but looses the pass param 33.

// on a page reached by
// domain.com/tenants/index/33?foo=bar
// the code 
echo $this->Html->link('active', ['?' => $query]);
// yields
// domain.com/tenants?foo=bar&active=1

// and the code 
echo $this->Html->link('active', [
    'controller' => 'tenants',
    'action' => 'index',
    '?' => $query,
]);
// yields
// domain.com/tenants?foo=bar&active=1

Both produce identical output as you say, but not the output I need.

True, you could use $request->here with http_build_query() but it looks too manual/hacky

Maybe it is worth to open an issue for this (to add a handy helper function to request, or to Router to read pass in array)

Turns out there is already a tool in place.

Router::reverse() will take in the normal params array and produce the desired result.

That’s the kind of simple answer I was hoping for!

2 Likes

Did’nt know about that. Its not on the docs. Maybe a hint would be helpful :stuck_out_tongue:

Good for you for finding out!

Great that you got what you are looking for.

Please create a PR in https://github.com/cakephp/docs so everybody can have a idea about it.

Will do. Just trying to get a grip on what is there so I can find an appropriate way to add it… couple of days probably.

1 Like

Anyone with an interest in the details of this docs addition:

A pull request is up for draft one of the change

And here is the end of the story:

https://book.cakephp.org/4/en/development/routing.html#generating-urls

4 Likes