Jeen 2017-12-15 18:03:40 7967次浏览 6条评论 3 0 0

关于Yii2 配置文件中路由规则的使用说明 (基于yii2.0.12)

看到挺多同学在问URL路由规则的问题,本人之前也踩过些坑,所以感觉有必要整理一下,方便后来者

PS: 也看了挺多站内的问答, 大体上都是在讲一些 yii2官方文档中给出的说明, 说一些基础的配置方法。然而大多数时候并没有讲到实质问题,所以感觉有必要重新归纳整理一番

配置代码段

//...
'urlManager' => [
    'enablePrettyUrl' => true,
    'showScriptName' => false,
    'cache' => YII_DEBUG ? false : 'cache',
    'suffix' => '.html',
    'rules' => [
        'pattern' => 'route', //写法1
        [
            'class' => 'yii\web\UrlRule',//非必要
            'pattern' => '',
            'route' => '',
            'suffix' => '.do',// 优先级高
            //...其它
        ], //写法2
        //...
    ],
],

如上,常见的rule配置有两种方式:
1、 'pattern' => 'route' 的形式
2、 数组的形式,如果数组中不指定使用的类, 默认即是: yii\web\UrlRule::class

下面咱们分开阐述一下这两种方式的使用

//方式1
//适合一些比较简单的路由规则设置,但是如果出现可选参数,可以采用 配置多条规则的方式解决。
//例如,规则如下
'site/test-<a:\w+>-<b:\w+>' => 'site/index',
'site/test-<b:\w+>' => 'site/index',

//测试
echo Url::to(['site/index', 'b'=>'bvalue']); 
//输出  /site/test-bvalue.html 
//... 
//其它同理

当然,如果你的参数比较多,建太多规则显然是不合适的。
另外就是这种多规则并存使用,容易出现混乱。

//假设我定义3条规则
'site/test-<a:\w+>-<b:\w+>' => 'site/index',
'site/test-<b:\w+>' => 'site/index',
'site/test-<a:\w+>' => 'site/index',

//那么在我访问  /site/test-value.html  的时候
// 这个  value 是a的值还是b的值呢?
//为了避免这种问题, 就可能需要把规则修改为如下配置

'site/test-a<a:\w+>-b<b:\w+>' => 'site/index',
'site/test-b<b:\w+>' => 'site/index',
'site/test-a<a:\w+>' => 'site/index',

所以,个人建议在出现多参数,或者参数为可选时,使用数组的形式进行配置。
下面我们看下数组的配置用例

//沿用 上述例子, 注意  这时候  我们只定义下面一个路由规则
[
    'pattern' => 'site/test-<a:\w+>-<b:\w+>',
    'route' => 'site/index',
],
//先看看 
echo Url::to(['site/index','b' => 'bvalue']);
//输出   /site/index.html?b=bvalue
//变成了 带问号的 get传参形式, 这当然不是我们想要的。

//调整rule配置,如下
 [
    'pattern' => 'site/test-<a:\w+>-<b:\w+>',
    'route' => 'site/index',
    'defaults' => [ //默认值
        'a' => '', //只能是 空字符串
    ],
],
//新增了 参数默认值的配置
//重新测试  输出  /site/test--bvalue.html 

//到这边其实已经满足了我们的基础需求, 但还是不完善的

为什么不完善呢? 可能你也注意到了,上述 样例配置中 //只能是 空字符串 的注释说明.

截止到目前的官方版本,其它默认值还是不支持的。

比如我修改 a 的默认值为 avalue , 测试结果并不是 /site/test-avalue-bvalue.html
而是回到了 /site/index.html?b=bvalue 的状态

这也不是我想看到的结果, 我可能想把 a 的默认值设置为各种 类似 0 - 9 一些约定的 string等等。

那该如何解决呢?

这时候就比较费劲了, 需要修改框架的核心代码,或者扩展自定义一下。
当然个人建议是 继承后做自定义修改。
操作的具体过程我就不赘述了,请确认你知道如何自定义一个组件类,并能理解配置中指定某个组件类的原理。

核心操作说明:
修改yii\web\UrlRulecreateUrl 方法中 490行附近的代码逻辑

