[关闭]
@snowdiva 2016-10-10T14:11:00.000000Z 字数 5250 阅读 476

[ Laravel 5.3 文档 ] HTTP层 -- 控制器

Laravel5.3 Laravel学习 控制器 控制器中间件 资源控制器

原文地址:Laravel学院


目录:


1、简介

将所有的请求处理逻辑都放在单个routes.php中显然是不合理的,你也许还希望使用控制器类组织管理这些行为。控制器可以将相关的HTTP请求封装到一个类中进行处理。通常控制器存放在app/Http/Controllers目录中。

2、基本控制器

定义控制器

下面是一个基本控制器类的例子。所有的Laravel控制器应该继承自Laravel自带的控制器类Controller,控制器基类提供了一些很方便的方法如middleware,用于添加中间件到控制器动作:

  1. <?php
  2. namespace App\Http\Controllers;
  3. use App\User;
  4. use App\Http\Controllers\Controller;
  5. class UserController extends Controller
  6. {
  7. /**
  8. * 为指定用户显示详情
  9. *
  10. * @param int $id
  11. * @return Response
  12. */
  13. public function showProfile($id)
  14. {
  15. return view('user.profile', ['user' => User::findOrFail($id)]);
  16. }
  17. }

我们可以像这样定义指向该控制器动作的路由

  1. Route::get('user/{id}', 'UserController@showProfile');

现在,如果一个请求匹配上面的路由URI,UserControllershowProfile方法就会被执行。当然,路由参数也会被传递给这个方法。

注:控制器并不一定要继承自基类,不过,那样的话就不能使用那些便利的方法了,比如middlewarevalidatedispatch等。

控制器 & 命名空间

你应该注意到我们在定义控制器路由的时候没有指定完整的控制器命名空间,而只是定义了App\Http\Controllers之后的部分。默认情况下,RouteServiceProvider将会在一个路由群组中载入routes.php文件,并且该路由群组指定了群组中路由控制器所在的命名空间。

如果你在App\Http\Controllers目录下选择使用PHP命名空间嵌套或只控制器,只需要使用相对于App\Http\Controllers命名空间的指定类名即可。因此,如果你的完整控制器类是App\Http\Controllers\Photos\AdminController,你可以像这样注册路由:

  1. Route::get('foo', 'Photos\AdminController@method');

单动作控制器

如果你想要定义一个只处理一个动作的控制器,可以在这个控制器中定义__invoke方法:

  1. <?php
  2. namespace App\Http\Controllers;
  3. use App\User;
  4. use App\Http\Controllers\Controller;
  5. class ShowProfile extends Controller
  6. {
  7. /**
  8. * Show the profile for the given user.
  9. *
  10. * @param int $id
  11. * @return Response
  12. */
  13. public function __invoke($id)
  14. {
  15. return view('user.prefile', ['user' => User::findOrFail($id)]);
  16. }
  17. }

当你为这个单动作控制器注册路由的时候,不需要指定方法:

  1. Route::get('user/{id}', 'ShowProfile');

3、控制器中间件

中间件可以像这样分配给控制器路由:

  1. Route::get('profile', 'UserController@show')->middleware('auth');

但是,将中间件放在控制器构造函数中更方便,在控制器的构造函数中使用middleware方法你可以很轻松的分配中间件给该控制器。你甚至可以限定该中间件应用到该控制器类的指定方法:

  1. class UserController extends Controller
  2. {
  3. /**
  4. * 实例化一个新的 UserController 实例
  5. *
  6. * @return void
  7. */
  8. public function __construct()
  9. {
  10. $this->middleware('auth');
  11. $this->middleware('log')->only('index');
  12. $this->middleware('subscribed')->ecept('store');
  13. }
  14. }

注:你可以将中间件分配给多个控制器动作,不过这意味着你的控制器会变得越来越臃肿,这种情况下,需要考虑将控制器分割成更多、更小的控制器。

4、资源控制

Laravel的资源控制使得构建围绕资源的RESTful控制器变得毫无痛苦,例如,你可能想要在应用中创建一个控制器,用于处理关于图片存储的HTTP请求,使用Artisan命令make:controller,我们可以快速创建这样的控制器:

  1. php artisan make:controller PhotoController --resource

该Artisan命令将会生成一个控制器文件app/Http/Controllers/PhotoController.php,这个控制包含了每一个资源操作对应的方法。

接下来,可以为该控制器注册一个资源路由:

  1. Route::resource('photos', 'PhotoController');

这个路由声明包含了处理图片资源RESTful动作的多个路由,相应地,Artisan生成的控制器也已经为这些动作设置了对应的处理方法。

资源控制器处理的动作

方法 路径 动作 路由名称
GET /photos index photots.index
GET /photos/create create photots.create
POST /photos store photots.store
GET /photos/{photo} show photots.show
GET /photos/{photo}/edit edit photots.edit
PUT/PATCH /photos/{photo} update photots.update
DELETE /photos/{photo} destroy photots.destroy

