laravel5路由改为规则匹配

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了laravel5路由改为规则匹配相关的知识,希望对你有一定的参考价值。

laravel已经有很多项目在使用,但是路由配置却是一个不可缺少的工作,很多时候路由配置工作不仅增加重复工作量而且还会增加代码开销,当项目到一定的级别时路由配置数量将是惊人的。

很多时候不得不认为laravel路由配置虽然灵活但很臃肿,反而使用其它可以自动匹配的路由的框架更方便。当项目中路由是按 命名空间类名+方法名 时就可以使用通用的配置方式来简化路由配置。

如果laravel使用自动匹配路由是否会折损框架本身的功能或特性么?这是由使用人或决策人来判定的,如果认为路由过多是可以接受的那么则不需要这么操作。

当如果需要这么配置时,可以直接使用下面的代码块。

路由配置代码如下:(这块代码需要配置到其它路由后面,否则可能会影响其它路由匹配)

    //所有其它路由不可在这条之后添加
    Route::any(‘/{controller}.{action}/{one?}/{two?}/{three?}/{four?}/{five?}‘, [
                ‘as‘ => ‘mvc‘,
                ‘uses‘ => function() {
                    return abort(404);
                }])
            ->where(‘controller‘, ‘(.*)‘);
    //匹配mvc成功后事件处理
    Route::matched(function(IlluminateRoutingEventsRouteMatched $matched) {
        if ($matched->route->getName() == ‘mvc‘) {
            $controllerParam = $matched->route->parameter(‘controller‘);
            $actionParam = $matched->route->parameter(‘action‘);
            //必需合法
            if (!preg_match(‘#[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*(/[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*)+#‘, $controllerParam . ‘/‘ . $actionParam)) {
                return;
            }
            //控制器与方法解析匹配
            $space = explode(‘/‘, $controllerParam);
            $namecpase = $matched->route->getAction(‘namespace‘) ?: ‘App\Http\Controllers‘;
            $controller = rtrim($namecpase, ‘\‘) . ‘\‘ . implode(‘\‘, array_map(‘studly_case‘, array_filter($space))) . ‘Controller‘;
            $action = studly_case($actionParam);
            if (!method_exists($controller, $action)) {
                return;
            }
            $method = new ReflectionMethod($controller, $action);
            $comment = $method->getDocComment();
            if(!$method->isPublic() || !preg_match(‘/@methods(s*([a-z]+)(s*,s*[a-z]+)s*)/i‘, $comment, $matches)){
                return;
            }
            $methods = array_map(function($item) {
                return trim(ltrim($item, ‘,‘));
            }, array_slice($matches, 1));
            if(!in_array(request()->method(), $methods)){
                return;
            }
            //路由参数处理
            $parameters = array_keys($matched->route->parameters());
            $parameters = array_slice($parameters, array_search(‘one‘, $parameters));
            $setParameters = [];
            foreach ($method->getParameters() as $num => $parameter) {
                $class = $parameter->getClass();
                if ($class && is_subclass_of($class->name, IlluminateDatabaseEloquentModel::class) && !is_null($matched->route->parameters[$parameters[$num]])) {
                    $setParameters[$parameter->name] = $matched->route->parameters[$parameters[$num]];
                }
            }
            $matched->route->parameters = array_merge($setParameters, $matched->route->parameters);
            $actions = $matched->route->getAction();
            $actions[‘uses‘] = $controller . ‘@‘ . $action;
            $actions[‘controller‘] = $actions[‘uses‘];
            $matched->route->setAction($actions);
        }
    });

控制器配置代码:

namespace AppHttpControllersIndexController;

class IndexController extends Controller {
    /**
     * 初始化,配置中间件
     */
     public function __construct() {
        $this->middleware([‘auth‘], [‘only‘ => [‘modify‘], ‘except‘ => [‘add‘]]);
    }

    /**
     * 列表
     * @return IlluminateContractsViewFactory|IlluminateViewView
     * @methods(POST, GET)
     */
    public function lists() {
              return view(‘index.lists‘, [‘lists‘ => Model::paginate()]);
        }
         /**
     * 列表
     * @return IlluminateContractsViewFactory|IlluminateViewView
     * @methods(GET)
     */
        public function add() {
                return view(‘index.add‘, []);
        }
         /**
     * 列表
     * @return IlluminateContractsViewFactory|IlluminateViewView
     * @methods(GET)
     */
        public function modify(Model $model){
                return view(‘index.modify‘, [‘model‘ => $model]);
        }

访问地址分别是:
http://localhost/index.lists
http://localhost/index.add
http://localhost/index.modify/{model_id}

需要注意的是,这种配置方式优化了路由性能,减少了路由配置工作,但会直接暴露控制器的相对路径(对此有偏见的不建议使用),同时也会影响通过路由获取URL的功能,比如route()函数,需要通过控制器的相对路径,不好再指定其它别名(当然这块影响还好)。

使用注意事项:
1、非通用的中间件配置需要放到控制器的构造函数来配置,也可以指定使用或排除的函数名,如上面的代码中
2、控制器方法可以支持到5个路由参数,参数是以{action}之后开始,可以自由配置参数类型
3、控制器方法允许的请求类型通过注释来配置@methods(POST, GET) 可以配置想要的对应请求类型,不配置不能访问,并且方法是共有方法
4、如果需要通过route()函数生成路由地址,需要指定对应的路径参数,如:route(‘mvc‘,[‘controller‘=>‘index‘,‘action‘=>‘lists‘]) 或者另外封装
5、控制器与方法是严格匹配合法标识符,匹配不到的直接404,安全性好,有偏见的可以自行修改
6、这种配置可以与标准配置同时存在,只是规则不重叠即可,理论上这种配置放到最后会更好
7、这种配置可以派生到域名参数,或其它参数上,看项目的需求

以上是关于laravel5路由改为规则匹配的主要内容,如果未能解决你的问题,请参考以下文章

Laravel5添加新路由文件并制定规则

laravel5.5学习2-路由系统

thinkphp路由的完整匹配

thinkphp路由的完整匹配

laravel5.1基础路由的使用

laravel5.1基础路由的使用