craftcms / cms

Build bespoke content experiences with Craft.
https://craftcms.com
Other
3.29k stars 639 forks source link

UrlRule::pattern must be set error on front-end after upgrading from Craft 2 #10251

Closed romainpoirier closed 2 years ago

romainpoirier commented 2 years ago

Description

I have followed the steps described in the documentation. Everything gone smooth, and seems to works as expected in the CP. However, I can't access any page on front-end, because of this error:


yii\base\InvalidConfigException: UrlRule::pattern must be set. in /craft/vendor/yiisoft/yii2/web/UrlRule.php:192
Stack trace:
#0 /craft/vendor/yiisoft/yii2/base/BaseObject.php(109): yii\web\UrlRule->init()
#1 /craft/vendor/craftcms/cms/src/web/UrlRule.php(71): yii\base\BaseObject->__construct(Array)
#2 [internal function]: craft\web\UrlRule->__construct(Array)
#3 /craft/vendor/yiisoft/yii2/di/Container.php(420): ReflectionClass->newInstanceArgs(Array)
#4 /craft/vendor/yiisoft/yii2/di/Container.php(171): yii\di\Container->build('craft\\web\\UrlRu...', Array, Array)
#5 /craft/vendor/yiisoft/yii2/BaseYii.php(365): yii\di\Container->get('craft\\web\\UrlRu...', Array, Array)
#6 /craft/vendor/yiisoft/yii2/web/UrlManager.php(246): yii\BaseYii::createObject(Array)
#7 /craft/vendor/craftcms/cms/src/web/UrlManager.php(294): yii\web\UrlManager->buildRules(Array)
#8 /craft/vendor/yiisoft/yii2/web/UrlManager.php(190): craft\web\UrlManager->buildRules(Array)
#9 /craft/vendor/yiisoft/yii2/base/BaseObject.php(109): yii\web\UrlManager->init()
#10 /craft/vendor/craftcms/cms/src/web/UrlManager.php(100): yii\base\BaseObject->__construct(Array)
#11 [internal function]: craft\web\UrlManager->__construct(Array)
#12 /craft/vendor/yiisoft/yii2/di/Container.php(420): ReflectionClass->newInstanceArgs(Array)
#13 /craft/vendor/yiisoft/yii2/di/Container.php(171): yii\di\Container->build('craft\\web\\UrlMa...', Array, Array)
#14 /craft/vendor/yiisoft/yii2/BaseYii.php(365): yii\di\Container->get('craft\\web\\UrlMa...', Array, Array)
#15 /craft/vendor/yiisoft/yii2/di/ServiceLocator.php(137): yii\BaseYii::createObject(Array)
#16 /craft/vendor/yiisoft/yii2/base/Module.php(748): yii\di\ServiceLocator->get('urlManager', true)
#17 /craft/vendor/craftcms/cms/src/web/Application.php(337): yii\base\Module->get('urlManager', true)
#18 /craft/vendor/yiisoft/yii2/base/Application.php(577): craft\web\Application->get('urlManager')
#19 /craft/vendor/craftcms/cms/src/web/Request.php(1325): yii\base\Application->getUrlManager()
#20 /craft/vendor/yiisoft/yii2/web/Application.php(83): craft\web\Request->resolve()
#21 /craft/vendor/craftcms/cms/src/web/Application.php(272): yii\web\Application->handleRequest(Object(craft\web\Request))
#22 /craft/vendor/yiisoft/yii2/base/Application.php(392): craft\web\Application->handleRequest(Object(craft\web\Request))
#23 /craft/htdocs/index.php(26): yii\base\Application->run()
#24 {main}
Copy StacktraceSearch StackoverflowSearch GoogleException
Invalid Configuration – yii\base\InvalidConfigException
UrlRule::pattern must be set.
1. in /craft/vendor/yiisoft/yii2/web/UrlRule.phpat line 192
2. in /craft/vendor/yiisoft/yii2/base/BaseObject.php at line 109– yii\web\UrlRule::init()
3. in /craft/vendor/craftcms/cms/src/web/UrlRule.php at line 71– yii\base\BaseObject::__construct(['route' => 'templates/render', 'params' => ['template' => '404']])
65666768697071727374757677                ];
            }

            $config['pattern'] = strtr($config['pattern'], self::$_regexTokens);
        }

        parent::__construct($config);
    }

    /**
     * @inheritdoc
     */
    public function parseRequest($manager, $request)
