引言:Laravel 官方終于推出5.1版本快速入門指南了,學(xué)院君在 reddit 上看到大家的討論后才得知這一消息,立即著手進(jìn)行了翻譯,希望對 Laravel 學(xué)習(xí)者有所幫助。
快速入門指南會對 Laravel 框架做一個基本介紹,包括數(shù)據(jù)庫遷移、Eloquent ORM、路由、驗(yàn)證、視圖以及 Blade 模板等等。如果你是個 Laravel 新手甚至之前對 PHP 框架也很陌生,那么這里將會成為你的良好起點(diǎn)。如果你已經(jīng)使用過 Laravel 獲取其它 PHP 框架,可以考慮跳轉(zhuǎn)到進(jìn)階指南(翻譯中)。
為了演示 Laravel 特性的基本使用,我們將將會構(gòu)建一個簡單的、用于追蹤所有要完成任務(wù)的任務(wù)列表(To-Do List),本教程完整的代碼已經(jīng)公開在 Github 上:https://github.com/laravel/quickstart-basic。
當(dāng)然,開始之前你首先要做的是安裝一個新的 Laravel 應(yīng)用。你可以使用 Homestead 虛擬機(jī)或者本地 PHP 開發(fā)環(huán)境來運(yùn)行應(yīng)用。設(shè)置好開發(fā)環(huán)境后,可以使用如下 Composer 命令安裝應(yīng)用:
composer create-project laravel/laravel quickstart --prefer-dist
當(dāng)然你還可以通過克隆 GitHub 倉庫到本地來安裝:
git clone https://github.com/laravel/quickstart-basic quickstart
cd quickstart
composer install
php artisan migrate
如果你還不了解如何構(gòu)建本地開發(fā)環(huán)境,可參考 Homestead 和安裝文檔。
首先,讓我們使用遷移來定義數(shù)據(jù)表用于處理所有任務(wù)。Laravel 的數(shù)據(jù)庫遷移特性提供了一個簡單的方式來對數(shù)據(jù)表結(jié)構(gòu)進(jìn)行定義和修改:不需要讓團(tuán)隊(duì)的每個成員添加列到本地數(shù)據(jù)庫,只需要簡單運(yùn)行你提交到源碼控制中的遷移即可實(shí)現(xiàn)數(shù)據(jù)表創(chuàng)建及修改。
那么,讓我們來創(chuàng)建這個處理所有任務(wù)的數(shù)據(jù)表吧。Artisan 命令可以用來生成多種類從而節(jié)省重復(fù)的勞動,在本例中,我們使用 make:migration
命令生成 tasks
對應(yīng)的數(shù)據(jù)表遷移:
php artisan make:migration create_tasks_table --create=tasks
該命令生成的遷移文件位于項(xiàng)目根目錄下的 database/migrations
目錄,可能你已經(jīng)注意到了,make:migration
命令已經(jīng)在遷移文件中為我們添加了自增 ID 和時間戳,接下來我們要編輯該文件添加更多的列到數(shù)據(jù)表 tasks
:
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTasksTable extends Migration{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('tasks', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('tasks');
}
}
要運(yùn)行遷移,可以使用 Artisan 命令 migrate
。如果你使用的是 Homestead,應(yīng)該在虛擬機(jī)中運(yùn)行該命令:
php artisan migrate
該命令會為我們創(chuàng)建遷移文件中定義的所有數(shù)據(jù)表,如果你使用數(shù)據(jù)庫客戶端軟件查看數(shù)據(jù)庫,可以看到已經(jīng)創(chuàng)建了一個新的 tasks
表,其中包含了我們在遷移中定義的列。接下來,我們準(zhǔn)備為這個數(shù)據(jù)表定義一個 Eloquent ORM 模型。
Laravel 使用的默認(rèn) ORM 是 Eloquent,Eloquent 使用模型讓數(shù)據(jù)存取變得簡單和輕松,通常,每一個 Eloquent 模型都有一個與之對應(yīng)的數(shù)據(jù)表。
所以我們要定義一個與剛剛創(chuàng)建的 tasks
表對應(yīng)的 Task
模型,同樣我們使用 Artisan 命令來生成這個模型:
php artisan make:model Task
該模型類位于 app
目錄下,默認(rèn)情況下,模型類是空的,我們不需要告訴該 Eloquent 模型對應(yīng)哪張數(shù)據(jù)表,這一點(diǎn)我們在 Eloquent 文檔中提及過,這里默認(rèn)對應(yīng)的數(shù)據(jù)表是 tasks
,下面是這個空的模型類:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Task extends Model{
//
}
了解更多關(guān)于 Eloquent 模型類的細(xì)節(jié),可查看完整的 Eloquent 文檔。
下面我們需要為應(yīng)用定義一些路由,路由的作用是在用戶訪問指定頁面時將頁面URL匹配到被執(zhí)行的控制器或匿名函數(shù)。默認(rèn)情況下,所有的 Laravel 路由都定義在 app/Http/routes.php
。
在本應(yīng)用中,我們需要至少三個路由:顯示所有任務(wù)的路由,添加新任務(wù)的路由,以及刪除已存在任務(wù)的路由。接下來,讓我們在 app/Http/routes.php
文件中創(chuàng)建這三個路由:
<?php
use App\Task;
use Illuminate\Http\Request;
/**
* Display All Tasks
*/
Route::get('/', function () {
//
});
/**
* Add A New Task
*/
Route::post('/task', function (Request $request) {
//
});
/**
* Delete An Existing Task
*/
Route::delete('/task/{id}', function ($id) {
//
});
接下來,我們來填充/路由,在這個路由中,我們要渲染一個 HTML 模板,該模板包含添加新任務(wù)的表單,以及顯示任務(wù)列表。
在 Laravel 中,所有的 HTML 模板都存放在 resources/views
目錄下,我們可以使用 view
函數(shù)從路由中返回其中一個模板:
Route::get('/', function () {
return view('tasks');
});
當(dāng)然,接下來我們需要去創(chuàng)建這個視圖。
本應(yīng)用為了簡單處理只包含一個視圖,其中包含了添加新任務(wù)的表單和所有任務(wù)的列表。為了讓大家有一個直觀的視覺效果,我們貼出該視圖的截圖,可以看到我們在視圖中使用了基本的 Bootstrap CSS 樣式:
http://wiki.jikexueyuan.com/project/laravel-5.1/images/basic-overview.png" alt="" />
幾乎所有的 web 應(yīng)用都是在不同頁面中共享同一個布局,例如,本應(yīng)用在視圖頂部有一個導(dǎo)航條,該導(dǎo)航條在每個頁面都會出現(xiàn)。Laravel 通過在每個頁面中使用 Blade 布局讓共享這些公共特性變得簡單。
正如我們之前討論的,所有 Laravel 視圖都存放在 resources/views
中,因此,我們在 resources/views/layouts/app.blade.php
中定義一個新的布局視圖,.blade.php
擴(kuò)展表明框架使用 Blade 模板引擎來渲染視圖,當(dāng)然,你可以使用原生的 PHP 模板,然而,Blade 提供了的標(biāo)簽語法可以幫助我們編寫更加清爽、簡短的模板。
編輯 app.blade.php
內(nèi)容如下:
// resources/views/layouts/app.blade.php
<!DOCTYPE html><html lang="en">
<head>
<title>Laravel Quickstart - Basic</title>
<!-- CSS And JavaScript -->
</head>
<body>
<div class="container">
<nav class="navbar navbar-default">
<!-- Navbar Contents -->
</nav>
</div>
@yield('content')
</body>
</html>
注意布局中的 @yield('content')
部分,這是一個 Blade 指令,用于指定繼承布局的子頁面在這里可以注入自己的內(nèi)容。接下來,我們來定義使用該布局的子視圖來提供主體內(nèi)容。
好了,我們已經(jīng)創(chuàng)建了應(yīng)用的布局視圖,下面我們需要定義一個包含創(chuàng)建新任務(wù)的表單和已存在任務(wù)列表的視圖,該視圖文件存放在 resources/views/tasks.blade.php
。
我們將跳過 Bootstrap CSS 的樣板文件而只專注在我們所關(guān)注的事情上,不要忘了,你可以從 GitHub 下載本應(yīng)用的所有資源:
// resources/views/tasks.blade.php
@extends('layouts.app')
@section('content')
<!-- Bootstrap Boilerplate... -->
<div class="panel-body">
<!-- Display Validation Errors -->
@include('common.errors')
<!-- New Task Form -->
<form action="/task" method="POST" class="form-horizontal">
{{ csrf_field() }}
<!-- Task Name -->
<div class="form-group">
<label for="task" class="col-sm-3 control-label">Task</label>
<div class="col-sm-6">
<input type="text" name="name" id="task-name" class="form-control">
</div>
</div>
<!-- Add Task Button -->
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6">
<button type="submit" class="btn btn-default">
<i class="fa fa-plus"></i> Add Task
</button>
</div>
</div>
</form>
</div>
<!-- TODO: Current Tasks -->
@endsection
在繼續(xù)往下之前,讓我們簡單談?wù)勥@個模板。首先,我們使用 @extends
指令告訴 Blade 我們要使用定義在 resources/views/layouts/app.blade.php
的布局,所有 @section('content')
和@endsection
之間的內(nèi)容將會被注入到 app.blade.php
布局的 @yield('contents')
指令位置。
現(xiàn)在,我們已經(jīng)為應(yīng)用定義了基本的布局和視圖,接下來,我們準(zhǔn)備添加代碼到 POST /task
路由來處理添加新任務(wù)到數(shù)據(jù)庫。
注:@include('common.errors')
指令將會加載 resources/views/common/errors.blade.php
模板中的內(nèi)容,我們還沒有定義這個模板,但很快就會了!
現(xiàn)在我們已經(jīng)在視圖中定義了表單,接下來需要編寫代碼處理表單請求,我們需要驗(yàn)證表單輸入,然后才能創(chuàng)建一個新任務(wù)。
對這個表單而言,我們將 name
字段設(shè)置為必填項(xiàng),而且長度不能超過255個字符。如果表單驗(yàn)證失敗,將會跳轉(zhuǎn)到前一個頁面,并且將錯誤信息存放到一次性 session 中:
Route::post('/task', function (Request $request) {
$validator = Validator::make($request->all(), [
'name' => 'required|max:255',
]);
if ($validator->fails()) {
return redirect('/')
->withInput()
->withErrors($validator);
}
// Create The Task...
});
$errors
變量讓我們停下來討論下上述代碼中的->withErrors($validator)
部分,->withErrors($validator)
會將驗(yàn)證錯誤信息存放到一次性 session 中,以便在視圖中可以通過 $errors
變量訪問。
我們在視圖中使用了 @include('common.errors')
指令來渲染表單驗(yàn)證錯誤信息,common.errors
允許我們在所有頁面以統(tǒng)一格式顯示錯誤信息。我們定義 common.errors
內(nèi)容如下:
// resources/views/common/errors.blade.php
@if (count($errors) > 0)
<!-- Form Error List -->
<div class="alert alert-danger">
<strong>Whoops! Something went wrong!</strong>
<br><br>
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
注:$errors
變量在每個 Laravel 視圖中都可以訪問,如果沒有錯誤信息的話它就是一個空的 ViewErrorBag
實(shí)例。
現(xiàn)在輸入驗(yàn)證已經(jīng)做好了,接下來正式開始創(chuàng)建一個新任務(wù)。一旦新任務(wù)創(chuàng)建成功,頁面會跳轉(zhuǎn)到/
。要創(chuàng)建任務(wù),可以使用 Eloquent 模型提供的 use
方法:
Route::post('/task', function (Request $request) {
$validator = Validator::make($request->all(), [
'name' => 'required|max:255',
]);
if ($validator->fails()) {
return redirect('/')
->withInput()
->withErrors($validator);
}
$task = new Task;
$task->name = $request->name;
$task->save();
return redirect('/');
});
好了,到了這里,我們已經(jīng)可以成功創(chuàng)建任務(wù),接下來,我們繼續(xù)添加代碼到視圖來顯示所有任務(wù)列表。
首先,我們需要編輯/路由傳遞所有已存在任務(wù)到視圖。view
函數(shù)接收一個數(shù)組作為第二個參數(shù),我們可以將數(shù)據(jù)通過該數(shù)組傳遞到視圖中:
Route::get('/', function () {
$tasks = Task::orderBy('created_at', 'asc')->get();
return view('tasks', [
'tasks' => $tasks
]);
});
數(shù)據(jù)被傳遞到視圖后,我們可以在 tasks.blade.php
中以表格形式顯示所有任務(wù)。Blade 中使用@foreach
處理循環(huán)數(shù)據(jù):
@extends('layouts.app')
@section('content')
<!-- Create Task Form... -->
<!-- Current Tasks -->
@if (count($tasks) > 0)
<div class="panel panel-default">
<div class="panel-heading">
Current Tasks
</div>
<div class="panel-body">
<table class="table table-striped task-table">
<!-- Table Headings -->
<thead>
<th>Task</th>
<th> </th>
</thead>
<!-- Table Body -->
<tbody>
@foreach ($tasks as $task)
<tr>
<!-- Task Name -->
<td class="table-text">
<div>{{ $task->name }}</div>
</td>
<td>
<!-- TODO: Delete Button -->
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
@endif
@endsection
至此,本應(yīng)用基本完成。但是,當(dāng)任務(wù)完成時我們還沒有途徑刪除該任務(wù),接下來我們就來處理這件事。
我們在 tasks.blade.php
視圖中留了一個“TODO”注釋用于放置刪除按鈕。當(dāng)刪除按鈕被點(diǎn)擊時, DELETE /task
請求被發(fā)送到應(yīng)用后臺:
<tr>
<!-- Task Name -->
<td class="table-text">
<div>{{ $task->name }}</div>
</td>
<!-- Delete Button -->
<td>
<form action="/task/{{ $task->id }}" method="POST">
{{ csrf_field() }}
{{ method_field('DELETE') }}
<button>Delete Task</button>
</form>
</td>
</tr>
盡管我們使用的路由是 Route::delete
,但我們在刪除按鈕表單中使用的請求方法為 POST,HTML 表單只支持 GET
和 POST
兩種請求方式,因此我們需要使用某種方式來偽造 DELETE 請求。
我們可以在表單中通過輸出 method_field('DELETE')
來偽造 DELETE
請求,該函數(shù)生成一個隱藏的表單輸入框,然后 Laravel 識別出該輸入并使用其值覆蓋實(shí)際的 HTTP 請求方法。生成的輸入框如下:
<input type="hidden" name="_method" value="DELETE">
最后,讓我們添加業(yè)務(wù)邏輯到路由中執(zhí)行刪除操作,我們可以使用 Eloquent 提供的 findOrFail
方法從數(shù)據(jù)庫通過 ID 獲取模型實(shí)例,如果不存在則拋出404異常。獲取到模型后,我們使用模型的 delete
方法刪除該模型在數(shù)據(jù)庫中對應(yīng)的記錄。記錄被刪除后,跳轉(zhuǎn)到/
頁面:
Route::delete('/task/{id}', function ($id) {
Task::findOrFail($id)->delete();
return redirect('/');
});