伪造表单方法

由于HTML表单不能发起PUTPATCHDELETE请求,需要添加一个隐藏的_method字段来伪造HTTP请求方式,辅助函数method_field可以帮我们做这件事:

  1. {{ method_field('PUT') }}

部分资源路由

声明资源路由时可以指定改路由处理的动作子集:

  1. Route::resource('photo', 'PhotoController', ['only' => ['index', 'show']]);
  2. Route::resource('photo', 'PhotoController', ['except' => ['create', 'store', 'update', 'destroy']]);

命名资源路由

默认情况下,所有资源控制器动作都有一个路由名称,然而,我们可以通过传入names数组来覆盖这些默认的名字:

  1. Route::resource('photo', 'PhotoController', ['names' => ['create' => 'photo.build']]);

命名资源路由参数

默认情况下,Route::resource将会基于资源名称的单数格式为资源路由创建路由参数,你可以通过在选项数组中传递parameters来覆盖这一默认设置。parameters应该是资源名称和参数名称的关联数组:

  1. Route::resource('user', 'AdminUserController', ['parameters' => ['user' => 'admin_user']]);

上面的示例代码会为资源的show路由生成如下URL:

  1. /user/{admin_user}

补充资源控制器

如果有必要在默认资源路由之外添加额外的路由到资源控制器,应该在调用Route::resource之前定义这些路由;否则,通过resource方法定义的路由可能无意中优先于补充的额外路由:

  1. Route::get('photo/popular', 'PhotoController@method');
  2. Route::resource('photos', 'PhotoController');

注:注意保持控制器的单一职责,如果你发现指向控制器动作的路由超过默认提供的资源控制器动作集合了,考虑将你的控制器分割成更多、更小的控制器。

5、依赖注入 & 控制器

构造函数注入

Laravel使用服务容器解析所有的Laravel控制器,因此,可以在控制器的构造函数中类型声明任何依赖,这些依赖会自动解析并注入控制器实例中:

  1. <?php
  2. namespace App\Http\Controllers;
  3. use Illuminate\Routing\Contoller;
  4. use App\Repositories\UserRepository;
  5. class UserController extends Controller
  6. {
  7. /**
  8. * The User repository instance.
  9. */
  10. protected $users;
  11. /**
  12. * 创建新的控制器实例
  13. *
  14. * @param UserRepository $users
  15. * @return void
  16. */
  17. public function __construct(UserRepository $users)
  18. {
  19. $this->users = $users;
  20. }
  21. }

当然,你还可以类型提示任何Laravel契约,如果容器可以解析,就可以进行类型提示。

方法注入

除了构造函数注入之外,还可以在控制器的动作方法中进行依赖的类型提示,例如,我们可以在某个方法中类型提示Illuminate\Http\Request实例:

  1. <?php
  2. namespace App\Http\Controllers;
  3. use Illuminate\Http\Request;
  4. use Illuminate\Routing\Controller;
  5. class UserController extends Controller
  6. {
  7. /**
  8. * 存储新用户
  9. *
  10. * @param Request $request
  11. * @return Response
  12. */
  13. public function store(Request $request)
  14. {
  15. $name = $request->input('name');
  16. // 后续代码...
  17. }
  18. }

如果控制器方法期望输入路由参数,只需要将路由参数放到其他以来之后,例如,如果你的路由定义如下:

  1. Route::put('user/{id}', 'UserController@update');

你需要通过定义控制器方法所示来类型提示Iluminate\Http\Request并访问路由参数id

  1. <?php
  2. namespace App\Http\Controllers;
  3. use Illuminate\Http\Request;
  4. use Illuminate\Routing\Controller;
  5. class UserController extends Controller
  6. {
  7. /**
  8. * 更新指定用户
  9. *
  10. * @param Request $request
  11. * @param int $id
  12. * @return Response
  13. * @translator http://laravelacademy.org
  14. */
  15. public function update(Request $request, $id)
  16. {
  17. // 代码处理...
  18. }
  19. }

6、路有缓存

注意:路有缓存不会作用于基于闭包的路由。要使用路有缓存,必须将闭包路由转化成控制器路由。
如果你的应用完全基于控制器路由,可以使用Laravel的路有缓存,使用路有缓存将会极大减少注册所有应用路由所花费的时间开销,在某些案例中,路由注册速度甚至能提高100倍!想要生成路有缓存,只需执行Artisan命令route:cache

  1. php artisan route:cache

运行完成后,每次请求都会从缓存中读取路由,记住,如果你添加新的路由需要重新生成路由缓存。因此,只有在项目部署阶段才需要运行route:cache命令。

想要移出缓存路由文件,使用route:clear命令即可:

  1. php artisan route:clear
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注