CakeDC/users

Cake\Routing\Exception\MissingRouteException for url's generated by Url helper in layout

C8Robin opened this issue · 5 comments

Navigation in my layout builds urls using the Url builder.
#958 and #935 seem similar, but not exactly, although #935 mentions also view building links seems to cause the issue.

When attempting to render a page as a non logged-in user, I get a MissingRouteException for those urls that the layout is asking the Url helper to build.

I noticed that the routes being requested include 'plugin'=> 'CakeDC/Users' ; I assume this is the case because the user is not yet logged in. See example below, no route requested with plugin reference.

Would expect a Url->build(...) request to work in a layout, as I am not asking to execute that request yet, just build the link. Tried the AuthLink helper, but the result is the same.

Reproduce

  • by baking a default CakePHP 4 application,
  • and use CakeDC/Users plugin: load plugin, execute migrations and create a superadmin, use default permissions file, didn't use my own auth config file (NO users.php file in config/). So am using plugin as much out of the box as possible.
  • Keep the default cakephp layout (default.php), just add a statement somewhere to build a url.
  • Note: have a DB with one table (books) and baked everything for 'books'

CakeDC/Users: 11.0.0
CakePHP: 4.3.5

Layout extract

<main class="main">
    <div class="container">
        <?= $this->Url->build(['controller' => 'Books']);?>
        <?= $this->Flash->render() ?>
        <?= $this->fetch('content') ?>
    </div>
</main>

Application.php

public function bootstrap(): void
    {
        // Call parent to load bootstrap from files.
        parent::bootstrap();

        if (PHP_SAPI === 'cli') {
            $this->bootstrapCli();
        } else {
            FactoryLocator::add(
                'Table',
                (new TableLocator())->allowFallbackClass(false)
            );
        }

        /*
         * Only try to load DebugKit in development mode
         * Debug Kit should not be installed on a production system
         */
        if (Configure::read('debug')) {
            $this->addPlugin('DebugKit');
        }

        // Load more plugins here
        $this->addPlugin('CakeDC/Users');
    }

After some more testing, I noticed that providing a url as a string, does not lead to this problem.
This exception only manifests when requesting Url to build a url.

e.g.
<?= $this->Html->link('Books', ['controller' => 'Books'])?>
will raise that exception, when user is not logged in
while
<?= $this->Html->link('Books','/books/')?>
will not.

I notice that HTML helper requests Url helper to build a url, without altering the url that was given:

if ($url !== null) {
    $url = $this->Url->build($url, $options);
    unset($options['fullBase']);
} else {
...
}

Inspecting Url helper's argument 'url' in Url::build, I notice that these are the values of that url (checked via DebugKit, in my browser):

[
    'controller' => 'Books',
    'plugin' => 'CakeDC/Users',
    'action' => 'index',
    '_ext' => null,
]

I don't know how or why 'plugin' => 'CakeDC/Users' got in there, maybe some middleware is inserting this?

In the list of available routes (DebugKit again), I see that this route exists:

/{controller}
=>

[
  'plugin' => null,
  'action' => 'index',
]

Workaround for now is probably to use strings as urls in my layout (i.e. the site navigation), but that might break in the future I guess.

Am still puzzled...

Maybe a better workaround for now, is to generate my site nav urls like this:

<?= $this->Html->link('Books', ['plugin' => false, 'controller' => 'Books'])?>

This link works, and when not logged in I am redirected to the login page.

Doesn't solve the root cause, and if I would have to do this throughout my application, it would not be very elegant.

I am getting the same error on a site using CakeDC/users plugin. The site worked fine on Saturday. I first became aware of the issue on Sunday.

Prior to this, attempting to access a valid url when not authenticated would redirect to a login page.

Confirmed C8Robin's workaround using HTML helper and including 'plugin' => false works for my situation also. The issue appeared recently for me due to adding HTML helper code on the home.php page.

That's how HtmlHelper and UrlHelper works. They will create url based on current request, if you are accessing a plugin or prefix url they will use the current plugin|prefix.
To use a non plugin|prefix url you must do what you did <?= $this->Html->link('Books', ['plugin' => false, 'controller' => 'Books'])?> or <?= $this->Html->link('Books', ['plugin' => false, 'prefix' => false, 'controller' => 'Books'])?>