最适合入门的Laravel初级教程(五)路由控制器关联

路由咱会创建了;
控制器也有了;
接下来要搞的就是把两者关联起来了;
最适合入门的laravel初级教程(三)
我们讲过 Route 的 get 或者 post 方法第一个参数就是我们要定义的路由;
就是我们在地址栏请求的那段url;
第二个参数可以是一个闭包函数;
里面写请求定义的路由时执行的内容;
上篇文章我们说过;
如果把代码都放这个闭包函数中是臃肿且难以维护的;
所以就需要使用控制器了;
很显然;控制器就是来替代这第二个参数的闭包函数的;
写起来也非常简单直接写控制器名即可;
然后用 @ 符号分割控制器和控制器的方法

Route::get('article/index', 'ArticleController@index');
Route::get('article/create', 'ArticleController@create');
Route::post('article/store', 'ArticleController@store');


可以在控制器中写点内容;

访问定义的路由就可以看到内容了;

一切都是这么的完美;
但是如果你和我一样帅;
额;不是;
如果你和我一样懒且善于总结思考;
你会发现这三条路由都是以 article/ 为前缀的;
在路由中我们应该怎么减少这种重复呢?
这就是我们接着要讲的分组的概念;
路由组就是把一些有相同特性的路由放在一个组里面;
我们先来定义一个前缀路由组;
上面这3条路由就可以改造成这个样子了;

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

随着项目的扩大;
如果控制器都直接放在 app/Http/Controllers 目录下的话;
那维护起来也开始略头疼了;
于是就可以为控制器分目录存放了;
比如说我要建一个 app/Http/Controllers/Admin/ArticleController.php;
再建一个 app/Http/Controllers/Home/ArticleController.php ;
命令行也是可以加目录的;

php artisan make:controller Admin/ArticleController --resource
php artisan make:controller Home/ArticleController --resource

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

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

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

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

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

访问起来就是这样的了;

因为 Admin 目录下我们还会创建更多的路由器;
所以;我们应该使用 group 嵌套的这种方式;
比如说我们再有一个 app/Http/Controllers/Home/TagController.php;
那路由就是这样的了;

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

除了文档上讲的这种方式;
其实以前版本的 laravel 还有另一种定义路由组的方式;

Route::group(['prefix'=>'admin', 'namespace'=>'Admin'], function () {
    Route::group(['prefix'=>'article'], function () {
        Route::get('index', 'ArticleController@index');
        Route::get('create', 'ArticleController@create');
        Route::post('store', 'ArticleController@store');
    });
});

就是把 prefix 和 namespace 这些都作为 group 方法的第一个参数;
不过现在不推荐这种写法了;
不过因为很多以前的项目都是这样写的;
这里讲一下让童鞋们查看别人以前的项目的时候能理解而不迷茫;

到这里我们已经学会了如何组织多级目录了;
为了讲解的简单;
我们回到 app/Http/Controllers/ArticleController.php 文件接着往下看;
会发现命令行创建的控制器里面有个 edit 方法;

public function edit($id)
{
    //
}

edit 方法有个 $id 参数;
这个参数是干什么用的呢?
通过名字我们很容易就明白这是用来修改数据的;
id 一般又是数据库的自增字段;
那这就是要修改指定 id 的数据了;
但是这个 id 是哪传来的呢?
下面就到了讲解路由参数的时候了;
定义路由的时候我们是可以定义路由参数的;
我们接着上面的路由加一个 edit 的;

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

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

public function edit($id)
{
    return '地址栏传的参数是:'.$id;
}

携带着路由参数通过路由访问这个方法;

这里面有个容易栽跟头的地方;
就是控制器中的参数名跟路由参数名不是必须相同的;
也就是说我这样写也是可以的;

public function edit($a)
{
    return '地址栏传的参数是:'.$a;
}

一个路由参数的时候这倒不会觉得什么;
一旦定义多个路由参数的时候;
这个坑就真的坑了;

Route::prefix('article')->group(function () {
    // ...
    Route::get('edit/{id}/{name}', 'ArticleController@edit');
});

