介紹
不要把所有處理請(qǐng)求的邏輯都放到一個(gè)單獨(dú)的 routes.php
文件里,我們可以使用控制器去組織這些行為。Controller
可以把相關(guān)的處理 HTTP 請(qǐng)求的邏輯放到一個(gè)類里面。一般控制器都放在 app/Http/Controllers
這個(gè)目錄的下面:
app/Http/Controllers
├── Auth
│ ├── AuthController.php
│ └── PasswordController.php
├── Controller.php
├── HomeController.php
└── WelcomeController.php
1 directory, 5 files
基本控制器
定義控制器
下面是一個(gè)基本控制器類的例子。所有的 Laravel 控制器應(yīng)該繼承自 Laravel 自帶的控制器基類 Controller
,控制器基類提供了一些很方便的方法如 middleware
,用于添加中間件 到控制器動(dòng)作:
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
/**
* 為指定用戶顯示詳情
*
* @param int $id
* @return Response
*/
public function show($id)
{
return view(
'user.profile',
[
'user' => User::findOrFail($id)
]
);
}
}
我們可以像這樣定義指向該控制器動(dòng)作的路由:
Route::get('user/{id}', 'UserController@show');
這樣當(dāng)用戶請(qǐng)求訪問 user/{id}
這種類型的地址的時(shí)候,就會(huì)用 UserController 里面的 show
這個(gè)方法來處理這些請(qǐng)求。
注:控制器并不是一定要繼承自基類,不過,那樣的話就不能使用一些便利的方法了,比如
middleware
、validate
和dispatch
等。
控制器 & 命名空間
使用控制器的時(shí)候,不需要去指定控制器的全部命名空間,可以只用在 App\Http\Controllers
(根命名空間) 命名空間之后的部分。
默認(rèn)情況下,RouteServiceProvider
在載入 routes.php
文件的時(shí)候,會(huì)包含控制器 根命名空間。
如果你的完整控制器類 App\Http\Controllers\Photos\AdminController
,則可以像這樣注冊(cè)路由:
Route::get('foo', 'Photos\AdminController@method');
單動(dòng)作控制器
如果你想要定義一個(gè)只處理一個(gè)動(dòng)作的控制器,可以在這個(gè)控制器中定義 __invoke
方法:
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
class ShowProfile extends Controller
{
/**
* 顯示給定用戶的用戶資料
*
* @param int $id
* @return Response
*/
public function __invoke($id)
{
return view(
'user.profile',
[
'user' => User::findOrFail($id)
]
);
}
}
當(dāng)你為這個(gè)單動(dòng)作控制器注冊(cè)路由的時(shí)候,不需要指定方法:
Route::get('user/{id}', 'ShowProfile');
控制器中間件
中間件可以像這樣分配給控制器路由:
Route::get('profile', 'UserController@show')->middleware('auth');
但是,將中間件放在控制器構(gòu)造函數(shù)中更方便,在控制器的構(gòu)造函數(shù)中使用 middleware
方法你可以很輕松的分配中間件給該控制器。你甚至可以限定該中間件應(yīng)用到該控制器類的指定方法:
class UserController extends Controller
{
/**
* 實(shí)例化一個(gè)新的 UserController 實(shí)例
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('log')->only('index');
$this->middleware('subscribed')->except('store');
}
}
在控制器中還可以使用閉包注冊(cè)中間件,這為我們定義只在某個(gè)控制器使用的中間件提供了方便,無需定義完整的中間件類:
$this->middleware(function ($request, $next) {
// ...
return $next($request);
});
注:你還可以將中間件分配給多個(gè)控制器動(dòng)作,不過,這意味著你的控制器會(huì)變得越來越臃腫,這種情況下,需要考慮將控制器分割成多個(gè)更小的控制器。
資源控制器
Laravel 的資源控制器使得構(gòu)建圍繞資源的 RESTful 控制器變得毫無痛苦,例如,你可能想要在應(yīng)用中創(chuàng)建一個(gè)控制器,用于處理關(guān)于圖片存儲(chǔ)的 HTTP 請(qǐng)求,使用 Artisan
命令 make:controller
,我們可以快速創(chuàng)建這樣的控制器:
php artisan make:controller PhotoController --resource
該 Artisan
命令將會(huì)生成一個(gè)控制器文件 app/Http/Controllers/PhotoController.php
,這個(gè)控制器包含了每一個(gè)資源操作對(duì)應(yīng)的方法。
接下來,可以為該控制器注冊(cè)一個(gè)資源路由:
Route::resource('photos', 'PhotoController');
這個(gè)路由聲明包含了處理圖片資源 RESTful
動(dòng)作的多個(gè)路由,相應(yīng)地,Artisan
生成的控制器也已經(jīng)為這些動(dòng)作設(shè)置了對(duì)應(yīng)的處理方法。
資源控制器處理的動(dòng)作
方法 | 路徑 | 動(dòng)作 | 路由名稱 |
---|---|---|---|
GET | /photos |
index | photos.index |
GET | /photos/create |
create | photos.create |
POST | /photos |
store | photos.store |
GET | /photos/{photo} |
show | photos.show |
GET | /photos/{photo}/edit |
edit | photos.edit |
PUT/PATCH | /photos/{photo} |
update | photos.update |
DELETE | /photos/{photo} |
destroy | photos.destroy |
指定資源模型
如果你在使用路由模型綁定并且想要在資源控制器的方法中對(duì)模型實(shí)例進(jìn)行類型提示,可以在生成控制器的使用使用 --model
選項(xiàng):
php artisan make:controller PhotoController --resource --model=Photo
偽造表單方法
由于 HTML 表單不能發(fā)起PUT
、PATCH
和DELETE
請(qǐng)求,需要添加一個(gè)隱藏的 _method
字段來偽造 HTTP
請(qǐng)求方式,輔助函數(shù) method_field
可以幫我們做這件事:
{{ method_field('PUT') }}
部分資源路由
聲明資源路由時(shí)可以指定該路由處理的動(dòng)作子集:
Route::resource('photo', 'PhotoController', ['only' =>
['index', 'show']
]);
Route::resource('photo', 'PhotoController', ['except' =>
['create', 'store', 'update', 'destroy']
]);
命名資源路由
默認(rèn)情況下,所有資源控制器動(dòng)作都有一個(gè)路由名稱,不過,我們可以通過傳入 names
數(shù)組來覆蓋這些默認(rèn)的名字:
Route::resource('photo', 'PhotoController', ['names' =>
['create' => 'photo.build']
]);
命名資源路由參數(shù)
默認(rèn)情況下, Route::resource
將會(huì)基于資源名稱的單數(shù)格式為資源路由創(chuàng)建路由參數(shù),你可以通過在選項(xiàng)數(shù)組中傳遞 parameters
來覆蓋這一默認(rèn)設(shè)置。parameters
應(yīng)該是資源名稱和參數(shù)名稱的關(guān)聯(lián)數(shù)組:
Route::resource('user', 'AdminUserController', ['parameters' => [
'user' => 'admin_user'
]]);
上面的示例代碼會(huì)為資源的 show
路由生成如下URL
:
/user/{admin_user}
補(bǔ)充資源控制器
如果有必要在默認(rèn)資源路由之外添加額外的路由到資源控制器,應(yīng)該在調(diào)用 Route::resource
之前定義這些路由;否則,通過 resource
方法定義的路由可能無意中優(yōu)先于補(bǔ)充的額外路由:
Route::get('photos/popular', 'PhotoController@method');
Route::resource('photos', 'PhotoController');
注:注意保持控制器的單一職責(zé),如果你發(fā)現(xiàn)指向控制器動(dòng)作的路由超過默認(rèn)提供的資源控制器動(dòng)作集合了,考慮將你的控制器分割成多個(gè)更小的控制器。
依賴注入 & 控制器
構(gòu)造函數(shù)注入
Laravel 使用服務(wù)容器解析所有的 Laravel 控制器,因此,可以在控制器的構(gòu)造函數(shù)中類型聲明任何依賴,這些依賴會(huì)被自動(dòng)解析并注入到控制器實(shí)例中:
<?php
namespace App\Http\Controllers;
use App\Repositories\UserRepository;
class UserController extends Controller
{
/**
* 用戶存儲(chǔ)庫實(shí)例.
*/
protected $users;
/**
* 創(chuàng)建新的控制器實(shí)例
*
* @param UserRepository $users
* @return void
*/
public function __construct(UserRepository $users)
{
$this->users = $users;
}
}
當(dāng)然,你還可以類型提示任何 Laravel 契約,如果容器可以解析,就可以進(jìn)行類型提示。注入依賴到控制器可以讓應(yīng)用更加易于測(cè)試。
方法注入
除了構(gòu)造函數(shù)注入之外,還可以在控制器的動(dòng)作方法中進(jìn)行依賴的類型提示,例如,我們可以在某個(gè)方法中類型提示 Illuminate\Http\Request
實(shí)例:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class UserController extends Controller
{
/**
* 存儲(chǔ)新用戶
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$name = $request->input('name');
//
}
}
如果控制器方法期望輸入路由參數(shù),只需要將路由參數(shù)放到其他依賴之后,例如,如果你的路由定義如下:
Route::put('user/{id}', 'UserController@update');
你需要通過定義控制器方法如下所示來類型提示 Illuminate\Http\Request
并訪問路由參數(shù)id
:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class UserController extends Controller
{
/**
* 更新指定用戶
*
* @param Request $request
* @param int $id
* @return Response
* @translator http://laravelacademy.org
*/
public function update(Request $request, $id)
{
//
}
}
路由緩存
如果你在網(wǎng)站上只用控制器路由,你可以使用 Laravel 的路由緩存。使用路由緩存可以很大程序的減少注冊(cè)所有網(wǎng)站所有的路由所用的時(shí)間。在有些情況下,可以快一百倍。生成路由緩存,只需要使用 route:cache
這個(gè) Artisan
命令:
php artisan route:cache
完成以后,就會(huì)使用路由緩存來代替 app/Http/routes.php
文件。注意如果你添加了新的路由,你需要生成新的路由緩存,因?yàn)檫@個(gè),只在部署項(xiàng)目的時(shí)候才會(huì)使用 oute:cache
命令。
想要?jiǎng)h除掉路由緩存,可以使用 route:clear
命令:
php artisan route:clear