One of the most satisfying bits of code to write, are those simple solutions to simple (or overlooked) problems. The problem I’m going to write about today is Routing.
What’s wrong with routing?
However, that’s not to say it can’t be improved. To set the scene take a look at the 2.x docs for routing and you’ll find the following example:
1 2 3 4 5
No surprises there. So the above route would be used like so:
1 2 3 4 5 6
Unless your application is trivial, it’s quite likely to have your view files full of code like this, and there’s nothing wrong with that, as it’s the standard way to write a url that uses reverse routing (taking an array and returning a string).
However, it’s normally when you already have a chunk of code written that you get a curveball come your way such as:
We forgot about seo - we need to put some of that magic sauce in the url. All urls.
So now, your route (and relevant controller code if necessary) gets updated to e.g.:
1 2 3 4 5
And view code (and controller redirects) needs to change to match like so:
1 2 3 4
Rinse and repeat a few times and this gets pretty tedious. What if there was a better way?
A better way
Let’s jump straight into designing a solution and then make it work.
I’m going to make use of named routes as this both reduces verbosity and is a minor speed up - since it means telling the router explicitly which route to use, instead of asking it to itterate over all route definitions looking for a match.
This is the end result we’re going to achieve:
1 2 3 4 5 6 7 8 9
Note: Entity Routing IS NOT a CakePHP 3.x core feature - the above will not “just work”
Now let’s think about that for a second:
- The call contains the entity, it doesn’t explicitly say which bits of the entity are in the url
- Changing only the route definition will change the result
- It is unlikely to ever need to change
Can you feel the awesome?
Making it work
We only need 2 things for the above to work
1. An appropriate route definition
We’ll need a named route definition, and to specify to use a different route class:
1 2 3 4 5
2. The entity-route class
And, to create the route class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
All the above route does is use the route template (
/posts/:slug) to identify which properties
to read from the passed entity if it is present (slug), otherwise it will act exactly the same as a
With the above route definition and route class all of these would return the same string:
1 2 3
But only one of the above calls is imune to “significant” route changes.
Entity routing is a rather simple change.
One thing that it has encouraged me to do is to consider creating bespoke route classes more often, for example, have some sort of “make sure this parameter is always set” logic in your app controller before filter? Why not put that logic in the route definition and forget about it?
That’s all for now, let me know what you think =).