在控制器中获取路由参数的时候;

public function edit($name, $id)
{
    return 'id是:' . $id . '<br>name是:' . $name;
}

访问 http://bjyblog.test/article/edit/666a/白俊遥
在你以为闭着眼都知道结果的时候;
一只硕大的幺蛾子飞了过来;

你发现 id 和 name 没对上;
该敲黑板画重点了筒子们;
路由参数中的第一个参数对应控制器中的第一个路由参数;
以此类推;
在控制器中路由参数跟参数名是没关系的;
只跟顺序有关;

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

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

这样就只能传数字了;
其实大多的表都是用 id 做主键的;
如果每个路由都手动定义一遍约束;
那也是挺麻烦的;
laravel 又一次方方面面都为我们考虑到了;
找到 app/Providers/RouteServiceProvider.php 这个文件;
在 boot 方法中可以定义全局约束;

public function boot()
{
    Route::pattern('id', '[0-9]+');

    parent::boot();
}

这样就不需要为每条带 id 参数的路由定义约束了;
以后所有带 id 参数的路由就只能传数字了;
不懂这个 RouteServiceProvider 的话没关系不要纠结在这;
就先当是固定用法;
以后慢慢懂;

跟路由参数容易搞混的是请求参数;
路由参数?请求参数?傻傻分不清楚;
举个栗子;

Route::prefix('article')->group(function () {
    // ...
    Route::get('edit/{id}/{name}', 'ArticleController@edit');
});

bjyblog.test/article/edit/666/白俊遥?music=越过山丘&book=平凡世界
id 和 name 就是路由参数;
music 和 book 就是请求参数;
路由参数的获取我们已经会了;
那请求参数怎么获取呢?
我们再回控制器中转悠转悠还会发现 update 方法;

public function update(Request $request, $id)
{
    //
}

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

    public function edit(Request $request, $id, $name)
    {
        $music = $request->input('music');
        $book = request()->input('book');
        $str = <<<php
id: $id <br>
name: $name <br>
music: $music <br>
book: $book <br>
php;
        return $str;
    }

这个 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 函数的升级版;
打印出来的效果是这样的;

如果想打印数据并 die 掉可以使用 dd() 函数;
如果只想从一大堆请求参数中获取指定的请求参数
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'));
    }

再次赞美 laravel 的体贴周到;

白俊遥博客
请先登录后发表评论
  • latest comments
  • 总共29条评论
白俊遥博客

张小宇 :白哥,laravel8 路由更新。   https://learnku.com/docs/laravel/8.x/releases/9351#d99737    这是原文,能更新一下吗?

2020-11-11 11:30:45 回复

白俊遥博客

zwsnail :request 和 route终于分清了哈哈

2020-02-16 18:00:04 回复

白俊遥博客

:不好意思重复问了, 在上一篇问过, 但在这篇里问好像更合适, 请问laravel6有没有不用注入Request的方式获取请求数据? 或者不在controller里取得个有效的实例化Request比如把Request封到自己的类里, 方便测试, Request还是好用的...想在其它地方(非controller里) 实例化一个有效的Request

2019-12-21 15:59:02 回复

白俊遥博客 白俊遥博客

云淡风晴 :可以用 request() 函数;比如说 request()->input('name') ;

2019-12-21 17:08:47 回复

白俊遥博客

:哦!~~原来还有个内置的helpers , 印象中不知道哪段文档说 某个版本后把helpers单独分了出来"laravel/helpers", 然后安装了发现只有arr_* 和 stt_* 就蒙了

2019-12-21 19:25:22 回复

白俊遥博客

:@云淡风晴 谢谢~~

2019-12-21 19:26:35 回复

白俊遥博客

建奇A :站在使用者角度来说,不得不承认老白很适合做老师,能通俗易懂简明扼要的 说出重点所在。而我看 learnku.com(原 laravel-china.org)上的付费教程就有点懵逼了, 一个CURD 3个HTML页面就能讲完的事,偏偏新建了快20个模板互相引入继承, 站在新手角度来说不明白为什么这样做,站在老鸟角度来说 啰里啰嗦 没有重点可言,而最重要的定义路由章节却一笔带过。

