[TOC]
### **1、简介**
将所有的请求处理逻辑都放在单个 `routes.php` 中显然是不合理的,你也许还希望使用[控制器](http://laravelacademy.org/tags/%e6%8e%a7%e5%88%b6%e5%99%a8 "View all posts in 控制器")类组织管理这些行为。控制器可以将相关的 HTTP 请求封装到一个类中进行处理。通常控制器存放在 `app/Http/Controllers` 目录中。
### **2、基本控制器**
下面是一个基本控制器类的例子。所有的 [Laravel](http://laravelacademy.org/tags/laravel "View all posts in 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)]);
}
}
~~~
我们可以像这样定义指向该控制器动作的[路由](http://laravelacademy.org/tags/%e8%b7%af%e7%94%b1 "View all posts in 路由"):
~~~
Route::get('user/{id}', 'UserController@showProfile');
~~~
现在,如果一个请求匹配上面的路由 URI,`UserController` 的 `showProfile` 方法就会被执行。当然,路由参数也会被传递给这个方法。
#### **控制器 & 命名空间**
你应该注意到我们在定义控制器路由的时候没有指定完整的控制器命名空间,而只是定义了 `App\Http\Controllers`之后的部分。默认情况下,`RouteServiceProvider` 将会在一个路由群组中载入 `routes.php` 文件,并且该路由群组指定定了群组中路由控制器所在的命名空间。
如果你在 `App\Http\Controllers` 目录下选择使用 PHP 命名空间嵌套或组织控制器,只需要使用相对于`App\Http\Controllers` 命名空间的指定类名即可。因此,如果你的完整控制器类是`App\Http\Controllers\Photos\AdminController`,你可以像这样注册路由:
~~~
Route::get('foo', 'Photos\AdminController@method');
~~~
#### **命名控制器路由**
和闭包路由一样,可以指定控制器路由的名称:
~~~
Route::get('foo', ['uses' => 'FooController@method', 'as' => 'name']);
~~~
你还可以使用辅助函数 `route` 来为已命名的控制器路由生成对应的 URL:
~~~
$url = route('name');
~~~
### **3、控制器[中间件](http://laravelacademy.org/tags/%e4%b8%ad%e9%97%b4%e4%bb%b6 "View all posts in 中间件")**
中间件可以像这样分配给控制器路由:
~~~
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](http://laravelacademy.org/tags/restful "View all posts in RESTful") 资源控制器**
Laravel 的资源控制器使得构建围绕资源的 RESTful 控制器变得毫无痛苦,例如,你可能想要在应用中创建一个控制器,用于处理关于图片存储的 HTTP 请求,使用 Artisan 命令 `make:controller`,我们可以快速创建这样的控制器:
~~~
php artisan make:controller PhotoController --resource
~~~
该 Artisan 命令将会生成一个控制器文件 `app/Http/Controllers/PhotoController.php`,这个控制器包含了每一个资源操作对应的方法。
接下来,可以为该控制器注册一个资源路由:
~~~
Route::resource('photo', 'PhotoController');
~~~
这个路由声明包含了处理图片资源 RESTful 动作的多个路由,相应地,Artisan 生成的控制器也已经为这些动作设置了对应的处理方法。
#### **资源控制器处理的动作**
| 方法 | 路径 | 动作 | 路由名称 |
| --- | --- | --- | --- |
| 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 |
#### **只定义部分资源路由**
声明资源路由时可以指定该路由处理的动作子集:
~~~
Route::resource('photo', 'PhotoController',
['only' => ['index', 'show']]);
Route::resource('photo', 'PhotoController',
['except' => ['create', 'store', 'update', 'destroy']]);
~~~
#### **命名资源路由**
默认情况下,所有资源控制器动作都有一个路由名称,然而,我们可以通过传入 `names` 数组来覆盖这些默认的名字:
~~~
Route::resource('photo', 'PhotoController',
['names' => ['create' => 'photo.build']]);
~~~
#### **补充资源控制器**
如果有必要在默认资源路由之外添加额外的路由到资源控制器,应该在调用 `Route::resource` 之前定义这些路由;否则,通过 `resource` 方法定义的路由可能无意中优先于补充的额外路由:
~~~
Route::get('photos/popular', 'PhotoController@method');
Route::resource('photos', 'PhotoController');
~~~
### **5、[依赖注入](http://laravelacademy.org/tags/%e4%be%9d%e8%b5%96%e6%b3%a8%e5%85%a5 "View all posts in 依赖注入") & 控制器**
#### **构造函数注入**
Laravel 使用服务容器解析所有的 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 契约,如果容器可以解析,就可以进行类型提示。
#### **方法注入**
除了构造函数注入之外,还可以在控制器的动作方法中进行依赖的类型提示,例如,我们可以在某个方法中类型提示 `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)
{
//
}
}
~~~
### **6、路由缓存**
> 注意:路由缓存不会作用于基于闭包的路由。要使用路由缓存,必须将闭包路由转化为控制器路由。
如果你的应用完全基于控制器路由,可以使用 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 模板引擎
- 架构
- 一次请求的生命周期
- 应用目录结构
- 服务提供者
- 服务容器
- 门面(Facades)
- 数据库
- 起步
- 查询构建器
- 迁移
- 填充数据
- Eloquent ORM
- 起步
- 关联关系
- 集合
- 访问器&修改器
- 序列化
- 服务
- 用户认证
- 用户授权
- Artisan Console
- 订阅支付实现:Laravel Cashier
- 缓存
- 集合
- 集成前端资源:Laravel Elixir
- 加密
- 错误&日志
- 事件
- 文件系统/云存储
- 哈希
- 辅助函数
- 本地化
- 邮件
- 包开发
- 分页
- Redis
- 队列
- Session
- Envoy Task Runner
- 任务调度
- 测试
- 验证
- 新手入门指南
- 简单任务管理系统
- 带用户功能的任务管理系统