//逻辑流程前有如下的 源码注释,可以参考 进行搜索
        // match default params
        // if a default param is not in the route pattern, its value must also be matched

也可以参考我修改的类
https://github.com/JeanWolf/plat/blob/master/common/core/UrlRuleWeb.php

测试样例如下:

//rule 样例配置
[
    'class' => UrlRuleWeb::class,
    'pattern' => 'site/test-<aa:\d+>-<bb:\d+>-<cc:\d+>',
    'route' => 'site/index',
    'suffix' => '.do', //自定义后缀 可选配置
    'defaults' => [
        'aa' => 2,
        'bb' => '0',
    ],
],

//测试
echo Url::to(['site/index', 'cc' => 3]);
//输出 /site/test-2-0-3.do 

完。

手动测试排版,如有纰漏,欢迎指正。

顺便打个小广告, 个人博客 http://blog.jeen.wang , 欢迎交流切磋。

转载请著名出处。谢谢 :)

  • 评论于 2017-12-15 20:31 举报

    大神!!!赞一个!!!太实质了,找了好几天了 都没讲到这些

  • 评论于 2017-12-15 22:55 举报

    这里还有一个问题 麻烦了:

            'rules' => [
                [
                    'pattern' => 'product',
                    'route' => 'article/product',
                ],
                [
                    'class' => common\core\UrlRuleWeb::class,
                    'pattern' => 'product_<filter_1:\d+>_<filter_4:\d+>_<filter_7:\d+>_<filter_12:\d+>_<page:\d+>',
                    'route' => 'article/product',
                    'suffix' => '',//自定义后缀 可选配置
                    'defaults' => [
                        'filter_1' => 0,
                        'filter_4' => '0',
                        'filter_7' => 0,
                        'filter_12' => 0,
                        'page' => 1
                    ],
                ], //写法2
                //...
            ],
    
  • 评论于 2017-12-15 22:56 举报

    第一条规则 ,如果加上,那么第二条规则 就不生效了

  • 评论于 2017-12-15 22:59 举报

    第一条规则 加了class你的类 也不行

  • 评论于 2017-12-15 23:00 举报

    另外,如果我把第一条规则去掉了,第二条规则也有个问题,就是参数刚刚好 就是defaults里的那些默认值,那么伪静态就失效了

    2 条回复
    评论于 2017-12-15 23:47 回复

    留意下 UrlRuleWeb 自定义类中的createUrl 方法的源码
    有一部分是根据个人需求定制的

    //400 行左右
            if ($_default_count == count($this->_paramRules)) {
                $this->createStatus = self::CREATE_STATUS_PARAMS_MISMATCH;
                return false;
            }
    //这边  个人为了防止 "无参情况下,都使用默认值" 的情况,加了一个判断条件
    //根据你的需求   把这个判断条件删除掉  应该就可以满足了
    
    //如果希望两条规则同时使用 ,可以在第一条中指定类名,然后修改这个判断条件如下
    
            if ($_default_count > 0 && $_default_count == count($this->_paramRules)) {
                $this->createStatus = self::CREATE_STATUS_PARAMS_MISMATCH;
                return false;
            }
    
    //测试配置如下
    
                [
                    'class' => UrlRuleWeb::class,
                    'pattern' => 'product',
                    'suffix' => '.do',//自定义后缀 可选配置
                    'route' => 'article/product',
                ],
                [
                    'class' => UrlRuleWeb::class,
                    'pattern' => 'product_<filter_1:\d+>_<filter_4:\d+>_<filter_7:\d+>_<filter_12:\d+>_<page:\d+>',
                    'route' => 'article/product',
                    'suffix' => '.html',//自定义后缀 可选配置
                    'defaults' => [
                        'filter_1' => 0,
                        'filter_4' => 0,
                        'filter_7' => 0,
                        'filter_12' => 0,
                        'page' => 1
                    ],
                ], //写法2
    
    

    由于是根据项目需求定制,难免会有差异
    欢迎补充 各种场景下的处理方案 :)

    评论于 2017-12-28 10:17 回复

    好的 谢谢

  • 评论于 2017-12-28 14:54 举报

    新手拜读。

您需要登录后才可以评论。登录 | 立即注册