Passed, named or query string params?

This is a question often asked. It’s also a question I had to find my own answers to – and to redefine those answers over time.

So here are my five cents regarding this topic:

Persistence: Passed params

You use passed params where there is a definite order in your URL regarding those params. So the second one never goes without the first one etc.
One example is a blog with date posts and you could just use the year or year/month or even year/month/day to select posts:

Issues

The encoding of named params can break urls. And, basically, they always violate the HTTP spec.
They are cake specific (no other application uses volatile params this way) and no real standard.

Imagine what happens when you pass named params (via search/userinput) that contain special chars like /, &, … That will break the URL.
You would need to manually encode and decode them all the time. Quite the pain. Using mod_rewrite you will also have to adjust the amount of
encoding/decoding to the amount of htaccess files invoked in apache (as that also triggers the encoding/decoding). That is a known issue with URLs and apache. For me it was a nightmare do work with it properly without the URL being easily breakable.

With that single line you are passing the query string params straight into the form as default values, populating the inputs on GET.
For each POST it will then ignore those, of course.

You could argue that the same was possible with named params. Well, kind of. They were not capable of using chars that needed to be urlescaped.
With query strings you don’t have to even think about it. It all works out of the box with anything you pass along.

Hands on

So how can we get our (new?) 2.x application future-proof and a little bit more 3.x ready?

I use this in my controllers to overwrite "named" as default paramType for the Paginator´:

// in beforeFilter()
$this->paginate['paramType'] = 'querystring';

Note: This works if you do not overwrite the whole paginate array in your methods, but use the same key/value assignments.
Alternatively, this is what I do:

I think that should already cover 99% of all cases.
Beware of special route setups, though, that might need some custom handling.

Tip: Using my Tools plugin CommonComponent you can get a warning if you forgot to remove/upgrade any named params to query strings when enabling Configure key 'App.warnAboutNamedParams'. Set it to true and get error log entries regarding those issues. Helped me to find remaining named params.

And once you don’t need BC anymore, you can simply drop the named param stuff:

$limit = $this->request->query('limit');

Mission accomplished.

Last words

As mentioned above my opinion regarding named params changed over time. I was working with them for years from 1.2 up to 2.2.
But at some point I saw the disadvantages outweigh the advantages. In 2.x there have been also many improvements regarding query strings so that since 2.3 I always use and recommend query strings for new applications. And for legacy ones I recommend upgrading – if possible.

And for 3.x there will be no named params anymore, anyway. So the sooner we start applying the query strings to apps and plugins, the better.

Also, using the extension routing as mentioned above you don’t really have any other choice, anyway.
Passed params like this are not even valid AFAIK:

/some/controller/action.json/bar/y

This is also pretty ugly:

/some/controller/action.json/foo:bar/x:y

The only clean approach here are the query strings appended:

/some/controller/action.json?foo=bar&x=y

Which can easily be read from the controller using CakeRequest::query():

Insight

The 3.x docs state the following:

Named parameters required special handling both in CakePHP as well as any PHP or javascript library that needed to interact with them, as named parameters are not implemented or understood by any library except CakePHP. The additional complexity and code required to support named parameters did not justify their existence, and they have been removed. In their place you should use standard query string parameters or passed arguments

Read more about the usage of the param types above in the documentation.

I don’t like query params because they make the url look messy. I think this article needs a follow up or amend explaining about creating SEO friendly urls using query strings using rewrite rules.

Mark

May 1, 2014 at 11:53

I disagree. It can’t look any more messy than with named params. Especially if you are an outsider, seeing them for the first time.
You might let you cloud your judgement by what you are used so far in Cake – but giving the in-validness of named params they are not comparable.
So it doesn’t matter actually if they are nice or whatever. Just don’t use em as if they never existed.

Using query strings usually doesn’t involve SEO – so it doesn’t necessarily need a follow up. When SEO is relevant you would usually use passed params – or internally make them behave like passed ones via routing.
Query strings are – as explained above – the way to quickly filter results – and as such don’t need any special love IMO.
Especially in the backend and such. For revelant frontend parts you can probably use some routing approach to map them to a more passed param style.

Hello Mark, nice article. I have an issue: I have a paginated list, and I am currently using querystrings.
I have two pages: I delete some items and my pages become single: I have a page not found error in redirection because the redirect still has page2 as url querystring parameter? How to avoid this ?

Thanks in advance

Rudy

Mark

November 15, 2014 at 16:48

That is a good point.
I guess after deleting it would be wise to either jump to first page or to check if there are still enough records to stay on that current page.

But shouldnt current versions of Cake2 do that automatically? What are you running?

It does that for security reasons if you use Html->url(). Use Router::url() if you don’t want h() to run over it. But then the URL should never be printed in the view.
So in short: having it escaped is totally valid and even a requirement for valid and secure HTML output. So it depends on your use case and especially where you are using that url.

Thanks Mark, beautifully explained as always – I have a bit more of an insight into what’s going on with the Html helper now. I’m using the url in jquery ajax calls – I realise I could create the whole thing using the js helper but I find it easier to debug when writing the js directly. Thanks again.

Hello
I am using CakeDC Search plugin , using last version so querystring as paramType option default: when I do search something , the result is parsed into a normal querystring, but once I tried to acess pagination links it return creating named parameters instead again!! And the pagination breaks up! Any idea about that ? Thanks

Rudy

Mark

January 2, 2015 at 16:48

I found out the same thing just a few days back.
It might be very well a CakePHP core bug or rather search plugin bug, as it only happens when you supply a custom URL to PaginatorHelper params/options, right?
Or what is your specific Paginator setup?

For me, taking those URLs out of it made it function normally again.

I assume we need to unset() the named params, that are re-formed to passed ones somewhere in the PrgComponent.

Hi Mark
I have checked about the problems of pagination: it seems that core paginator helper has a problem in _convertUrlKeys function: it does not create the querystring in "$url[‘?’]" with the parameters passed by $this-&gt;request-&gt;query.
I have modified the core just to test and adding those values and finally pagination works again.
But I was unable to remove named parameters from the url.
This is how the _convertUrlKeys function look like after my small mod ( I think there would be a better and cleaner way to achieve this result but I am in hurry and I needed a solution )