What's the difference between passing a template name to the route and defining it manually in the controller?

I’m new to CakePHP but I’m enjoying it so far. However, I’m still getting used to the conventions used by it.

One of the things I don’t understand is that in the basic example that ships with CakePHP, we get a router passing the controller name, the action and also an additional parameter, which would be the template name/path to the template, however, inside that controler, we have a long code, like this:

public function display(...$path)
        if (!$path) {
            return $this->redirect('/');
        if (in_array('..', $path, true) || in_array('.', $path, true)) {
            throw new ForbiddenException();
        $page = $subpage = null;

        if (!empty($path[0])) {
            $page = $path[0];
        if (!empty($path[1])) {
            $subpage = $path[1];
        $this->set(compact('page', 'subpage'));

        try {
            $this->render(implode('/', $path));
        } catch (MissingTemplateException $exception) {
            if (Configure::read('debug')) {
                throw $exception;
            throw new NotFoundException();

I understand that it’s just an example that we actually could handle the path and throw customized errors, but I would like to know if there’s any way to pass the view as parameter and have them set automatically, or we could just do this:


Like let’s say my template is called page.ctp or page.php and I want to pass variables to this template from a controller, I would just do:

    $this->set('variable', "I'm a variable");

But what If I want to send this variable to my page template without using the render function? Is there any way to do it using just the route like in the example?

Like let’s say the page template is the index:

$routes->connect('/', ['controller' => 'ShowVariable', 'action' => 'displayVar', 'page']);

    function displayVar(){
       $this->set('variable', "I'm a variable");

and I display it in my page template like this:


Would I still have to use $this->render('page');? If so, is this additional parameter in the route any useful?

Another question I would like to ask is, since we can access controllers via URL, routes become less important, right?

You only ever need to call render if you want to use a template with a different name than the action function.

Routes are critical, but for a lot of applications it’s enough to just use the default standard routing. Custom routes are there for when you want to make your URLs more SEO or user-friendly.

1 Like

On this topic then, when running composer create-project on CakePHP 4.0 there is a difference to now when running it with version 4.2.1.

In the automatically generated code, in src/Controller/PagesController.php the latest bake now adds the line: -
return $this->render();
as the last line of
public function display(string ...$path): ?Response
whereas before it did nopt.

I removed that new line to see if it makes a difference with the latest build of my app, and I didn’t see any change in my app’s behaviour.

So is this render() in pages display() now required? Can someone please explain why or why not?

Thanks guys :slight_smile:

1 Like

Thank you for your clarification. I actually would like to take advantage of your answer and ask another simple question, if you allow me to, regarding the same question.

Let’s say I have I have a controller and a table called Users and I get data from this users table using CakePHP ORM. If I have a signin function, it would be example.com/users/signin but what if I want just example.com/signin? I have tried this but it breaks the ORM functionality as the controller name is different from the table’s name.

Is there any way to set the URL like that using routes? I tried reading the documentation but I couldn’t understand.

Yes, that’s exactly what routes are for. Something like:

$routes->connect('/signin', ['controller' => 'Users', 'action' => 'signin']);
1 Like

I can’t comment on that, as I’m still stuck in 3.x for a little while yet. Moving towards 4.x, but not there yet…