[TOC]
### **關注文檔→[進群一起學習提升吧](https://jq.qq.com/?_wv=1027&k=5dpB2jL)**
此篇是本系列教程的完結篇,我們將一起給 Article 加入評論功能,讓游客在前臺頁面可以查看、提交、回復評論,并完成后臺評論管理功能,可以刪除、編輯評論。Article 和評論將使用 Laravel Eloquent 提供的“一對多關系”功能大大簡化模型間關系的復雜度。最終,我們將得到一個個人博客系統的雛形,并布置一個大作業,供大家實戰練習。
本篇文章中我將會使用一些 Laravel 的高級功能,這些高級功能對新手理解系統是不利的,但熟手使用這些功能可以大幅提升開發效率。
## **回顧 Eloquent**
前面我們已經說過,Laravel Eloquent ORM 是 Laravel 中最強大的部分,也是 Laravel 能如此流行最重要的原因。
`learnlaravel5/app/Article.php`就是一個最簡單的 Eloquent Model 類:
~~~html
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
//
}
~~~
若想進一步了解 Eloquent 推薦閱讀公眾號系列文章:[深入理解 Laravel Eloquent](http://mp.weixin.qq.com/s?__biz=MzI0NjcxNDYzOQ==&mid=100000057&idx=1&sn=97ecaca16a6aba85ea269a41abb3fe70&chksm=69ba59595ecdd04f3a01e2851e0c580e490fe172e1618a745c0e8ee34f05796a025dda1dade0#rd)
## **構建評論系統**
### **基礎規劃**
我們需要新建一個表專門用來存放每一條評論,每一條評論都屬于某一篇文章。評論之間的層級關系比較復雜,本文為入門教程,主要是為了帶領大家體驗模型間關系,就不再做過多的規劃了,將“回復別人的評論”暫定為簡單的在評論內容前面增加[@johnlui](https://github.com/johnlui)這樣的字符串。
### **建立 Model 類和數據表**
創建名為 Comment 的 Model 類,并順便創建附帶的 migration,在 learnlaravel5 目錄下運行命令:
~~~shell
php artisan make:model Comment -m
~~~
這樣一次性建立了 Comment 類和`learnlaravel5/database/migrations/2017_11_11_151823_create_comments_table.php`兩個文件。填充該文件的 up 方法,給`comments`表增加字段:
~~~html
public function up()
{
Schema::create('comments', function (Blueprint $table) {
$table->increments('id');
$table->string('nickname');
$table->string('email')->nullable();
$table->string('website')->nullable();
$table->text('content')->nullable();
$table->integer('article_id');
$table->timestamps();
});
}
~~~
之后運行命令:
~~~shell
php artisan migrate
~~~
去數據庫里瞧瞧,comments 表已經躺在那兒啦。
### **建立“一對多關系”**
在 Article 模型中增加一對多關系的函數:
~~~html
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
public function hasManyComments()
{
return $this->hasMany('App\Comment', 'article_id', 'id');
}
}
~~~
搞定啦!Eloquent 中模型間關系就是這么簡單!
擴展閱讀:[深入理解 Laravel Eloquent(三)——模型間關系(關聯)](http://mp.weixin.qq.com/s?__biz=MzI0NjcxNDYzOQ==&mid=100000080&idx=1&sn=1f9a6048383038c59f88b138654c76af&chksm=69ba59305ecdd0260d12b45a8d743c4ac6517b72de9bd8cad17e27a661b17529f2597c593f5c#rd)
### **構建前臺 UI**
讓我們修改前臺的視圖文件,想辦法把評論功能加進去。
#### **創建前臺的 ArticleController 類**
運行命令:
~~~shell
php artisan make:controller ArticleController
~~~
增加路由:
~~~html
Route::get('article/{id}', 'ArticleController@show');
~~~
此處的 {id} 指代任意字符串,在我們的規劃中,此字段為文章 ID,為數字,但是本行路由卻會嘗試匹配所有請求,所以當你遇到了奇怪的路由調用的方法跟你想象的不一樣時,記得檢查路由順序。路由匹配方式為前置匹配:任何一條路由規則匹配成功,會立刻返回結果,后面的路由便沒有了響應的機會。
給 ArticleController 增加 show 函數:
~~~html
public function show($id)
{
return view('article/show')->withArticle(Article::with('hasManyComments')->find($id));
}
~~~
別忘了在頂部引入 Model 類,否則會報類找不到的錯誤:
~~~html
....
use App\Article;
class ArticleController extends Controller
{
....
~~~
#### **創建前臺文章展示視圖**
新建`learnlaravel5/resources/views/article/show.blade.php`文件:
~~~html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Learn Laravel 5</title>
<link href="//cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<script src="//cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>
<script src="//cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<div id="content" style="padding: 50px;">
<h4>
<a href="/"><< 返回首頁</a>
</h4>
<h1 style="text-align: center; margin-top: 50px;">{{ $article->title }}</h1>
<hr>
<div id="date" style="text-align: right;">
{{ $article->updated_at }}
</div>
<div id="content" style="margin: 20px;">
<p>
{{ $article->body }}
</p>
</div>
<div id="comments" style="margin-top: 50px;">
@if (count($errors) > 0)
<div class="alert alert-danger">
<strong>操作失敗</strong> 輸入不符合要求<br><br>
{!! implode('<br>', $errors->all()) !!}
</div>
@endif
<div id="new">
<form action="{{ url('comment') }}" method="POST">
{!! csrf_field() !!}
<input type="hidden" name="article_id" value="{{ $article->id }}">
<div class="form-group">
<label>Nickname</label>
<input type="text" name="nickname" class="form-control" style="width: 300px;" required="required">
</div>
<div class="form-group">
<label>Email address</label>
<input type="email" name="email" class="form-control" style="width: 300px;">
</div>
<div class="form-group">
<label>Home page</label>
<input type="text" name="website" class="form-control" style="width: 300px;">
</div>
<div class="form-group">
<label>Content</label>
<textarea name="content" id="newFormContent" class="form-control" rows="10" required="required"></textarea>
</div>
<button type="submit" class="btn btn-lg btn-success col-lg-12">Submit</button>
</form>
</div>
<script>
function reply(a) {
var nickname = a.parentNode.parentNode.firstChild.nextSibling.getAttribute('data');
var textArea = document.getElementById('newFormContent');
textArea.innerHTML = '@'+nickname+' ';
}
</script>
<div class="conmments" style="margin-top: 100px;">
@foreach ($article->hasManyComments as $comment)
<div class="one" style="border-top: solid 20px #efefef; padding: 5px 20px;">
<div class="nickname" data="{{ $comment->nickname }}">
@if ($comment->website)
<a href="{{ $comment->website }}">
<h3>{{ $comment->nickname }}</h3>
</a>
@else
<h3>{{ $comment->nickname }}</h3>
@endif
<h6>{{ $comment->created_at }}</h6>
</div>
<div class="content">
<p style="padding: 20px;">
{{ $comment->content }}
</p>
</div>
<div class="reply" style="text-align: right; padding: 5px;">
<a href="#new" onclick="reply(this);">回復</a>
</div>
</div>
@endforeach
</div>
</div>
</div>
</body>
</html>
~~~
### **構建評論存儲功能**
我們需要創建一個 CommentsController 控制器,并增加一條“存儲評論”的路由。運行命令:
~~~shell
php artisan make:controller CommentController
~~~
控制器創建成功,接下來我們增加一條路由:
~~~html
Route::post('comment', 'CommentController@store');
~~~
給這個類增加 store 函數:
~~~html
public function store(Request $request)
{
if (Comment::create($request->all())) {
return redirect()->back();
} else {
return redirect()->back()->withInput()->withErrors('評論發表失敗!');
}
}
~~~
此處 Comment 類請自己引入。
#### **批量賦值**
我們采用批量賦值方法來減少存儲評論的代碼。
給 Comment 類增加 $fillable 成員變量:
~~~html
protected $fillable = ['nickname', 'email', 'website', 'content', 'article_id'];
~~~
### **檢查成果**
前臺文章展示頁:
[](https://camo.githubusercontent.com/7ecafe98d5e9c477d745a90802f592f7f1e69927/687474703a2f2f716e2e6c7677656e68616e2e636f6d2f323031372d31312d31312d31353130333835343330393235362e6a7067)
提交幾條評論之后:
[](https://camo.githubusercontent.com/be0a020f3c437b293f8133d11895924210171cfe/687474703a2f2f716e2e6c7677656e68616e2e636f6d2f323031372d31312d31312d31353130333835353138303639392e6a7067)
恭喜你,前臺評論功能構建完成!
## **【大作業】構建后臺評論管理功能**
評論跟 Article 一樣,是一種可以管理的資源列表。2015 版教程的最后,我風風火火地羅列了一堆又一堆的代碼,其實對還沒入門的人幾乎沒用。在此,我將這個功能作為大作業布置給大家。大作業嘛,當然是沒有標準答案的,但有效果圖:
[](https://camo.githubusercontent.com/eeca8316c3fa044bb2e9d1b47291b6bd96fa0d6b/687474703a2f2f716e2e6c7677656e68616e2e636f6d2f323031362d30362d30332d31343634393636383832333234322e6a7067)
[](https://camo.githubusercontent.com/1f392d801eeb7e86700f7bf41e2b6459f536506e/687474703a2f2f716e2e6c7677656e68616e2e636f6d2f323031362d30362d30332d31343634393636383934343330342e6a7067)
在做這個大作業的過程中,你將會反復地回頭去看前面的教程,反復地閱讀中文文檔,會仔細閱讀我的代碼,等你完成大作業的時候,Laravel 就真正入門啦~~