资源控制器是 Laravel 内部的一种功能强大的约定,它约定了一系列对某一种资源进行“增删改查”操作的路由配置,让我们不再需要对每一项需要管理的资源都写 N 行重复形式的路由。中文文档见:https://d.laravel-china.org/docs/5.5/controllers#resource-controllers

我们只需要写一行简单的路由:

就可以得到下面 7 条路由配置:

左边是 HTTP 方法,中间是 URL 路径,右边是 控制器中对应的函数,只要某个请求符合这七行中某一行的要求,那么这条请求就会触发第三列的 function。这是 Laravel 对于 RESTful 的规范,它不仅仅帮我们省去了几行路由配置代码,更是如何合理规划 URL 的指路明灯,相信你会从中学到很多。

下面我们正式开始一项一项地实现 Article 的新增、编辑、删除功能:

开始行动

将当前路由配置中的 改成 Route::resource('articles', 'ArticleController');,哦了。注意,article 单数变成了复数。

修改之前写好的视图文件

由于从单数变成了复数,后台首页及文章列表页的视图文件里的链接也需要修改。

  • 修改 learnlaravel5/resources/views/admin/home.blade.php 中的 {{ url('admin/article') }} 为 {{ url('admin/articles') }}。
  • 修改 learnlaravel5/resources/views/admin/article/index.blade.php 中的 {{ url('admin/article/create') }} 为 {{ url('admin/articles/create') }};修改 {{ url('admin/article/'.$article->id.'/edit') }} 为 {{ url('admin/articles/'.$article->id.'/edit') }};修改 {{ url('admin/article/'.$article->id) }} 为 {{ url('admin/articles/'.$article->id) }}。

新增一篇文章需要两个动作:第一步,获取“新增Article”的页面;第二步,提交数据到后端,插入一篇文章到数据库。我们使用下图中红框内的两条路由规则来实现这两步操作:

2017 版 Laravel 系列入门教程(四)【最适合中国人的 Laravel 教程】 - 图2

获取“新增Article”的页面

第一个红框里告诉我们应该使用 /admin/articles/create 对应“新增Article”的页面,浏览器使用 GET 方法从服务器获取,对应的是 ArticleController 中的 create() 方法,下面我们手动新建这个方法:

  1. public function create()
  2. {
  3. return view('admin/article/create');
  4. }

新增视图文件 learnlaravel5/resources/views/admin/article/create.blade.php

  1. @extends('layouts.app')
  2.  
  3. @section('content')
  4. <div class="container">
  5. <div class="row">
  6. <div class="col-md-10 col-md-offset-1">
  7. <div class="panel panel-default">
  8. <div class="panel-body">
  9.  
  10. @if (count($errors) > 0)
  11. <div class="alert alert-danger">
  12. <strong>新增失败</strong> 输入不符合要求<br><br>
  13. {!! implode('<br>', $errors->all()) !!}
  14. </div>
  15. @endif
  16.  
  17. <form action="{{ url('admin/articles') }}" method="POST">
  18. {!! csrf_field() !!}
  19. <input type="text" name="title" class="form-control" required="required" placeholder="请输入标题">
  20. <br>
  21. <textarea name="body" rows="10" class="form-control" required="required" placeholder="请输入内容"></textarea>
  22. <br>
  23. <button class="btn btn-lg btn-info">新增文章</button>
  24. </form>
  25.  
  26. </div>
  27. </div>
  28. </div>
  29. </div>
  30. </div>
  31. @endsection

点击文章管理页面最上面的“新增”按钮,你将得到以下页面:

视图调用

view() 方法是 Laravel 中一个全局的方法,用于调用视图文件,他接受一个字符串参数,并会按照这个参数去调取对应的路由,这很容易理解。实际上 'admin/article/create''admin.article.create' 是等价的,而且看起来后者更加优雅,不过我个人更推荐前者。代码优雅是好事儿,不过本质上代码是写给人看的,一切提高代码理解成本的行为都是不可取的。

“新增Article”的页面已经展示出来,下一步就是提交数据到后端了,理解提交数据,要从 HTML 表单开始。

表单

视图文件中有一个表单:

