本進階指南提供了對 Laravel 框架更深入的介紹,包括數(shù)據(jù)庫遷移、Eloquent ORM、路由、認證、授權、依賴注入、驗證、視圖以及 Blade 模板。如果你對 Laravel 框架或其他 PHP 框架已經有了基本的認識,本章節(jié)將是你新的起點,如果你完全還是新手,請從新手入門指南開始。
本節(jié)的示例仍然是構建一個任務系統(tǒng),但是在上一節(jié)基礎上,本任務系統(tǒng)將允許用戶注冊登錄,同樣完整的代碼已經放到 GitHub 上:https://github.com/laravel/quickstart-intermediate。
當然,首先你需要安裝一個新的 Laravel 應用。你可以使用 Homestead 虛擬機或者本地 PHP 開發(fā)環(huán)境來運行應用。開發(fā)環(huán)境準備完畢后,可以使用 Composer 來安裝應用:
composer create-project laravel/laravel quickstart --prefer-dist
你可以繼續(xù)往下閱讀,也可以選擇去 GitHub 下載項目源碼并在本地運行:
git clone https://github.com/laravel/quickstart-intermediate quickstart
cd quickstart
composer install
php artisan migrate
關于構建本地開發(fā)環(huán)境的詳細文檔可查看 Homestead 和安裝文檔。
首先,我們使用遷移來定于處理所有任務的數(shù)據(jù)庫。Laravel 的數(shù)據(jù)庫遷移使用平滑、優(yōu)雅的 PHP 代碼來提供一個簡單的方式定義和修改數(shù)據(jù)表結構。團隊成員們無需在本地數(shù)據(jù)庫手動添加或刪除列,只需要簡單運行你提交到源碼控制系統(tǒng)中的遷移即可。
由于我們允許用戶注冊,所以需要一張用來存儲用戶的表。幸運的是 Laravel 已經自帶了這個遷移用于創(chuàng)建基本的 users 表,我們不需要手動生成。該遷移文件默認位于 database/migrations
目錄下。
接下來,讓我們來創(chuàng)建用于處理所有任務的數(shù)據(jù)表 tasks
。我們使用 Artisan 命令 make:migration
來為 tasks
生成一個新的數(shù)據(jù)庫遷移:
php artisan make:migration create_tasks_table --create=tasks
生成的新遷移文件位于 database/migrations
目錄下。你可能已經注意到了,make:migration
命令已經在遷移文件中添加了自增 ID 和時間戳。我們將編輯該文件添加更多的字段到任務表 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->integer('user_id')->index();
$table->string('name');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('tasks');
}
}
其中,user_id
用于建立 tasks
表與 users
表之間的關聯(lián)。
要運行遷移,可以使用 migrate
命令。如果你使用的是 Homestead,需要在虛擬機中運行該命令,因為你的主機不能直接訪問 Homestead 上的數(shù)據(jù)庫:
php artisan migrate
該命令將會創(chuàng)建遷移中定義的尚未創(chuàng)建的所有數(shù)據(jù)表。如果你使用 MySQL 客戶端(如 Navicat For MySQL)查看數(shù)據(jù)表,你將會看到新的 users
表和 tasks
表。下一步,我們將要定義 Eloquent ORM模型。
Eloquent 是 Laravel 默認的 ORM,Eloquent 使用“模型”這一概念使得從數(shù)據(jù)庫存取數(shù)據(jù)變得輕松。通常,每個 Eloquent 模型都對應一張數(shù)據(jù)表。
首先,我們一個與 users 表相對應的模型 User。Laravel 已經自帶了這一模型 app/User,所以我們不需要重復創(chuàng)建了。
接下來,我們來定義與 tasks
表相對應的模型 Task。同樣,我們使用 Artisan 命令來生成模型類,在本例中,我們使用 make:model
命令:
php artisan make:model Task
該模型位于應用的 app
目錄下,默認情況下,該模型類是空的。我們不需要明確告訴 Eloquent 模型對應哪張表,Laravel 底層會有一個映射規(guī)則,這一點在之前 Eloquent 文檔已有說明,按照規(guī)則,這里 Task
模型默認對應 tasks
表。
接下來,讓我們在 Task
模型類中加一些代碼。首先,我們聲明模型上的 name 屬性支持“批量賦值”(關于批量賦值說明可查看這篇文章):
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Task extends Model{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['name'];
}
我們將在后續(xù)添加路由到應用中學習更多如何使用 Eloquent 模型。當然,你也可以先去查看完整的 Eloquent 文檔了解更多。
現(xiàn)在,模型已經定義好了,我們需要將它們關聯(lián)起來。例如,一個 User
實例對應多個 Task
實例,而一個 Task
實例從屬于某個 User
。定義關聯(lián)關系后將允許我們更方便的獲取關聯(lián)模型:
$user = App\User::find(1);
foreach ($user->tasks as $task) {
echo $task->name;
}
首先,我們在 User 模型中定義 tasks 關聯(lián)關系。Eloquent 關聯(lián)關系被定義成模型的方法,并且支持多種不同的關聯(lián)關系類型(查看完整的 Eloquent 關聯(lián)關系文檔了解更多)。在本例中,我們將會在 User 模型中定義 tasks 方法并在其中調用 Eloquent 提供的 hasMany 方法:
<?php
namespace App;
// Namespace Imports...
class User extends Model implements AuthenticatableContract,
AuthorizableContract,CanResetPasswordContract
{
use Authenticatable, Authorizable, CanResetPassword;
// Other Eloquent Properties...
/**
* Get all of the tasks for the user.
*/
public function tasks()
{
return $this->hasMany(Task::class);
}
}
接下來,我們會在 Task
模型中定義 user
關聯(lián)關系。同樣,我們將其定義為模型的方法。在本例中,我們使用 Eloquent 提供的 belongsTo
方法來定義該關聯(lián)關系:
<?php
namespace App;
use App\User;
use Illuminate\Database\Eloquent\Model;
class Task extends Model{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['name'];
/**
* Get the user that owns the task.
*/
public function user()
{
return $this->belongsTo(User::class);
}
}
好極了!現(xiàn)在我們已經定義好了關聯(lián)關系,接下來可以正式開始創(chuàng)建控制器了!
在新手入門指南創(chuàng)建的任務管理系統(tǒng)中,我們在 routes.php
中使用閉包定義所有的業(yè)務邏輯。而實際上,大部分應用都會使用控制器來組織路由。
我們還保留一個路由使用閉包:/路由,該路由是用于展示給游客的引導頁,我們將在該路由中渲染歡迎頁面。
在 Laravel 中,所有的 HTML 模板都位于 resources/views
目錄,并且我們使用 view
函數(shù)從路由中返回其中一個模板:
Route::get('/', function () {
return view('welcome');
});
當然,我們需要創(chuàng)建這個視圖,稍后就會。
此外,我們還要讓用戶注冊并登錄到應用。通常,在 web 應用中構建整個登錄認證層是一件相當冗長乏味的工作,然而,由于它是一個如此通用的需求,Laravel 試圖將這一過程變得簡單而輕松。
首先,注意到新安裝的 Laravel 應用中已經包含了 app/Http/Controllers/AuthController
這個控制器,該控制器中使用了一個特殊的 AuthenticatesAndRegistersUsers
trait,而這個 trait 中包含了用戶注冊登錄的所必須的相關邏輯。
那么接下來我們該怎么做呢?我們仍然需要創(chuàng)建注冊和登錄模板并定義指向認證控制器 AuthController
的路由。首先,添加我們需要的路由到 app/Http/routes.php
文件:
// Authentication Routes...
Route::get('auth/login', 'Auth\AuthController@getLogin');
Route::post('auth/login', 'Auth\AuthController@postLogin');
Route::get('auth/logout', 'Auth\AuthController@getLogout');
// Registration Routes...
Route::get('auth/register', 'Auth\AuthController@getRegister');
Route::post('auth/register', 'Auth\AuthController@postRegister');
完成認證還需要我們在 resources/views/auth
目錄下創(chuàng)建 login.blade.php
和 register.blade.php
,當然,這些個頁面的設計和樣式并不重要,只是需要包含一些基本的字段即可。
register.blade.php
文件需要一個包含 name
、email
、password
和 password_confirmation
字段的表單,該表單請求方式為 POST
,請求頁面路由為/auth/register
。
login.blade.php
文件應該需要一個包含 email
和 password
字段的表單,該表單請求方式為 POST
,請求頁面路由為/auth/login
。
注:如果你想要查看這些視圖的完整示例,可以去下載相應的 GitHub 項目:https://github.com/laravel/quickstart-intermediate
由于我們需要獲取和保存任務,所以還需要使用 Artisan 命令創(chuàng)建一個 TaskController
,生成的控制器位于 app/Http/Controllers
目錄:
php artisan make:controller TaskController --plain
現(xiàn)在這個控制器已經生成了,讓我們去 app/Http/routes.php
中定義一些指向該控制器的路由吧:
Route::get('/tasks', 'TaskController@index');
Route::post('/task', 'TaskController@store');
Route::delete('/task/{task}', 'TaskController@destroy');
對本應用而言,我們想要所有任務需要登錄用戶才能訪問,換句話說,用戶必須登錄到系統(tǒng)才能創(chuàng)建新任務。所以,我們需要限制訪問任務路由的用戶為登錄用戶。Laravel 使用中間件來處理這種限制。
如果要限制登錄用戶才能訪問該控制器的所有動作,可以在控制器的構造函數(shù)中添加對 middleware
方法的調用。所有有效的路由中間件都定義在 app/Http/Kernel.php 文件中。在本例中,我們想要定義一個 auth
中間件到 TaskController
上的所有動作:
<?php
namespace App\Http\Controllers;
use App\Http\Requests;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class TaskController extends Controller{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
}
本應用仍然只有一個視圖,該視圖包含了用于添加新任務的表單和顯示已存在任務的列表。為了讓你更直觀的查看該視圖,我們將已完成的應用截圖如下:
http://wiki.jikexueyuan.com/project/laravel-5.1/images/basic-overview.png" alt="" />
幾乎所有的 web 應用都會在不同界面共享同一布局,例如,本應用頂部的導航條將會在每個頁面顯示。Laravel 使用 Blade 讓不同頁面共享這些公共特性變得簡單。
正如我們之前討論的,所有 Laravel 視圖都存放在 resources/views
中,因此,我們在 resources/views/layouts/app.blade.php
中定義一個新的布局視圖,.blade.php
擴展表明框架使用 Blade 模板引擎來渲染視圖,當然,你可以使用原生的 PHP 模板,然而,Blade 提供了的標簽語法可以幫助我們編寫更加清爽、簡短的模板。
編輯 app.blade.php 內容如下:
// resources/views/layouts/app.blade.php
<!DOCTYPE html><html lang="en">
<head>
<title>Laravel Quickstart - Advanced</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 指令,用于指定繼承布局的子頁面在這里可以注入自己的內容。接下來,我們來定義使用該布局的子視圖來提供主體內容。
好了,我們已經創(chuàng)建了應用的布局視圖,下面我們需要定義一個包含創(chuàng)建新任務的表單和已存在任務列表的視圖,該視圖文件存放在 resources/views/tasks.blade.php
,對應 TaskController
中的 index
方法。
我們將跳過 Bootstrap CSS 的樣板文件而只專注在我們所關注的事情上,不要忘了,你可以從 GitHub 下載本應用的所有資源:
// 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ù)往下之前,讓我們簡單談談這個模板。首先,我們使用@extends
指令告訴 Blade 我們要使用定義在 resources/views/layouts/app.blade.php
的布局,所有@section('content')
和@endsection
之間的內容將會被注入到 app.blade.php
布局的@yield('contents')
指令位置。
現(xiàn)在,我們已經為應用定義了基本的布局和視圖,然后我們回到 TaskController
的 index
方法:
/**
* Display a list of all of the user's task.
*
* @param Request $request
* @return Response
*/
public function index(Request $request){
return view('tasks.index');
}
接下來,讓我們繼續(xù)添加代碼到 POST /task
路由的控制器方法來處理表單輸入并添加新任務到數(shù)據(jù)庫。
注:@include('common.errors')
指令將會加載 resources/views/common/errors.blade.php
模板中的內容,我們還沒有定義這個模板,但很快就會了!
現(xiàn)在我們已經在視圖中定義了表單,接下來需要編寫代碼到 TaskController@store
方法來處理表單請求并創(chuàng)建一個新任務。
對這個表單而言,我們將 name
字段設置為必填項,而且長度不能超過255個字符。如果表單驗證失敗,將會跳轉到/tasks
頁面,并且將錯誤信息存放到一次性 session 中:
/**
* Create a new task.
*
* @param Request $request
* @return Response
*/
public function store(Request $request){
$this->validate($request, [
'name' => 'required|max:255',
]);
// Create The Task...
}
如果你已經看過新手入門教程,那么你可能會注意到這里的驗證代碼與之前大不相同,這是因為我們現(xiàn)在在控制器中,可以方便地調用 ValidatesRequests
trait(包含在 Laravel 控制器基類中)提供的 validate
方法。
我們甚至不需要手動判讀是否驗證失敗然后重定向。如果驗證失敗,用戶會自動被重定向到來源頁面,而且錯誤信息也會被存放到一次性 Session 中。簡直太棒了,有木有!
$errors
變量我們在視圖中使用了@include('common.errors')
指令來渲染表單驗證錯誤信息,common.errors
允許我們在所有頁面以統(tǒng)一格式顯示錯誤信息。我們定義 common.errors
內容如下:
// 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
實例。
現(xiàn)在輸入驗證已經做好了,接下來正式開始創(chuàng)建一個新任務。一旦新任務創(chuàng)建成功,頁面會跳轉到/ tasks
。要創(chuàng)建任務,可以借助 Eloquent 模型的關聯(lián)關系。
大部分 Laravel 的關聯(lián)關系提供了 save
方法,該方法接收一個關聯(lián)模型實例并且會在保存到數(shù)據(jù)庫之前自動設置外鍵值到關聯(lián)模型上。在本例中,save
方法會自動將當前用戶登錄認證用戶的 ID 賦給給給定任務的 user_id
屬性。我們通過$request->user()
獲取當前登錄用戶實例:
/**
* Create a new task.
*
* @param Request $request
* @return Response
*/
public function store(Request $request){
$this->validate($request, [
'name' => 'required|max:255',
]);
$request->user()->tasks()->create([
'name' => $request->name,
]);
return redirect('/tasks');
}
很好,到了這里,我們已經可以成功創(chuàng)建任務,接下來,我們繼續(xù)添加代碼到視圖來顯示所有任務列表。
首先,我們需要編輯 TaskController@index
傳遞所有已存在任務到視圖。view
函數(shù)接收一個數(shù)組作為第二個參數(shù),我們可以將數(shù)據(jù)通過該數(shù)組傳遞到視圖中:
/**
* Display a list of all of the user's task.
*
* @param Request $request
* @return Response
*/
public function index(Request $request){
$tasks = Task::where('user_id', $request->user()->id)->get();
return view('tasks.index', [
'tasks' => $tasks,
]);
}
這里,我們還要講講 Laravel 的依賴注入,這里我們將 TaskRepository
注入到 TaskController
,以方便對 Task
模型所有數(shù)據(jù)的訪問和使用。
Laravel 的服務容器是整個框架中最重要的特性,在看完快速入門教程后,建議去研習下服務容器的文檔。
正如我們之前提到的,我們想要定義一個 TaskRepository
來處理所有對 Task
模型的數(shù)據(jù)訪問,隨著應用的增長當你需要在應用中共享一些 Eloquent 查詢時這就變得特別有用。
因此,我們創(chuàng)建一個 app/Repositories
目錄并在其中創(chuàng)建一個 TaskRepository
類。記住,Laravel 項目的 app
文件夾下的所有目錄都使用 PSR-4 自動加載標準被自動加載,所以你可以在其中隨心所欲地創(chuàng)建需要的目錄:
<?php
namespace App\Repositories;
use App\User;
use App\Task;
class TaskRepository{
/**
* Get all of the tasks for a given user.
*
* @param User $user
* @return Collection
*/
public function forUser(User $user)
{
return Task::where('user_id', $user->id)
->orderBy('created_at', 'asc')
->get();
}
}
Repository 創(chuàng)建好了之后,可以簡單通過在 TaskController
的構造函數(shù)中以類型提示的方式注入該 Repository,然后就可以在 index
方法中使用 —— 由于 Laravel 使用容器來解析所有控制器,所以我們的依賴會被自動注入到控制器實例:
<?php
namespace App\Http\Controllers;
use App\Task;use App\Http\Requests;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Repositories\TaskRepository;
class TaskController extends Controller{
/**
* The task repository instance.
*
* @var TaskRepository
*/
protected $tasks;
/**
* Create a new controller instance.
*
* @param TaskRepository $tasks
* @return void
*/
public function __construct(TaskRepository $tasks)
{
$this->middleware('auth');
$this->tasks = $tasks;
}
/**
* Display a list of all of the user's task.
*
* @param Request $request
* @return Response
*/
public function index(Request $request)
{
return view('tasks.index', [
'tasks' => $this->tasks->forUser($request->user()),
]);
}
}
數(shù)據(jù)被傳遞到視圖后,我們可以在 tasks/index.blade.php
中以表格形式顯示所有任務。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
至此,本應用基本完成。但是,當任務完成時我們還沒有途徑刪除該任務,接下來我們就來處理這件事。
我們在 tasks/index.blade.php
視圖中留了一個“TODO”注釋用于放置刪除按鈕。當刪除按鈕被點擊時,DELETE /task
請求被發(fā)送到應用后臺并觸發(fā) TaskController@destroy
方法:
<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 識別出該輸入并使用其值覆蓋實際的 HTTP 請求方法。生成的輸入框如下:
<input type="hidden" name="_method" value="DELETE">
現(xiàn)在,我們準備在 TaskController
中定義 destroy
方法,但是,在此之前,讓我們回顧下路由中對刪除任務的定義:
Route::delete('/task/{task}', 'TaskController@destroy');
在沒有添加任何額外代碼的情況下,Laravel 會自動注入給定任務 ID 到 TaskController@destroy
,就像這樣:
/**
* Destroy the given task.
*
* @param Request $request
* @param string $taskId
* @return Response
*/
public function destroy(Request $request, $taskId){
//
}
然而,在這個方法中首當其沖需要處理的就是通過給定 ID 從數(shù)據(jù)庫中獲取對應的 Task
實例,因此,如果 Laravel 能夠從一開始注入與給定 ID 匹配的 Task
實例豈不是很好?下面就讓我們來實現(xiàn)這個!
在 app/Providers/RouteServiceProvider.php
文件的 boot
方法中,我們添加如下這行代碼:
$router->model('task', 'App\Task');
這一小行代碼將會告知 Laravel 一旦在路由聲明中找到{task}
,就會獲取與給定 ID 匹配的 Task
模型?,F(xiàn)在我們可以像這樣定義 destroy
方法:
/**
* Destroy the given task.
*
* @param Request $request
* @param Task $task
* @return Response
*/
public function destroy(Request $request, Task $task){
//
}
現(xiàn)在,我們已經將 Task
實例注入到 destroy
方法;然而,我們并不能保證當前登錄認證用戶是給定任務的實際擁有人。例如,一些惡意請求可能嘗試通過傳遞隨機任務 ID 到/tasks/{task}
鏈接刪除另一個用戶的任務。因此,我們需要使用 Laravel 的授權功能來確保當前登錄用戶擁有對注入到路由中的 Task
實例進行刪除的權限。
Laravel 使用“策略”來將授權邏輯組織到單個類中,通常,每個策略都對應一個模型,因此,讓我們使用 Artisan 命令創(chuàng)建一個 TaskPolicy
,生成的文件位于 app/Policies/TaskPolicy.php
:
php artisan make:policy TaskPolicy
接下來,讓我們添加 destroy
方法到策略中,該方法會獲取一個 User
實例和一個 Task
實例。該方法簡單檢查用戶 ID 和任務的 user_id
值是否相等。實際上,所有的策略方法都會返回 true
或 false
:
<?php
namespace App\Policies;
use App\User;
use App\Task;
use Illuminate\Auth\Access\HandlesAuthorization;
class TaskPolicy{
use HandlesAuthorization;
/**
* Determine if the given user can delete the given task.
*
* @param User $user
* @param Task $task
* @return bool
*/
public function destroy(User $user, Task $task)
{
return $user->id === $task->user_id;
}
}
最后,我們需要關聯(lián) Task
模型和 TaskPolicy
,這可以通過在 app/Providers/AuthServiceProvider.php
文件的 policies
屬性中添加注冊來實現(xiàn),注冊后會告知 Laravel 無論何時我們嘗試授權動作到 Task
實例時該使用哪個策略類進行判斷:
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
'App\Task' => 'App\Policies\TaskPolicy',
];
現(xiàn)在我們編寫好了策略,讓我們在 destroy
方法中使用它。所有的 Laravel 控制器中都可以調用 authorize
方法,該方法由 AuthorizesRequest
trait 提供:
/**
* Destroy the given task.
*
* @param Request $request
* @param Task $task
* @return Response
*/
public function destroy(Request $request, Task $task){
$this->authorize('destroy', $task);
// Delete The Task...
}
我們可以檢查下該方法調用:傳遞給 authorize
方法的第一個參數(shù)是我們想要調用的策略方法名,第二個參數(shù)是當前操作的模型實例。由于我們在之前告訴過 Laravel,Task
模型對應的策略類是 TaskPolicy
,所以框架知道觸發(fā)哪個策略類上的 destroy
方法。當前用戶實例會被自動傳遞到策略方法,所以我們不需要手動傳遞。
如果授權成功,代碼會繼續(xù)執(zhí)行。如果授權失敗,會拋出一個403異常并顯示一個錯誤頁面給用戶。
注:除此之外,Laravel 還提供了其它授權服務實現(xiàn)方式,可以查看授權文檔了解更多。
最后,讓我們添加業(yè)務邏輯到路由中執(zhí)行刪除操作,我們可以使用 Eloquent 提供的 delete
方法從數(shù)據(jù)庫中刪除給定的模型實例。記錄被刪除后,跳轉到/tasks
頁面:
/**
* Destroy the given task.
*
* @param Request $request
* @param Task $task
* @return Response
*/
public function destroy(Request $request, Task $task){
$this->authorize('destroy', $task);
$task->delete();
return redirect('/tasks');
}