4. craft\web\UrlRule::__construct(['route' => 'templates/render', 'params' => ['template' => '404']])
5. in /craft/vendor/yiisoft/yii2/di/Container.php at line 420– ReflectionClass::newInstanceArgs([['template' => '404']])
6. in /craft/vendor/yiisoft/yii2/di/Container.php at line 171– yii\di\Container::build('craft\web\UrlRule', [], ['template' => '404'])
7. in /craft/vendor/yiisoft/yii2/BaseYii.php at line 365– yii\di\Container::get('craft\web\UrlRule', [], ['template' => '404'])
8. in /craft/vendor/yiisoft/yii2/web/UrlManager.php at line 246– yii\BaseYii::createObject(['template' => '404'])
9. in /craft/vendor/craftcms/cms/src/web/UrlManager.php at line 294– yii\web\UrlManager::buildRules(['/?404/?(.*)' => '404', '/?(?P<slug>.+)/?(.*)' => '_routing', '/?(.*)/(?P<slug>.+)/?(.*)' => '_routing', 0 => ['template' => '404'], ...])
288289290291292293294295296297298299300                array_splice($rules, $i, 1, [$rule]);
            }

            $i++;
        }

        return parent::buildRules($rules);
    }

    /**
     * Returns the rules that should be used for the current request.
     *
     * @return array|null The rules, or null if it's a console request
10. in /craft/vendor/yiisoft/yii2/web/UrlManager.php at line 190– craft\web\UrlManager::buildRules(['/?404/?(.*)' => '404', '/?(?P<slug>.+)/?(.*)' => '_routing', '/?(.*)/(?P<slug>.+)/?(.*)' => '_routing', 0 => ['template' => '404'], ...])
11. in /craft/vendor/yiisoft/yii2/base/BaseObject.php at line 109– yii\web\UrlManager::init()
12. in /craft/vendor/craftcms/cms/src/web/UrlManager.php at line 100– yii\base\BaseObject::__construct(['enablePrettyUrl' => true, 'ruleConfig' => ['class' => 'craft\web\UrlRule'], 'showScriptName' => false, 'rules' => ['/?404/?(.*)' => '404', '/?(?P<slug>.+)/?(.*)' => '_routing', '/?(.*)/(?P<slug>.+)/?(.*)' => '_routing', 0 => ['template' => '404'], ...]])
949596979899100101102103104105106     */
    public function __construct(array $config = [])
    {
        $config['showScriptName'] = !Craft::$app->getConfig()->getGeneral()->omitScriptNameInUrls;
        $config['rules'] = $this->_getRules();

        parent::__construct($config);
    }

    /**
     * @inheritdoc
     */
    public function parseRequest($request)
