前面学习的路由与控制器,接下来学习如何把路由与控制器关联起来

配置路由关联控制器

  • Routeget 或者 post 方法,第一个参数就是我们要定义的路由,就是我们在地址栏请求的那段url, 第二个参数可以是一个闭包函数里面写请求定义的路由时执行的内容但是如果把代码都放这个闭包函数中是臃肿且难以维护的所以就需要使用控制器了。

  • 很显然控制器就是来替代这第二个参数的闭包函数的写起来也非常简单直接写控制器名即可,然后用 @ 符号分割控制器和控制器的方法Route::get('test/index','TestController@index'); Route::get('test/create','TestController@create'); Route::get('test/store','TestController@store');

  • 接着在控制器中写点东西

  • 这样我们在浏览器访问就可以看到返回的响应

路由分组

多么完美但是如果你和我一样帅,一样懒,你回发现三条路由都是 test/ 未前缀,在路由中应该减少这样的重复但是怎么做呢?接下来我们来了解了路由分组的概念

路由分组有啥好处?

有时候啊 一大堆路由它们都有共同的地方,比如都使用一个中间件(过两天写)或是前缀都一样,避免代码重复 我们可以将他们分到一组中。

路由组允许你在大量路由之间共享路由属性,例如中间件或命名空间,而不需要为每个路由单独定义这些属性。共享属性应该以数组的形式传入 Route::group 方法的第一个参数中。

嵌套的组尝试智能地「合并」其属性及其父组。中间件和 where 条件语句在附加名称、命名空间和前缀时被合并。在适当的情况下,命名空间的分隔符和斜线会被自动添加到 URI 前缀中

我们先来定义一个前缀路由组,上面这3条路由就可以改造成这个样子了

Route::prefix('test2')->group(function () {
    Route::get('index', 'TestController@index');
    Route::get('create', 'TestController@create');
    Route::post('store', 'TestController@store');
});

随着项目的扩大如果控制器都直接放在 app/Http/Controllers 目录下的话,那维护起来也开始也很头疼了于是就可以为控制器分目录存放.

比方说说建个 app/Http/Controllers/Admin/StoreController.php,再建一个 app/Http/Controllers/Home/IndexController.php命令行也是可以加目录的

1. php artisan make:controller Admin/StoreController --resource

2. php artisan make:controller Home/IndexController --resource

再在新建的控制器中写点内容加以区分

这种多级目录是不需要指明目录的只需要指明相对于app/Http/Controllers 目录的 namespace 即可

Route::prefix('admin/store')->namespace('Admin')->group(function () {
    Route::get('index', 'StoreController@index');
    Route::get('create', 'StoreController@create');
    Route::post('store', 'StoreController@store');
});

group 是可以嵌套的那么上面这样的路由还可以改造下

Route::prefix('home')->namespace('Home')->group(function () {
    Route::prefix('index')->group(function () {
        Route::get('index', 'IndexController@index');
        Route::get('create', 'IndexController@create');
        Route::post('store', 'IndexController@store');
    });
});

访问http://study.laraveltest.com/home/index/indexhttp://study.laraveltest.com/admin/store/index 会得到这样的响应

因为创建的目录下我们还会创建更多的路由器所以,我们应该使用 group 嵌套的这种方式,比如说我们再有一个 app/Http/Controllers/Home/TagController.php 执行创建控制器命令 php artisan make:controller Home/TagController --resource 那么路由就是这样的

Route::prefix('home')->namespace('Home')->group(function () {
    Route::prefix('index')->group(function () {
        Route::get('index', 'IndexController@index');
        Route::get('create', 'IndexController@create');
        Route::post('store', 'IndexController@store');
    });
    Route::prefix('tag')->group(function () {
        Route::get('index', 'TagController@index');
        Route::get('create', 'TagController@create');
        Route::post('store', 'TagController@store');
    });
});

路由参数

到这里我们已经学会了如何组织多级目录了,让我们回到 app/Http/Controllers/TestController.php 控制器上

会发现命令行创建的控制器里面有个 edit 方法,edit 方法有个 $id 参数,通过名字我们很容易就明白这是用来修改数据的,id 一般又是数据库的自增字段,但是这个 id 是哪传来的呢?下面就到了了解路由参数的时候了。

