[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)
{
//
}
}
~~~