13. craft\web\UrlManager::__construct(['enablePrettyUrl' => true, 'ruleConfig' => ['class' => 'craft\web\UrlRule'], 'showScriptName' => false, 'rules' => ['/?404/?(.*)' => '404', '/?(?P<slug>.+)/?(.*)' => '_routing', '/?(.*)/(?P<slug>.+)/?(.*)' => '_routing', 0 => ['template' => '404'], ...]])
14. in /craft/vendor/yiisoft/yii2/di/Container.php at line 420– ReflectionClass::newInstanceArgs([['enablePrettyUrl' => true, 'ruleConfig' => ['class' => 'craft\web\UrlRule']]])
15. in /craft/vendor/yiisoft/yii2/di/Container.php at line 171– yii\di\Container::build('craft\web\UrlManager', [], ['enablePrettyUrl' => true, 'ruleConfig' => ['class' => 'craft\web\UrlRule']])
16. in /craft/vendor/yiisoft/yii2/BaseYii.php at line 365– yii\di\Container::get('craft\web\UrlManager', [], ['enablePrettyUrl' => true, 'ruleConfig' => ['class' => 'craft\web\UrlRule']])
17. in /craft/vendor/yiisoft/yii2/di/ServiceLocator.php at line 137– yii\BaseYii::createObject(['enablePrettyUrl' => true, 'ruleConfig' => ['class' => 'craft\web\UrlRule']])
18. in /craft/vendor/yiisoft/yii2/base/Module.php at line 748– yii\di\ServiceLocator::get('urlManager', true)
19. in /craft/vendor/craftcms/cms/src/web/Application.php at line 337– yii\base\Module::get('urlManager', true)
331332333334335336337338339340341342343     */
    public function get($id, $throwException = true)
    {
        // Is this the first time the queue component is requested?
        $isFirstQueue = $id === 'queue' && !$this->has($id, true);

        $component = parent::get($id, $throwException);

        if ($isFirstQueue && $component instanceof Component) {
            $component->attachBehavior('queueLogger', QueueLogBehavior::class);
        }

        return $component;
20. in /craft/vendor/yiisoft/yii2/base/Application.php at line 577– craft\web\Application::get('urlManager')
21. in /craft/vendor/craftcms/cms/src/web/Request.php at line 1325– yii\base\Application::getUrlManager()
1319132013211322132313241325132613271328132913301331    /**
     * @inheritdoc
     * @internal Based on \yii\web\Request::resolve(), but we don't modify $_GET/$this->_queryParams in the process.
     */
    public function resolve()
    {
        if (($result = Craft::$app->getUrlManager()->parseRequest($this)) === false) {
            throw new NotFoundHttpException(Craft::t('yii', 'Page not found.'));
        }

        [$route, $params] = $result;

        /** @noinspection AdditionOperationOnArraysInspection */
22. in /craft/vendor/yiisoft/yii2/web/Application.php at line 83– craft\web\Request::resolve()
23. in /craft/vendor/craftcms/cms/src/web/Application.php at line 272– yii\web\Application::handleRequest(craft\web\Request)
266267268269270271272273274275276277278        if (($response = $this->_processActionRequest($request)) !== null) {
            return $response;
        }

        // If we're still here, finally let Yii do it's thing.
        try {
            return parent::handleRequest($request);
        } catch (\Throwable $e) {
            $this->_unregisterDebugModule();
            throw $e;
        }
    }

24. in /craft/vendor/yiisoft/yii2/base/Application.php at line 392– craft\web\Application::handleRequest(craft\web\Request)
25. in /craft/htdocs/index.php at line 26– yii\base\Application::run()
20212223242526define('CRAFT_ENVIRONMENT', getenv('ENVIRONMENT') ?: 'production');
// ...

// Load and run Craft
/** @var craft\web\Application $app */
$app = require CRAFT_VENDOR_PATH . '/craftcms/cms/bootstrap/web.php';
$app->run();
$_COOKIE = [
    '995b21e0a36aa4c8048448ff6b47f0e2_username' => 'e19645b452b9b7241fcb4b7dc183181a4049838dafe8be02069113ebd7340026a:2:{i:0;s:41:"995b21e0a36aa4c8048448ff6b47f0e2_username";i:1;s:6:"romain";}',
    '__stripe_mid' => '882c7bc3-d7ad-4112-8d33-013290d93a1d7338bf',
    'CraftSessionId' => '5llcnmtaj41jff4c7as8brjbis',
    '995b21e0a36aa4c8048448ff6b47f0e2_identity' => 'b0c2e55676bf38712dfdd0532f00f0dfdb65c758a2647c19613d23545c3e6a8ca:2:{i:0;s:41:"995b21e0a36aa4c8048448ff6b47f0e2_identity";i:1;s:162:"[1,"[\\"9G1zyF4RyqB7f8O1qoRlWk7ai_OGFPpxyGGzYbK1-7J_2pAsM-cy3enNnkrEZ1c7AxIdHxuVOteT0BFd7D62dgJok6v3-B-l8kcn\\",null,\\"7a1be88ae2876bc140d8e40ea8063137\\"]",1209600]";}',
    'CRAFT_CSRF_TOKEN' => '046a4c8c54a050947e90f3a9cca79dcbbf68bba19765de69f5c0f8a60f6ae0f4a:2:{i:0;s:16:"CRAFT_CSRF_TOKEN";i:1;s:208:"jDjZkXM6-KgOwpu9_VsYXfZ-zsAaBw-4rSGsh5n2|3484f7fd03556a3554793eb58c68e44c99d3a5071e08b5c44d1f048ab2cb84abjDjZkXM6-KgOwpu9_VsYXfZ-zsAaBw-4rSGsh5n2|1|$2y$13$XtIKCAYwsTHI9E2UEoWw9.apP12TFzjMDLqfTRLcrdykSgbxTU3qi";}',
];

$_SESSION = [
    'c6cbdb11005a3ca9189a19b4ea85e25e__flash' => [],
    'c6cbdb11005a3ca9189a19b4ea85e25e__auth_access' => [
        'editStructure:3',
        'seomaticPreviewAuthorizationKey4730',
        'previewElement:4730',
        'saveAssetInVolume:1',
        'seomaticPreviewAuthorizationKey13572',
        'previewDraft:35',
        'seomaticPreviewAuthorizationKey14745',
        'previewDraft:36',
        'seomaticPreviewAuthorizationKey14860',
        'previewDraft:37',
        'saveAssetInVolume:3',
        'previewElement:14860',
        'previewDraft:38',
        'seomaticPreviewAuthorizationKey17012',
        'previewDraft:39',
        'seomaticPreviewAuthorizationKey17518',
        'seomaticPreviewAuthorizationKey8',
        'previewElement:8',
        'seomaticPreviewAuthorizationKey5390',
        'previewElement:5390',
        'seomaticPreviewAuthorizationKey12',
        'previewElement:12',
        'seomaticPreviewAuthorizationKey62',
        'previewElement:62',
        'seomaticPreviewAuthorizationKey16',
        'previewElement:16',
        'seomaticPreviewAuthorizationKey22',
        'previewElement:22',
        'seomaticPreviewAuthorizationKey30',
        'previewElement:30',
        'seomaticPreviewAuthorizationKey5523',
        'previewElement:5523',
        'seomaticPreviewAuthorizationKey5420',
        'previewElement:5420',
        'seomaticPreviewAuthorizationKey5380',
        'previewElement:5380',
        'seomaticPreviewAuthorizationKey2',
        'previewElement:2',
        'seomaticPreviewAuthorizationKey28114',
        'previewElement:28114',
    ],
    '995b21e0a36aa4c8048448ff6b47f0e2__token' => '9G1zyF4RyqB7f8O1qoRlWk7ai_OGFPpxyGGzYbK1-7J_2pAsM-cy3enNnkrEZ1c7AxIdHxuVOteT0BFd7D62dgJok6v3-B-l8kcn',
    '995b21e0a36aa4c8048448ff6b47f0e2__id' => 1,
    '__authKey' => '["9G1zyF4RyqB7f8O1qoRlWk7ai_OGFPpxyGGzYbK1-7J_2pAsM-cy3enNnkrEZ1c7AxIdHxuVOteT0BFd7D62dgJok6v3-B-l8kcn",null,"7a1be88ae2876bc140d8e40ea8063137"]',
    '995b21e0a36aa4c8048448ff6b47f0e2__expire' => 1640768969,
    '__duration' => 1209600,
];
Yii Framework
2021-12-15, 10:09:30

Apache/2.4.46 (Unix) OpenSSL/1.0.2u mod_fastcgi/mod_fastcgi-SNAP-0910052141 mod_wsgi/3.5 Python/2.7.13 mod_perl/2.0.11 Perl/v5.30.1

Yii Framework/2.0.43

Any idea of what's going wrong? I didn't found any related issue.

Additional info

brandonkelly commented 2 years ago

Sounds like an issue with your routes in config/routes.php, which is covered in the upgrade guide here.

Can you post the contents of that file?

romainpoirier commented 2 years ago

That's what I thought, as this is from a very old Craft 2 website, not the most mature:

<?php

return array(
    '/?404/?(.*)'               => '404',
    '/?(?P<slug>.+)/?(.*)'      => '_routing',
    '/?(.*)/(?P<slug>.+)/?(.*)' => '_routing',
);

But even after replacing this by an empty array(), the same error is shown.

brandonkelly commented 2 years ago

Those values need to be updated to template rule arrays:

<?php

return [
    '/?404/?(.*)' => ['template' => '404'],
    '/?(?P<slug>.+)/?(.*)' => ['template' => '_routing'],
    '/?(.*)/(?P<slug>.+)/?(.*)' => ['template' => '_routing'],
];

But even after replacing this by an empty array(), the same error is shown.

Hm not sure what to make of that. The stack trace definitely shows that it is due to a misconfigured route array. Maybe you forgot to save your changes, or PHP just hadn’t noticed that you had changed the file due to OPcache.

romainpoirier commented 2 years ago

Thank you. I have edited the content with your uodated version, but unfortunately without any change.

I have also resave and reboot the server twice after modifying all of routing.php to <?php return array(); but the same error is still returned for every page on front-end. Even if I empty the /templates folder with a single very simple template.

From what I know, there's no caching enabled on my MAMP.

No further idea to investigate?

brandonkelly commented 2 years ago

it’s config/routes.php, not routing.php. Was that a typo, or are you maybe editing the wrong file?

romainpoirier commented 2 years ago

Sorry it was just a typo, I can confirm that the file is located at config/routes.php using <?php return array();.

brandonkelly commented 2 years ago

Not really sure what to make of this, then. Can you zip up your whole project along with a database backup and send it into support@craftcms.com? We can look into it from there.

romainpoirier commented 2 years ago

Done ✔. Thank you.

brandonkelly commented 2 years ago

Thanks! Was able to reproduce with your site and it is indeed a Craft bug, caused by your 404 route defined in SettingsRoutes. Turns out you’d get this error any time the first control panel-defined route had a numeric URI pattern. That doesn’t seem very far-fetched so I’m pretty surprised no one has run into this before.

It’s fixed now for the next release. To get the fix early, change your craftcms/cms requirement in composer.json to "dev-develop as 3.7.26" and run composer update.

romainpoirier commented 2 years ago

Thank you @brandonkelly. The UrlRule::pattern must be set error is now over.

But I now get a preg_match(): Compilation failed: quantifier does not follow a repeatable item at offset 1even with this as config/routes.php:

<?php

return [
    '/?404/?(.*)' => ['template' => '404'],
    '/?(?P<slug>.+)/?(.*)' => ['template' => '_routing'],
    '/?(.*)/(?P<slug>.+)/?(.*)' => ['template' => '_routing'],
];

Any idea why or if it's a related issue to what have been fixed?

timkelty commented 2 years ago

@romainpoirier if a pattern starts with a slash as yours do, you need to escape it, otherwise PHP will think you are using / as your regex delimiter.

That said, there are some other things going on:

Named parameters in the pattern should be defined using the format (<ParamName:RegExp>) rather than as a regular expression subpattern ((?P<ParamName>RegExp)).

Have another look at the upgrade guide for URL rules, which covers this.

So, your patterns should look something like this :

'404/?<pathRemainder:.*>' => ['template' => '404'],

pathRemainder will then be available in your template.

brandonkelly commented 2 years ago

Craft 3.7.27 is out with that initial bug fix.