A-A+

laravel4.2框架路由配置深入了解(下篇)

2016年01月05日 站长资讯 暂无评论

注意:参数过滤器,并不是把参数转换为对于合法格式数据,而是参与路由匹配程序,也就是说,如果存在参数名,则必须达到表达式的要求则才通过参数匹配,否则是不会进入当前路由节点。正则不需要添加^$这两个开始与结束限定符,程序会默认添加。域名与路由URL指定的参数都会受参数过滤影响,提取出来的参数会依先后的顺序传入Action处理方法中(域名的参数在前面)

如:

  1. Route::get('test/filter/{id}','TestController@filter')->where('id', '\d+');  

请求地址:

  1. test/filter  
  2.   
  3. test/filter/12  
  4.   
  5. test/filter/arg  

以上三个地址中,只有中间的一个会通过路由并进入TestController@filter控制器。

如果路由规则为:

  1. Route::get('test/filter/{id?}','TestController@filter')->where('id', '\d+');  

则前面两个请求都可以通过。

  1. /*============= 路由Controller配置 =============*/  
  2.   
  3. /*  
  4. *作用:批量添加路由  
  5. *参数:$controllers 每个数据元素相当于调用 controller 方法,[ URL=>Controller类名 ]  
  6. *返回值:null  
  7. */  
  8. Route::controllers(array $controllers);  
  9.    
  10.    
  11. /*  
  12. *作用:添加Controller路由  
  13. *参数:$uri [string] 控制器的路由,不含Action部分,默认Action为Index  
  14. *      $controller [string] 控制器类名,含命名空间  
  15. *      $names [array] 设置路由节点的as别名,[Action=>as]  
  16. *返回值:null  
  17. */  
  18. Route::controller($uri, $controller, $names = array());  

这类路由配置比常规配置方便,每个Controller文件只占用一个路由配置,类似其它框架如YII或CI的路由规则,但每个Action命名必须以常规路由方法为前缀(get,post,any等,但match除外)打头,如:getList,postList,anyList等等。命名中Action的大小写必须非常严格,前缀必须小写,Action部分第一个字母大写(如果Action的名为: anyGoodsList 这种的则请求的URL地址应该是 $url/goods-list)。不要以为PHP对类名与方法名无大小写区分而忽略这点,其实这类路由配置会加载每一个Controller文件,并且使用映射类来提取可用的Action名,以大写字母为界线添加 - 符号(除前缀get,any,post等被忽略)生成对应的URL地址然后根据Action的请求类型使用对应常规添加路由的方法把这些Action都再次添加到常规路由列表中。

例如:

  1. Route::controller('home', 'HomeController',['anyList'=>'homeList']);  

在HomeController.php文件中有三个Action方法名:

anyList

postEditData

getDelete

实际上路由解析器会生成三个常规路由:

  1. Route::any('home/list/{one?}/{two?}/{three?}/{four?}/{five?}', array('uses' => 'HomeController@anyList','as'=>'homeList'));  
  2.   
  3.   
  4. Route::post('home/edit-data/{one?}/{two?}/{three?}/{four?}/{five?}', array('uses' => 'HomeController@postEditData'));  
  5.   
  6.   
  7. Route::any('home/delete/{one?}/{two?}/{three?}/{four?}/{five?}', array('uses' => 'HomeController@getDelete'));  

并且还会生成一个请求匹配失败的默认处理路由节点:

  1. Route::any('home/{__missing}','HomeController@missingMethod')->where('_missing','(.*)');  

注意:使用Controller路由方式的,实际上是间接的使用常规路由,所以每个Action名称必须以常规路由方法名为前缀(get,post,any等,match除外)。所生成的URL地址是允许传入5个路径参数,这是默认的,当然如果你需要更多的参数可以去修改 Illuminate\Routing\ControllerInspector 的addUriWildcards方法的返回值,或者去扩展继承。

也正因为这类路由配置会加载Controller文件所以当某个文件出错或不存在时,整个路由块都无法正常工作。所以在使用这类路由配置时得注意,并且最后给对应的控制器添加一个missingMethod方法,这个方法是用来处理当没有匹配的Actin时执行的方法,可以用于处理错误请求或调试。

  1. /*============= 路由高级配置 =============*/  
  2. /*============= 路由分组 =============*/  
  3.    
  4. /*  
  5. *作用:以组的方式添加路由,同时添加一些相同的配置  
  6. *参数:$attributes [array] 公共配置属性,支持常规配置($action为数组时)所以属性。  
  7. *      $callback [closure] 匿名函数,(函数会传入一个参数Illuminate\Routing\Router)。  
  8. *返回值:null  
  9. */  
  10. Route::group(array $attributes, Closure $callback);  

