Dynamic routes?


#1

cakephp 3.x

Is there a way to create dynamic routes per article ?
(like in some well known CMS)


#2

This is what I use for it:

$routes->connect('/blog/*',['plugin'=>'Kikioboeru/Blog','controller' => 'Blog', 'action' => 'view']);

context:

Router::scope('/', function (RouteBuilder $routes) {
  $routes->connect('/blog/*',['plugin'=>'Kikioboeru/Blog','controller' => 'Blog', 'action' => 'view']);
});

It routes /blog/some-blog-post to the Blog controller in Kikioboeru/Blog plugin with the view action.

Refer to the documentation for more info:
https://book.cakephp.org/3.0/en/development/routing.html


#3

Thank you for answering.

I should have been more precise. Sorry.

I’ve been using cakephp since 1.2 so I know how to use the router in the routing section.

What I am looking for is a way to write routes in a controller method.
So that www.domain.com/articles/id reads www.domain.com/what_I_want in the address bar.


#5

Basically, CakePHP needs to know which controller, action and param to use to process request and send a response. It is the router job.

There is many ways to achieve permalinks all you have to do is :

  • Keep a map between slugs and records in database
  • Set up a scheme to disambiguate permalinks calls from others requests
  • Use a custom route to get slug param because id param must be integer or UUID.

If the controller is always implicit (ArticlesController in your example) and the action is also always implicit (view in your example), you can simply set a custom route like this:

$routes
  ->connect('/:slug', ['controller' => 'Articles', 'action' => 'view'])
  ->setPass(['slug']);

The slug param will be available in the view actions as parameter (like id). Then, you only need to fetch the article that matches the slug and pass it to the view.

Of course, it means that it may conflics with others controllers default actions (/users will look for a slug called users and not the index action of the users controller as it should do if using DashedRoute::class as fallback).

To avoid this, the the cookbook example keeps the articles controller in route :

$routes
   ->connect('/articles/:slug', ['controller' => 'Articles', 'action' => 'view'])
   ->setPass(['slug']);

It will give you better control on other application calls though allowing you to use SEO friendly urls. You can also use subdomains or routing prefix to serve requests to other controllers and keep root level only for articles.

The used scheme is up to you given your app architecture.

This is the “pure” CakePHP response. The famous “CMS”, if I guess well, is relying on mod_rewrite to pass slug as query param to process request.


#6

Thank you for your answer.
Question : if I pass a slug as parameter like in :
www.domain.com/articles/slug_string
what difference does it make compared to passing the id ?
I guess it should be slower as ids are primary indexes in the database.
But does it make a real difference ?


#7

Except the database query maybe it doesn’t do anything different for the route itself.
:id just tells Cake: pass as variable 'id'.
You can then (for example) limit it by saying (or rather, code it in) to the app: only accept integers or only accept [a-zA-Z].

So yea, except for the database it shouldn’t do anything in terms of performance