URL rule routes to wrong place

Hi

This rule

‘profile/<username:\w+>’ => ‘profile/view’

routes this URL


http://localhost/1394/frontend/web/profile/update

to


http://localhost/1394/frontend/web/profile/view

why?

My Yii-foo is a bit rusty, but I think you need to add a more general rule, like:


'profile/<username:\w+>' => 'profile/<action>'

Check out the guide.

The problem is probably that Yii can’t find a general rule, so it takes the rule that it knows, which is ‘profile/view’.

Thanks but I already did what you say before and it ends all ‘profile/something’ to 404. I think you right about a general rule but I still can’t find one works.

So it acts like a alive framework which is unruly too! We should use it for Halloween. ;D

Would you please show all the rules of your UrlManager, and also some example view code that creates wrong urls?

[EDIT]

Is your problem with creation of urls, or parsing of them? Or both?

Here is my UrlManager:




'urlManager' => [

            'enablePrettyUrl' => true,

            'showScriptName' => false,

            'rules' => [

                'poll/<id:\d+>' => 'poll/view',

                'polls' => 'poll/index',

                'user/<username:\w+>' => 'user/timeline',

                'profile/<username:\w+>' => 'profile/view',//If I remove this line, everything starts working again

                


            ],

            

        ],



I’m working on advanced if you mind.

Creation and parsing work for …/profile/username. For example


Url::to(['/profile/view','username'=>Yii::$app->user->identity->username])

creates


/1394/frontend/web/profile/aida

and it ends correctly to


/1394/frontend/web/profile/view?username=aida

But it also makes a request to


http://localhost/1394/frontend/web/profile/update

ends in


http://localhost/1394/frontend/web/profile/view

which is not what is expected.

Thanks for helping me.




http://localhost/1394/frontend/web/profile/update



The url above will fall into the following rule




'profile/<username:\w+>' => 'profile/view',



because "update" can be considered as "username".

Probably the following will work:




'rules' => [

    'poll/<id:\d+>' => 'poll/view',

    'polls' => 'poll/index',

    'user/<username:\w+>' => 'user/timeline',

    'profile/<username:\w+>/<action:\w+>' => 'profile/<action>',

    'profile/<username:\w+>' => 'profile/view',

],



This should create




http://localhost/1394/frontend/web/profile/aida/update



for




Url::to(['/profile/update','username'=>Yii::$app->user->identity->username])



It works but for a different requirement. I don’t want to pass “username” parameter for “update” action.

Please, let me ask a question about the true subject you mentioned.

Is it what we have to expect from the rule?

I think creating rules for url is not a big deal when everything works as we expect from. Am I missing something about <username:\w+> part that makes "update" fall in to trap?

That’s how url rules work.

It is a bit like CSS in that it cascades.

If you think logically about it, you could have a user named ‘update’ and an action called ‘peter’. :)

when I write <username:\w+> I expect a parameter with name of “username” and value of “peter” or “update” is detected by parser not a parameter with each name, but otherwise what is the point of specification a name for it (e.g. username) ? When “username” is ignored by parser why don’t we just write something like this <\w+> ?

The rules have a right hand side and a left hand side - and there is a hugely important difference between


<username>

and username!

The rule tells Yii what slug to use for which action.

Enter http://localhost/peter/update in the address field of your browser.

That doesn’t mean anything.

‘peter’ and ‘update’ could be mapped to whatever you choose.

It would be intelligent to map them to <username>/<action>, but that is your job.

You create some sensible rules for the url manager to follow.

I hope you understand.

Perhaps take a look at some existing (and non-trivial) Yii applications? :)

In url creation, the rule works from right to left. So, “Url::to([’/profile/view’, ‘username’=>‘abc’)” will create “/profile/abc”.

In url parsing, the rule works from left to right. "/profile/xyz" will be parsed as "/profile/view?username=xyz". This might be what you expect. But "/profile/update" will also be parsed as "/profile/view?username=update". Everything that falls into the regex pattern "/profile\/[\w]+/" will be treated like that, since Yii can not tell whether the pattern is a username or not.

The rules are evaluated from top to bottom. If one of them matches the pattern, then it will be used. The rest of the rules will be ignored. So, in your case, you can insert some rule that handles "/profile/update" before "/profile/view" rule.

The most quick and dirty one may be:




'rules' => [

    ...

    'profile/update' => 'profile/update',

    'profile/<username:\w+>' => 'profile/view',

],



Thanks, it works. Your description is very very helpful.

I already used top down priority to solve the problem once but I had chosen a wrong rule.

Again , I appreciate you for helping me.

Problem solved!