组配置是方便一些有相同属性的路由批量追加的好方法,也可以递归组(最内层组会覆盖外层组相同的公共配置属性),组内的路由会自动提取当前所在组的公共配置属性,并且覆盖相同的配置。

配置说明:Route::group组配置,支持常规路由配置($action为数组时)所有元素,并且在这个基础上还增加了一个 'namespace' 键名,可以指定组内所以控制器的命名空间前缀,也就是说,组配置其实没有什么特殊功能,只是用于多个路由节点使用了相同的一些属性时,方便处理,使路由配置更加的清晰。

注意:只有namespace,prefix这两个属性值不会被覆盖,而是追加到当前路由节点的前面。namespace是追加到当前控制器的类名前面,而prefix则是追加到当前路由节点的prefix元素前面。常规路由指定了namespace属性是无效的。

如:

  1. Route::group([  
  2.   
  3.     'namespace'=>'index\goods',   //指定命名空间前缀  
  4.   
  5.   
  6.     'prefix'=>'dc-',      //指定URL前缀  
  7.   
  8.   
  9.     'domain'=>'www.{laravel}.com',    //指定域名  
  10.   
  11.     'before'=>'name:filter|list:filter', //进入action前参数过滤处理规则  
  12.     'after'=>array('name','list') //调用action返回值进行过滤处理规则  
  13.   
  14.     ],function($router){  
  15.   
  16.         $router->get('index/list','IndexController@showList');//追加路由节点  
  17.   
  18.         //追加路由节点  
  19.   
  20.         $router->get('index/edit/{id}',['uses'=>'IndexController@showList','before'=>'']);  
  21.   
  22.         $router->controller('index/goods','GoodsController');//追加多个路由节点  
  23.   
  24.   
  25. });  

上面组中第一个路由节点同等于:

  1. Route::get('index/list',[  
  2.   
  3.     'uses'=>'index\goods\IndexController@showList'  
  4.   
  5.     'prefix'=>'dc-',      //指定URL前缀  
  6.   
  7.   
  8.     'domain'=>'www.{laravel}.com',    //指定域名  
  9.   
  10.     'before'=>'name:filter|list:filter', //进入action前参数过滤处理规则  
  11.     'after'=>array('name','list') //调用action返回值进行过滤处理规则  
  12.   
  13. ]);  

也就是说,以组的方式添加路由节点就是为了提取公共的配置,批量的追加到组内的路由节点中。组与组是可以递归的,当然递归后内层组是可以覆盖外层的公共配置(namespace,prefix是被连接而非覆盖)。

  1. /*============= 路由给Action添加Model对象参数 =============*/  
  2. /*  
  3. *参数:$key [string] 参数名,必需与路由节点的提取参数名相同才会被调用替换  
  4. *      $class [string]  对应的Model类名。  
  5. *      $callback [Closure|null] 如果对应的Model返回空则执行这个匿名函数  
  6. *返回值:null  
  7. */  
  8. Route::model($key, $class, Closure $callback = null);  

注意:使用这种方式给控制器的Action方法传入Model对象参数时,如果Model对象获取数据为空时,必需要指定$callback匿名函数,否则路由报错(匹配失败),即无法正常进入路由。

Model注入参数方式是全局的,其所以前面路由节点只要参数名相同都会被替换并执行对应的Model。

例:

  1. Route::model('user','Users',function(){ //注入Model参数,只要参数名为“user”则生成Model。  
  2.   
  3.     return []; //Model创建失败  
  4.   
  5. });  
  6.   
  7. Route::get('user/orders/{user}',function($user){ //追加路由,并提取参数“user”  
  8.   
  9.     return $user; //直接输出 JSON 串  
  10.   
  11. })->where('user','\d+'); //对参数“user”进行正则过滤处理  

如果Users创建成功则输出对应的JSON串,如果失败则返回空JSON串(注意:框架会自动把数组转为JSON串返回给客户端)。

