# 基礎 —— HTTP 控制器
## 1、簡介
將所有的請求處理邏輯都放在單個`routes.php`中肯定是不合理的,你也許還希望使用控制器請求封裝到一個類中進行處理。通常控制器存放在`app/Http/Controllers`目錄中。
## 2、基本控制器
下面是一個基本控制器類的例子。所有的Laravel控制器應該繼承自Laravel自帶的控制器基類`Controller`:
~~~
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
/**
* 為指定用戶顯示詳情
*
* @param int $id
* @return Response
*/
public function showProfile($id)
{
return view('user.profile', ['user' => User::findOrFail($id)]);
}
}
~~~
我們可以像這樣定義指向該控制器動作的路由:
~~~
Route::get('user/{id}', 'UserController@showProfile');
~~~
現在,如果一個請求匹配上面的路由URI,`UserController`的`showProfile`方法就會被執行。當然,路由參數也會被傳遞給這個方法。
### 2.1 控制器&命名空間
你應該注意到我們在定義控制器路由的時候沒有指定完整的控制器命名空間,而只是定義了`App\Http\Controllers`之后的部分。默認情況下,`RouteServiceProvider`將會在一個路由分組中載入`routes.php`文件,并且該路由分組指定定了分組中路由控制器所在的命名空間。
如果你在`App\Http\Controllers`目錄下選擇使用PHP命名空間嵌套或組織控制器,只需要使用相對于`App\Http\Controllers`命名空間的指定類名即可。因此,如果你的完整控制器類是`App\Http\Controllers\Photos\AdminController`,你可以像這樣注冊路由:
~~~
Route::get('foo', 'Photos\AdminController@method');
~~~
### 2.2 命名控制器路由
和閉包路由一樣,可以指定控制器路由的名字:
~~~
Route::get('foo', ['uses' => 'FooController@method', 'as' => 'name']);
~~~
設置好控制器路由后,就可以使用幫助函數`action`很方便地為控制器動作生成對應的URL:
~~~
$url = action('FooController@method');
~~~
你還可以使用幫助函數`route`來為已命名的控制器路由生成對應的URL:
~~~
$url = route('name');
~~~
## 3、控制器中間件
[中間件](http://laravelacademy.org/post/57.html)可以像這樣分配給控制器路由:
~~~
Route::get('profile', [
'middleware' => 'auth',
'uses' => 'UserController@showProfile'
]);
~~~
但是,將中間件放在控制器構造函數中更方便,在控制器的構造函數中使用`middleware`方法你可以很輕松的分配中間件給該控制器。你甚至可以限定該中間件應用到該控制器類的指定方法:
~~~
class UserController extends Controller
{
/**
* 實例化一個新的 UserController 實例
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('log', ['only' => ['fooAction', 'barAction']]);
$this->middleware('subscribed', ['except' => ['fooAction', 'barAction']]);
}
}
~~~
## 4、RESTful資源控制器
Laravel的資源控制器使得構建圍繞資源的RESTful控制器變得毫無痛苦,例如,你可能想要在應用中創建一個控制器,用于處理關于圖片存儲的HTTP請求,使用Artisan命令`make:controller`,我們可以快速創建這樣的控制器:
~~~
php artisan make:controller PhotoController
~~~
該Artisan命令將會生成一個控制器文件`app/Http/Controllers/PhotoController.php`,這個控制器包含了每一個資源操作對應的方法。
接下來,可以為該控制器注冊一個資源路由:
~~~
Route::resource('photo', 'PhotoController');
~~~
這個路由聲明包含了處理圖片資源RESTful動作的多個路由,相應地,Artisan生成的控制器也已經為這些動作設置了對應的處理方法。
### 4.1 資源控制器處理的動作
| 方法 | 路徑 | 動作 | 路由名稱 |
| --- | --- | --- | --- |
| GET | `/photo` | index | photo.index |
| GET | `/photo/create` | create | photo.create |
| POST | `/photo` | store | photo.store |
| GET | `/photo/{photo}` | show | photo.show |
| GET | `/photo/{photo}/edit` | edit | photo.edit |
| PUT/PATCH | `/photo/{photo}` | update | photo.update |
| DELETE | `/photo/{photo}` | destroy | photo.destroy |
### 4.2 只定義部分資源路由
聲明資源路由時可以指定該路由處理的動作子集:
~~~
Route::resource('photo', 'PhotoController',
['only' => ['index', 'show']]);
Route::resource('photo', 'PhotoController',
['except' => ['create', 'store', 'update', 'destroy']]);
~~~
### 4.3 命名資源路由
默認情況下,所有資源控制器動作都有一個路由名稱,然而,我們可以通過傳入`names`數組來覆蓋這些默認的名字:
~~~
Route::resource('photo', 'PhotoController',
['names' => ['create' => 'photo.build']]);
~~~
### 4.4 嵌套資源
有時候我們需要定義路由到“嵌套”資源。例如,一個圖片資源可能擁有多條“評論”,要“嵌套”資源控制器,在路由聲明中使用“.”號即可:
~~~
Route::resource('photos.comments', 'PhotoCommentController');
~~~
該路由將注冊一個嵌套的資源,使用URL訪問方式如下:
`photos/{photos}/comments/{comments}`.
~~~
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
class PhotoCommentController extends Controller
{
/**
* 顯示指定照片評論
*
* @param int $photoId
* @param int $commentId
* @return Response
* @translator http://laravelacademy.org
*/
public function show($photoId, $commentId)
{
//
}
}
~~~
### 4.5 補充資源控制器
如果有必要在默認資源路由之外添加額外的路由到資源控制器,應該在調用`Route::resource`之前定義這些路由;否則,通過`resource`方法定義的路由可能無意中優先于補充的額外路由:
~~~
Route::get('photos/popular', 'PhotoController@method');
Route::resource('photos', 'PhotoController');
~~~
> 擴展閱讀:實例教程——[創建RESTFul風格控制器實現文章增刪改查](http://laravelacademy.org/post/549.html)
## 5、隱式控制器
Laravel允許你只定義一個路由即可訪問控制器類中的所有動作,首先,使用`Route::controller`方法定義一個路由,該`controller`方法接收兩個參數,第一個參數是控制器處理的baseURI,第二個參數是控制器的類名:
~~~
Route::controller('users', 'UserController');
~~~
接下來,添加方法到控制器,方法名應該以HTTP請求方法開頭:
~~~
<?php
namespace App\Http\Controllers;
class UserController extends Controller
{
/**
* 響應 GET /users 請求
*/
public function getIndex()
{
//
}
/**
* 響應 GET /users/show/1 請求
*/
public function getShow($id)
{
//
}
/**
* 響應 GET /users/admin-profile 請求
*/
public function getAdminProfile()
{
//
}
/**
* 響應 POST /users/profile 請求
*/
public function postProfile()
{
//
}
}
~~~
在上例中可以看到,`getIndex`方法將會在訪問控制器處理的默認URI——users時被調用。
### 5.1?分配路由名稱
如果你想要命名該控制器中的一些路由,可以將一個名稱數組作為第三個參數傳遞到該`controller`方法:
~~~
Route::controller('users', 'UserController', [
'getShow' => 'user.show',
]);
~~~
## 6、依賴注入?& 控制器
### 6.1 構造函數注入
Laravel使用[服務容器](http://laravelacademy.org/post/93.html)解析所有的Laravel控制器,因此,可以在控制器的構造函數中類型聲明任何依賴,這些依賴會被自動解析并注入到控制器實例中:
~~~
<?php
namespace App\Http\Controllers;
use Illuminate\Routing\Controller;
use App\Repositories\UserRepository;
class UserController extends Controller
{
/**
* The user repository instance.
*/
protected $users;
/**
* 創建新的控制器實例
*
* @param UserRepository $users
* @return void
*/
public function __construct(UserRepository $users)
{
$this->users = $users;
}
}
~~~
當然,你還可以類型提示任何[Laravel契約](http://laravelacademy.org/post/95.html),如果容器可以解析,就可以進行類型提示。
### 6.2 方法注入
除了構造函數注入之外,還可以在控制器的動作方法中進行依賴的類型提示,例如,我們可以在某個方法中類型提示`Illuminate\Http\Request`實例:
~~~
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
class UserController extends Controller
{
/**
* 存儲新用戶
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$name = $request->input('name');
//
}
}
~~~
如果控制器方法期望輸入路由參數,只需要將路由參數放到其他依賴之后,例如,如果你的路由定義如下:
~~~
Route::put('user/{id}', 'UserController@update');
~~~
你需要通過定義控制器方法如下所示來類型提示`Illuminate\Http\Request`并訪問路由參數`id`:
~~~
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
class UserController extends Controller
{
/**
* 更新指定用戶
*
* @param Request $request
* @param int $id
* @return Response
* @translator http://laravelacademy.org
*/
public function update(Request $request, $id)
{
//
}
}
~~~
## 7、路由緩存
如果你的應用完全基于路由使用控制器,可以使用Laravel的路由緩存,使用路由緩存將會極大減少注冊所有應用路由所花費的時間開銷,在某些案例中,路由注冊速度甚至能提高100倍!想要生成路由緩存,只需執行Artisan命令`route:cache`:
~~~
php artisan route:cache
~~~
就這么簡單!你的緩存路由文件現在取代`app/Http/routes.php`文件被使用,記住,如果你添加新的路由需要重新生成路由緩存。因此,只有在項目開發階段你才會運行`route:cache`命令。
想要移除緩存路由文件,使用`route:clear`命令即可:
~~~
php artisan route:clear
~~~
- 前言
- 序言
- 序言 ―― 發行版本說明
- 序言 ―― 升級指南
- 序言 ―― 貢獻代碼
- 開始
- 開始 ―― 安裝及配置
- 開始 ―― Laravel Homestead
- 基礎
- 基礎 ―― HTTP路由
- 基礎 ―― HTTP 中間件
- 基礎 ―― HTTP 控制器
- 基礎 ―― HTTP 請求
- 基礎 ―― HTTP 響應
- 基礎 ―― 視圖
- 基礎 ―― Blade模板
- 架構
- 架構 ―― 一次請求的生命周期
- 架構 ―― 應用目錄結構
- 架構 ―― 服務提供者
- 架構 ―― 服務容器
- 架構 ―― 契約
- 架構 ―― 門面
- 數據庫
- 數據庫 ―― 起步
- 數據庫 ―― 查詢構建器
- 數據庫 ―― 遷移
- 數據庫 ―― 填充數據
- Eloquent ORM
- Eloquent ORM ―― 起步
- Eloquent ORM ―― 關聯關系
- Eloquent ORM ―― 集合
- Eloquent ORM ―― 調整器
- Eloquent ORM ―― 序列化
- 服務
- 服務 ―― 用戶認證
- 服務 ―― Artisan 控制臺
- 服務 ―― Laravel Cashier(交易)
- 服務 ―― 緩存
- 服務 ―― 集合
- 服務 ―― Laravel Elixir
- 服務 ―― 加密
- 服務 ―― 錯誤&日志
- 服務 ―― 事件
- 服務 ―― 文件系統/云存儲
- 服務 ―― 哈希
- 服務 ―― 幫助函數
- 服務 ―― 本地化
- 服務 ―― 郵件
- 服務 ―― 包開發
- 服務 ―― 分頁
- 服務 ―― 隊列
- 服務 ―― Redis
- 服務 ―― Session
- 服務 ―― Envoy 任務運行器(SSH任務)
- 服務 ―― 任務調度
- 服務 ―― 測試
- 服務 ―― 驗證