[TOC]
## 1、簡介
將所有的請求處理邏輯都放在單個`routes.php`中肯定是不合理的,你也許還希望使用控制器類組織管理這些行為。控制器可以將相關的HTTP請求封裝到一個類中進行處理。通常控制器存放在`app/Http/Controllers`目錄中。
## 2、基本控制器
下面是一個基本控制器類的例子。所有的[Lumen](http://laravelacademy.org/tags/lumen "View all posts in Lumen")控制器應該繼承自Lumen安裝默認的基本控制器:
~~~
<?php
namespace App\Http\Controllers;
use App\User;
class UserController extends Controller
{
/**
* 為指定用戶顯示詳情
*
* @param int $id
* @return Response
*/
public function showProfile($id)
{
return view('user.profile', ['user' => User::findOrFail($id)]);
}
}
~~~
我們可以像這樣[路由](http://laravelacademy.org/tags/%e8%b7%af%e7%94%b1 "View all posts in 路由")到控制器動作:
~~~
$app->get('user/{id}', 'UserController@showProfile');
~~~
現在,如果一個請求匹配指定的路由URI,`UserController`的`showProfile`方法就會被執行。當然,路由參數也會被傳遞給這個方法。
### 2.1 控制器&命名空間
你應該注意到我們在定義控制器路由的時候沒有指定完整的控制器命名空間,我們只需要定義`App\Http\Controllers`之后的類名部分。默認情況下,`bootstrap/app.php`將會在一個路由分組中載入`routes.php`文件,該路由分組包含了控制器的根命名空間。
如果你在`App\Http\Controllers`目錄下選擇使用PHP命名空間嵌套或組織控制器,只需要使用相對于`App\Http\Controllers`根命名空間的指定類名即可。因此,如果你的完整控制器類是`App\Http\Controllers\Photos\AdminController`,你可以像這樣注冊路由:
~~~
$app->get('foo', 'Photos\AdminController@method');
~~~
### 2.2 命名控制器路由
和閉包路由一樣,可以指定控制器路由的名字:
~~~
$app->get('foo', ['uses' => 'FooController@method', 'as' => 'name']);
~~~
一旦你為控制器路由分配了名字,那么你就可以使用幫助函數`action`很方便的生成URL到action,這里我們也只需要指定相對?`App\Http\Controllers`的命名空間即可:
~~~
$url = action('FooController@method');
~~~
你還可以使用幫助函數`route`來為已命名的控制器路由生成URL:
~~~
$url = route('name');
~~~
## 3、控制器中間件
中間件可以像這樣分配給控制器路由:
~~~
$app->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、依賴注入&控制器
### 4.1 構造函數注入
Lumen使用[服務容器](http://laravelacademy.org/post/471.html)解析所有的Lumen控制器,因此,可以在控制器的構造函數中類型提示任何依賴,這些依賴會被自動解析并注入到控制器實例中:
~~~
<?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
* @translator http://laravelacademy.org
*/
public function __construct(UserRepository $users)
{
$this->users = $users;
}
}
~~~
當然,你還可以類型提示任何[Laravel契約](http://laravelacademy.org/post/95.html),如果容器可以解析,就可以進行類型提示。
### 4.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');
//
}
}
~~~
如果控制器方法期望輸入路由參數,只需要將路由參數放到其他依賴之后,例如,如果你的路由定義如下:
~~~
$app->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)
{
//
}
}
~~~