Model注入方式可以方便的把对应的Model注入到控制器的Action方法中,让程序可以更专注的去做修改添加等处理。

注入Model参数时,并未判断Model类名是否继承于ORM模型(Illuminate\Database\Eloquent\Model别名处理后为Eloquent)

代码如下:

也就是说,只要传入的Model类名包含了find方法,则可以顺利的进入注入,而不一定要指定为ORM模型,当然这样做有违背框架的初衷。

  1. /*============= 路由给Action添加自定义处理参数 =============*/  
  2. /*  
  3. *参数:$key [string] 公共配置属性,支持常规配置($action为数组时)所以属性。  
  4. *      $binder [callable] 可调用函数(传入参数:对应参数值,当前路由节点对象)  
  5. *返回值:null  
  6. */  
  7. Route::bind($key, $binder);  

bind与model同为给Action注入参数,model是更专注为ROM模型处理的,而bind是面向创建更为灵活的参数。从上面的截图可以看的出来,model注入是bind注入的派生子项。

注意:由于bind对于$binder参数要求为可调用函数,则并不像model那样必需为匿名函数,所以bind有更多的调用方法,bind绑定也是全局的。

例:

  1. Route::bind('user',function($id){  //绑定参数名“user”  
  2.   
  3.   
  4.     return [$id]; //返回参数值  
  5.   
  6.   
  7. });  
  8.   
  9. Route::get('user/order/{user}',function($user){  //追加路由节点,并且提取参数“user”的值  
  10.   
  11.     return $user; //返回参数JSON串  
  12.   
  13.   
  14. });  
  15.   
  16.  /*============= 路由资源控制器 =============*/  
  17. /*  
  18. *参数:$name [string] 公共配置属性,支持常规配置($action为数组时)所以属性。  
  19. *      $controller [string] 控制器类名  
  20. *      $options [array] 指定路由项  
  21. *  
  22. *说明:$options 数组结构:  
  23. *    array(  
  24. *        'only'=>array('index', 'create', 'store', 'show', 'edit', 'update', 'destroy'),  
  25. *        'except'=>array('index', 'create', 'store', 'show', 'edit', 'update', 'destroy'),  
  26. *        'names'=>array('index'=>'resource-index'),  
  27. *        'as'=>'resource-route'  
  28. *    )  
  29. *  only 是只需要的Action方法名,except 是只在除了这些Actin方法名但优先级没有only高,也就是  
  30. *  有only时except无意义;names 是指定Action对应的路由节点 as 值,as 是指定当前资源路由下除  
  31.   
  32.   
  33. *  “update”路由节点外的 as 值前缀并以“.”连接默认的 as 值,names的优先级高于 as,也就是  
  34. *  说,设置了names的方法名,再设置 as 最终的路由节点以names为准,其它均无效。  
  35. *  
  36. *返回值:null  
  37. */  
  38. Route::resource($name, $controller, array $options = array());  

路由资源是一种以RESTful架构风格的固定路由生成模块,它不只是可以生成选择性的固定路由节点,还可以通过 artisan 命令自动生成Controller文件。具体的默认路由节点如下:

例:

  1. Route::resource('home','HomeController')  

实际上使用resource默认会生成路由节点有:

注意:"{home}"是$name参数以 "." 为拆分点最后段个字符串(内部的“-”会转为“_”)。除"update"节点外其它每个路由节点都会默认生成一个as值。当然也可以在添加资源路由时追加$options参数指定as值(以 names 下标的数组 [ 方法名 => as值 ] )或指定前缀(以 as 下标的字符串,最后以“.”连接默认的 as 连接名),当然 names 的优先级要比 as 高。

关于 as 值如果理解不来,可以使用,Route::currentRouteName() 获取当前的路由名,再分析。

路由资源使用的是RESTful架构,而这一架构并未得到很好的支持,尤其是浏览器,当然对应移动端的APP则可以使用,但国内对于这种架构认为还不够,所以这种路由方式只需要知道就可以,在实际应用中,会很少采用。

总结:laravel框架路由配置是以每个独立请求URL为一个节点,往往一个系统中有很多的请求地址,所以在配置路由时得因系统的大小合理规划,如果一直在一个文件只添加路由,时间一长,路由节点过多,则会不利于管理。

标签:

给我留言