这是一个非常普通的 HTML form(表单),只有两点需要我们费点心思去理解。

第一,表单的 action。form 是 HTML 规范,在点击了表单中的提交按钮后,浏览器会使用 method 属性的值(GET、POST等)将某些数据组装好发送给 action 的值(URL),这里我们动态生成了一个 URL 作为 action,并且指定了表单提交需要使用 POST 方法。

第二,csrf_field。这是 Laravel 中内置的应对 CSRF 攻击的防范措施,任何 POST PUT PATCH 请求都会被检测是否提交了 CSRF 字段。对应的代码为 learnlaravel5/app/Http/Kernel.php 里的 $middlewareGroups 属性里的 值。

{!! csrf_field() !!} 实际上会生成一个隐藏的 input:<input type="hidden" name="_token" value="GYZ8OHDAbZICMcEvcTiS82qlZs2XrELklpEl159S">

这一行也可以这么写:

  1. <input type="hidden" name="_token" value="{{ csrf_token() }}">

如果你的系统有很多的 Ajax,而你又不想降低安全性,这里的 csrf_token() 函数将会给你巨大的帮助。

后端接收数据

我们在页面中随便填入一些数据,点击提交按钮,这条请求会被分配到那里呢?

2017 版 Laravel 系列入门教程(四)【最适合中国人的 Laravel 教程】 - 图4

第二个红框告诉我们,应该向 admin/articles 以 POST 方法提交表单,其对应的是 store() 方法。现在我们新建 store 方法:

  1. public function store(Request $request)
  2. $this->validate($request, [
  3. 'title' => 'required|unique:articles|max:255',
  4. 'body' => 'required',
  5. ]);
  6.  
  7. $article = new Article;
  8. $article->title = $request->get('title');
  9. $article->body = $request->get('body');
  10. $article->user_id = $request->user()->id;
  11.  
  12. if ($article->save()) {
  13. return redirect('admin/articles');
  14. } else {
  15. return redirect()->back()->withInput()->withErrors('保存失败!');
  16. }
  17. }

检验成果

填入数据:

恭喜你,文章新增功能完成!

详细注释

下面我已注释的形式细细解析每一段代码的作用:

这两行路由配置可以满足我们的需求:

上面一行:展示“编辑某一篇文章”的表单;下面一行:上传数据并到数据库更新这篇文章。

这个就当做第二个小作业留给你们,尝试自己去构建吧这里面还有个小坑,参考我的代码就可以迅速地解决呦

删除某个资源跟新增、编辑相比最大的不同就是运行方式的不同:删除按钮看起来是一个独立的按钮,其实它是一个完整的表单,只不过只有这一个按钮暴露在页面上:

  1. <form action="{{ url('admin/articles/'.$article->id) }}" method="POST" style="display: inline;">
  2. {{ method_field('DELETE') }}
  3. {{ csrf_field() }}
  4. <button type="submit" class="btn btn-danger">删除</button>
  5. </form>

大家可能注意到了这句代码 {{ method_field('DELETE') }},这是什么意思呢?这是 Laravel 特有的请求处理系统的特殊约定。虽然 DELETE 方法在 RFC2616 中是可以携带 body 的(甚至 GET 方法都是可以携带的),但是由于历史的原因,不少 web server 软件都将 DELETE 方法和 GET 方法视作不可携带 body 的方法,有些 web server 软件会丢弃 body,有些干脆直接认为请求不合法拒绝接收。所以在这里,Laravel 的请求处理系统要求所有非 GET 和 POST 的请求全部通过 POST 请求来执行,再将真正的方法使用 _method 表单字段携带给后端。上面小作业中的小坑便是这个,PUT/PATCH 请求也要通过 POST 来执行。

在控制器中增加删除文章对应的是 destroy 方法:

  1. public function destroy($id)
  2. {
  3. Article::find($id)->delete();
  4. return redirect()->back()->withInput()->withErrors('删除成功!');
  5. }

点击删除按钮,检验效果:

恭喜你,文章新增、编辑、删除功能构建成功!

原文: https://github.com/johnlui/Learn-Laravel-5/issues/19