2019-03-30 18:51:23 回复

白俊遥博客 白俊遥博客

云淡风晴 :多谢认可;这个很多时候也看个人掌握的知识内容;可能我们比较相近哈; laravel-china 的课程是从实战的角度来写的;为了实现项目;可能会有一些重复的地方会让你感觉啰嗦;我这个系列教程是从知识点的角度来写的;一个一个知识点来讲;角度不一样吧;

2019-04-14 22:24:19 回复

白俊遥博客

追梦小窝 :啊飒飒

2018-12-29 13:58:45 回复

白俊遥博客

追梦小窝 :哈哈哈

2018-12-29 13:57:45 回复

白俊遥博客

追梦小窝 :阿达

2018-12-19 08:51:26 回复

白俊遥博客

伟大的PHP程序员 :11白俊遥博客

2018-12-17 14:30:48 回复

白俊遥博客

追梦小窝 :啊啊啊啊

2018-12-19 08:52:29 回复

白俊遥博客

追梦小窝 :去

2018-12-19 08:53:35 回复

白俊遥博客

追梦小窝 白俊遥博客

2018-12-29 13:59:45 回复

白俊遥博客

天青色等烟雨 :顶起,支持白大师!

2018-04-08 23:00:04 回复

白俊遥博客

用心 :报错method prefix does not exist. // Route::prefix('admin/article')->namespace('Admin')->group(function () {//     Route::get('index', 'ArticleController@index');//     Route::get('create', 'ArticleController@create');//     Route::post('store', 'ArticleController@store');// });

2018-03-20 17:29:40 回复

白俊遥博客 白俊遥博客

云淡风晴 :下载我的代码运行下看看: https://github.com/baijunyao/laravel-course

2018-03-31 19:39:50 回复

白俊遥博客

用心 :Route::group(['prefix' => 'admin','namespace'=>'Admin'],function () {    Route::group(['prefix' => 'article'],function () {        Route::get('index', 'ArticleController@index');        Route::get('create', 'ArticleController@create');        Route::post('store', 'ArticleController@store');    });});

2018-03-20 17:26:35 回复

白俊遥博客

点杠 :这篇文章得细细品味了,有TP5基础的会舒服点

2018-03-06 17:38:15 回复

白俊遥博客

木-微博 :首先感谢白先生写的这么详细的入门教程,另外就是不才在这篇里发现了一点小瑕疵:原文这里group 是可以嵌套的;那么上面这样的路由还可以改造下;---------------代码里是定义的Home下的路由,但是浏览器访问的却是Admin的控制器,小白可能会有点晕,不知是不是白先生故意挖的小坑,再次感谢您的教程,希望越做越有趣!白俊遥博客

2018-02-05 01:14:17 回复

白俊遥博客 白俊遥博客

云淡风晴 :多谢反馈;已经统一成admin了;

2018-03-04 22:54:18 回复

白俊遥博客

快乐远〖航〗 :3个月前用thinkphp5.0做了一个小项目。这节内容thinkphp的路由和laravel路由很像啊,路由这课学起来无压力。对了那个Request类两个框架也很像,不过laravel功能上更细更强大。

2018-01-29 21:13:01 回复

白俊遥博客

天之皓月 :顶起

2018-01-29 17:25:00 回复

白俊遥博客

null :顶起啊 666

2018-01-05 19:11:31 回复

白俊遥博客

Han-MeiM 白俊遥博客能不能只获取post参数或者get参数呀。

2018-01-04 21:20:36 回复

白俊遥博客 白俊遥博客

云淡风晴 :$request->query 获取的是 get 参数;$request->request 获取的是 post 参数;

2018-03-04 23:12:34 回复

白俊遥博客

微笑^_^ :看完了,厉害了我的哥

2018-01-01 18:02:49 回复

白俊遥博客

师丨爷 :我又来了,哈哈哈

2017-12-31 17:05:06 回复