0
votes

I have these possible urls:

Having country at beginning:

peru/blog/search/my-search
peru/blog/tag/my-tag
peru/blog/my-blog-post
peru/blog/
peru/

Without Country at beginning:

blog/search/my-search
blog/tag/my-tag
blog/my-blog-post
blog/
/

How it works:

As I understand url management there are 2 processes:

  1. When you write an url on the browser. In this case Yii tries to convert this url into a route and params.

  2. When you are creating an url using Yii::$app->urlManager->createAbsoluteUrl, in example.

According to these, I am writing some rules in the urlManager, first the general config:

'urlManager' => [
            'class'           => 'yii\web\UrlManager',
            'enablePrettyUrl' => true,
            'showScriptName' => false,
            'rules' => []
]

Now the rules:

'<country:peru|france>/<module:[\w\-]+>/tag/<tag:[\w\-]*>' => '<module>/index',
'<country:peru|france>/<module:[\w\-]+>/search/<search:[\w\-]*>' => '<module>/index',
'<country:peru|france>/<module:[\w\-]+>/<slug:[\w\-]*>' => '<module>/index',
'<country:peru|france>/<module:[\w\-]+>' => '<module>/index', 

'<module:[\w\-]+>/tag/<tag:[\w\-]*>' => '<module>/index',
'<module:[\w\-]+>/search/<search:[\w\-]*>' => '<module>/index',
'<module:[\w\-]+>/<slug:[\w\-]*>' => '<module>/index',
'<module:[\w\-]+>' => '<module>/index',

As you notice from the rules, I pass a parameter "module" in the url, and I want that one to be used as controller.

In the case of country I had to add some possible matches, if not I was not able to make it work.

With the above rules, It works when I input a "pretty" url on the browser like:

http://example.com/blog/search/my-search

But my issue starts If try to create an url:

Yii::$app->urlManager->createAbsoluteUrl(["blog/index", "module" => "blog"] 
Rule: '<module:[\w\-]+>' => '<module>/index'
Url Expected: http://example.com/blog
Url Generated: http://example.com/blog?module=blog

It seems it does not fall in the rule, not sure.

If I try to create an url:

Yii::$app->urlManager->createAbsoluteUrl(['blog/index', 'module' => 'blog', 'slug' => 'my-post'])
Rule: '<module:[\w\-]+>/<slug:[\w\-]*>' => '<module>/index'
Url Expected: http://example.com/blog/my-post
Url Generated: http://example.com/blog/my-post?module=blog

From these 2 cases, I notice it is adding the controller to the url

Questions:

  1. In my rule I use I think it collides with predefined variables like: , . I have tried change it, but still same issue.

  2. In the case of country I had to add possible options: Peru, france to make it work, if not it did not work, how can I make it work without those options?

  3. The url match depends on the amount of query params or does it count controller and action too?

  4. How can I make empty parameters be ignored for the rules, when creating an url?

  5. Why is adding controller to the url?

  6. Is the rules order correct?

2

2 Answers

0
votes

I think I found a solution to all my questions:

  1. So far I have not found predefined keywords for rules: <controller>, <action>, <module> are just name of variables, if someone knows something different, please let me know.

  2. Yii URL manager (and probably any URL manager) can only match the amount of parameters we send and match it against rules, not the variable names, so if we send:

    Yii only understands that we are sending one parameter, so if in the rules we have:

    '<language:[\w\-]*>' => 'language/index'
    
    '<country:[\w\-]*>' => 'country/index'
    

    Yii will use the first rule that matches, so in this case would be <language> rule which will match. Then Yii will pass a variable $language with "peru" as value to LanguageControlle, which is wrong.

    So in order to help Yii we have to add patterns to help it use correct rule, we could add a pattern to match only any value with 2 characters or specific values list like:

    <language:es|en> => 'language/index'
    
    <country:[\w\-]*> => 'country/index'
    

    In this case if we have "peru" as value, it will not match first rule, so it will use second one.

  3. Answered above.

  4. Ignore empty parameters, we can use + instead of * in the rules, in that way empty parameters will not match.

  5. Remove the controller, we need to add a rule at the end:

    '' => 'site/index'
    
  6. Question ordering, it should start with the rules with most parameters and inside that group order them from the less generic to more generic rules.

At the end my rules are:

'<base:es|en>/<module:ideas|user|blog>/tag/<tag:[\w\-]*>' => '<module>/index',
'<base:es|en>/<module:ideas|user|blog>/search/<search:[\w\-]*>' => '<module>/index',
'<base:es|en>/<module:ideas|user|blog>/<slug:[\w\-]*>' => '<module>/index',
'<base:es|en>/<module:ideas|user|blog>' => '<module>/index',
'<base:es|en>/<slug:contact>' => 'site/index',
'<base:es|en>' => 'site/index',


'<module:ideas|user|blog>/tag/<tag:[\w\-]*>' => '<module>/index',
'<module:ideas|user|blog>/search/<search:[\w\-]*>' => '<module>/index',
'<module:ideas|user|blog>/<slug:[\w\-]*>' => '<module>/index',
'<module:ideas|user|blog>' => '<module>/index',
'<slug:contact>' => 'site/index',
'' => 'site/index',

I hope this saves time to someone in the future.

0
votes

The problem is how you create URL. If <module> is available in route pattern (value in rules array), then you don't need to pass it manually. It will be detected from route.

Sou you should create your URLs like this:

Yii::$app->urlManager->createAbsoluteUrl(['blog/index', 'slug' => 'my-post'])
Yii::$app->urlManager->createAbsoluteUrl(['blog/index']);