Laravel 的 HTTP 控制器
简介
除了在路由文件中以闭包的形式定义所有的请求处理逻辑外,你可能还想使用控制器类来组织此类操作。控制器能够将相关的请求处理逻辑组成一个单独的类。控制器被存放在 app/Http/Controllers
目录下。
基础控制器
定义控制器
以下是一个基础控制器类的例子。需要注意的是,该控制器继承了 Laravel 内置的基础控制器类。该基础类提供了一些便捷的方法,比如 middleware
方法,该方法可以用来给控制器操作添加中间件:
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
/**
* 展示给定用户的信息。
*
* @param int $id
* @return Response
*/
public function show($id)
{
return view('user.profile', ['user' => User::findOrFail($id)]);
}
}
你可以这样定义一个指向该控制器操作的路由:
Route::get('user/{id}', 'UserController@show');
现在,当请求和此特定路由的 URI 匹配时,UserController
类的 show
方法就会被执行。当然,路由参数也会被传递至该方法。
控制器并不是 一定 要继承基础类。只是,你将无法使用一些便捷的功能,比如 middleware
,validate
和 dispatch
方法。
控制器与命名空间
这一点很重要,我们在定义控制器路由时,不必指定完整的控制器命名空间。RouteServiceProvider
会在一个包含命名空间的路由组中加载路由文件,因此我们只需要指定类名中 App\Http\Controllers
命名空间之后的部分就可以了。
如果你选择将控制器存放在 App\Http\Controllers
目录下,只需简单地使用相对于根命名空间 App\Http\Controllers
的特定类名。因此,如果你的完整控制器类是 App\Http\Controllers\Photos\AdminController
,你应该用这种方式注册指向该控制器的路由:
Route::get('foo', 'Photos\AdminController@method');
单一操作控制器
如果想定义一个只处理单个操作的控制器,你可以在控制器中只设置一个 __invoke
方法:
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
class ShowProfile extends Controller
{
/**
* 展示给定用户的信息。
*
* @param int $id
* @return Response
*/
public function __invoke($id)
{
return view('user.profile', ['user' => User::findOrFail($id)]);
}
}
为单一操作控制器注册路由时,无需指定方法:
Route::get('user/{id}', 'ShowProfile');
控制器中间件
中间件 可以在路由文件中指定给控制器路由:
Route::get('profile', 'UserController@show')->middleware('auth');
然而,在控制器的构造方法中指定中间件会更为便捷。在控制器构造方法中使用 middleware
方法,你可以很容易地将中间件指定给控制器操作。你甚至可以约束中间件只对控制器类中的某个特定方法生效:
class UserController extends Controller
{
/**
* 创建一个新的控制器实例。
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('log')->only('index');
$this->middleware('subscribed')->except('store');
}
}
控制器也允许你使用闭包的方式注册中间件。这提供了一种很便捷地为单个控制器定义中间件的方式,而不用定义一个完整的中间件类:
$this->middleware(function ($request, $next) {
// ...
return $next($request);
});
你可能将中间件指定到控制器的部分操作上,然而,这会使你的控制器过于臃肿。换个角度,考虑将控制器分成多个更小的控制器。