定义路由的时候我们是可以定义路由参数,我们接着上面的路由加一个 edit ,我们在定义路由的时候用花括号包一个变量名那这个变量就可以直接传到控制器方法中然后在地址栏传什么控制器中就可以接到什么为了方便测试我们在这个方法中返回 id

Route::prefix('test2')->group(function () {
    Route::get('index', 'TestController@index');
    Route::get('create', 'TestController@create');
    Route::post('store', 'TestController@store');
    Route::get('edit/{id}', 'TestController@edit');
});


接下来我们访问http://study.laraveltest.com/test2/edit/2344

这里面有个值得注意的地方,就是控制器中的参数名跟路由参数名不是必须相同的,一个路由参数的时候这倒不会觉得什么,一旦定义多个路由参数的时候,这就有点坑了
重新写一个方法edit1

    /**
     * @param $name
     * @param $id
     *
     * @return string
     */
    public function edit1($name,$id)
    {
        return '吾乃 Test 控制器的 edit 方法,地址栏的传参id为: "'. $id .'",name为: "'.$name.'"';
    }

配置路由

Route::prefix('test2')->group(function () {
            ...
    Route::get('edit1/{id}/{name}', 'TestController@edit1');
});

访问 http://study.laraveltest.com/test2/edit1/2344/风清醉

你会发现 id 和 name 没对上,这边画个重点 路由参数中的第一个参数对应控制器中的第一个路由参数以此类推在控制器中路由参数跟参数名是没关系的只跟顺序有关。

再个 id 一般都是纯数字,这里却传了字母 ,我们应该怎么约束下 id 呢?laravel 方方面面都为我们考虑到了,我们加个 where 就行了。

Route::prefix('test2')->group(function () {
    ...
    Route::get('edit1/{id}/{name}', 'TestController@edit1')->where('id', '[0-9]+');;
});

这样就只能传数字了其实大多的表都是用 id 做主键的如果每个路由都手动定义一遍约束那也是挺麻烦的laravel 又一次方方面面都为我们考虑到了。

找到 app/Providers/RouteServiceProvider.php 这个文件在 boot 方法中可以定义全局约束 Route::pattern('id', '[0-9]+');
这样就不需要为每条带 id 参数的路由定义约束了,以后所有带 id 参数的路由就只能传数字了。

请求参数

路由参数容易搞混的是请求参数路由参数?请求参数?傻傻分不清楚

我们请求 http://study.laraveltest.com/test2/edit1/2344/清风醉?code=12345&status=succ idname 就是路由参数 codestatus就是请求参数,路由参数上文已经介绍了,那么请求参数怎么获取呢?

现在让我们回到控制器里去找 update 方法

   /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        //
    }

这个 Request $request 就是我们用来获取请求参数的关键,它的意思是向控制器的方法传一个 $request 它是一个 Request 类,我们可以把我们的 edit 方法也加个 $request

    /**
     * @param Request $request
     * @param         $name
     * @param         $id
     *
     * @return string
     */
    public function edit1(Request $request, $id, $name )
    {

        $code   = $request->input('code');
        $status = request()->input('status');

        return '吾乃 Test 控制器的 edit 方法,地址栏的传参id为: "' .
            $id . '",name为: "' .
            $name . '",code为: "'.
            $code.'",status为: "'.
            $status.'"';
    }

这个 Request $request 是不会影响路由参数的顺序的 它放前放后都是可以的,我们访问这个方法并携带请求参数

Request 类有一个 input 方法,把要获取的参数名传给它就可以了,我上面示例中还用了个 request() 函数它跟 Request $request 效果是一样的,$request 可以方便复用,所以在控制器中更推荐使用$request,如果传的请求参数比较多的时候这样一个一个取贼麻烦,Request 还有个 all 方法就可以获取全部的请求参数

public function edit(Request $request, $id, $name)
{
    dump($request->all());
}

dump 是 laravel 自带的一个打印函数,就是 php 自带的 var_dump 函数的升级版,打印的效果如下

Request 还有个 only 方法作用是从一大堆请求参数中获取指定的请求参数

public function edit(Request $request, $id, $name)
{
    dump($request->only('music', 'book'));
}

Request 还有个 except 方法作用是排除某个参数剩下的全要

public function edit(Request $request, $id, $name)
{
    dump($request->except('music'));
}