Skip to content

控制器

基本控制器

与其在单个 routes.php 文件中定义所有路由级逻辑,不如使用控制器类来组织这些行为。控制器可以将相关的路由逻辑分组到一个类中,并利用更高级的框架特性,例如自动 依赖注入

控制器通常存储在 app/controllers 目录中,并且该目录默认在 composer.json 文件的 classmap 选项中注册。然而,控制器实际上可以位于任何目录或子目录中。路由声明不依赖于控制器类文件在磁盘上的位置。因此,只要 Composer 知道如何自动加载控制器类,它可以放置在您希望的任何地方。

以下是一个基本控制器类的示例:

php
class UserController extends BaseController {

	/**
	 * 显示给定用户的个人资料。
	 */
	public function showProfile($id)
	{
		$user = User::find($id);

		return View::make('user.profile', array('user' => $user));
	}

}

所有控制器都应扩展 BaseController 类。BaseController 也存储在 app/controllers 目录中,可以用作放置共享控制器逻辑的地方。BaseController 扩展了框架的 Controller 类。现在,我们可以像这样路由到这个控制器动作:

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

如果您选择使用 PHP 命名空间来嵌套或组织您的控制器,只需在定义路由时使用完全限定的类名:

php
Route::get('foo', 'Namespace\FooController@method');
lightbulb

由于我们使用 Composer 来自动加载 PHP 类,控制器可以位于文件系统的任何位置,只要 composer 知道如何加载它们。控制器目录不强制执行应用程序的任何文件夹结构。路由到控制器完全与文件系统解耦。

您还可以在控制器路由上指定名称:

php
Route::get('foo', array('uses' => 'FooController@method', 'as' => 'name'));

要生成指向控制器动作的 URL,您可以使用 URL::action 方法或 action 辅助方法:

php
$url = URL::action('FooController@method');

$url = action('FooController@method');

您可以使用 currentRouteAction 方法访问正在运行的控制器动作的名称:

php
$action = Route::currentRouteAction();

控制器过滤器

过滤器 可以在控制器路由上指定,类似于“常规”路由:

php
Route::get('profile', array('before' => 'auth',
			'uses' => 'UserController@showProfile'));

但是,您也可以从控制器内部指定过滤器:

php
class UserController extends BaseController {

	/**
	 * 实例化一个新的 UserController 实例。
	 */
	public function __construct()
	{
		$this->beforeFilter('auth', array('except' => 'getLogin'));

		$this->beforeFilter('csrf', array('on' => 'post'));

		$this->afterFilter('log', array('only' =>
							array('fooAction', 'barAction')));
	}

}

您还可以使用闭包在线指定控制器过滤器:

php
class UserController extends BaseController {

	/**
	 * 实例化一个新的 UserController 实例。
	 */
	public function __construct()
	{
		$this->beforeFilter(function()
		{
			//
		});
	}

}

如果您希望在控制器上使用另一个方法作为过滤器,可以使用 @ 语法来定义过滤器:

php
class UserController extends BaseController {

	/**
	 * 实例化一个新的 UserController 实例。
	 */
	public function __construct()
	{
		$this->beforeFilter('@filterRequests');
	}

	/**
	 * 过滤传入的请求。
	 */
	public function filterRequests($route, $request)
	{
		//
	}

}

隐式控制器

Laravel 允许您轻松定义一个路由来处理控制器中的每个动作。首先,使用 Route::controller 方法定义路由:

php
Route::controller('users', 'UserController');

controller 方法接受两个参数。第一个是控制器处理的基本 URI,第二个是控制器的类名。接下来,只需向控制器添加方法,前缀为它们响应的 HTTP 动词:

php
class UserController extends BaseController {

	public function getIndex()
	{
		//
	}

	public function postProfile()
	{
		//
	}

	public function anyLogin()
	{
		//
	}

}

index 方法将响应控制器处理的根 URI,在这种情况下是 users

如果您的控制器动作包含多个单词,您可以在 URI 中使用“破折号”语法访问该动作。例如,以下控制器动作在我们的 UserController 中将响应 users/admin-profile URI:

php
public function getAdminProfile() {}

RESTful资源控制器

资源控制器使围绕资源构建 RESTful 控制器变得更加容易。例如,您可能希望创建一个控制器来管理应用程序存储的“照片”。通过 Artisan CLI 的 controller:make 命令和 Route::resource 方法,我们可以快速创建这样的控制器。

要通过命令行创建控制器,请执行以下命令:

php
php artisan controller:make PhotoController

现在我们可以将资源路由注册到控制器:

php
Route::resource('photo', 'PhotoController');

这条单一的路由声明创建了多个路由,以处理对照片资源的各种 RESTful 操作。同样,生成的控制器将已经为每个这些操作提供了存根方法,并附有说明它们处理的 URI 和动词的注释。

资源控制器处理的操作

动词路径操作路由名称
GET/resourceindexresource.index
GET/resource/createcreateresource.create
POST/resourcestoreresource.store
GET/resource/showresource.show
GET/resource/{resource}/editeditresource.edit
PUT/PATCH/resource/updateresource.update
DELETE/resource/destroyresource.destroy

有时您可能只需要处理资源操作的子集:

php
php artisan controller:make PhotoController --only=index,show

php artisan controller:make PhotoController --except=index

您还可以在路由上指定要处理的操作子集:

php
Route::resource('photo', 'PhotoController',
				array('only' => array('index', 'show')));

Route::resource('photo', 'PhotoController',
				array('except' => array('create', 'store', 'update', 'destroy')));

默认情况下,所有资源控制器操作都有一个路由名称;但是,您可以通过传递一个 names 数组来覆盖这些名称:

php
Route::resource('photo', 'PhotoController',
				array('names' => array('create' => 'photo.build')));

处理嵌套资源控制器

要“嵌套”资源控制器,请在路由声明中使用“点”符号:

php
Route::resource('photos.comments', 'PhotoCommentController');

此路由将注册一个“嵌套”资源,可以通过以下 URL 访问:photos/{photoResource}/comments/{commentResource}

php
class PhotoCommentController extends BaseController {

	public function show($photoId, $commentId)
	{
		//
	}

}

向资源控制器添加额外路由

如果您需要向资源控制器添加额外的路由,超出默认资源路由,您应该在调用 Route::resource 之前定义这些路由:

php
Route::get('photos/popular', 'PhotoController@method');
Route::resource('photos', 'PhotoController');

处理缺失的方法

使用 Route::controller 时,可以定义一个捕获所有方法,该方法将在给定控制器上找不到其他匹配方法时被调用。该方法应命名为 missingMethod,并接收请求的参数和方法参数数组:

定义捕获所有方法

php
public function missingMethod($parameters = array())
{
	//
}

如果您使用资源控制器,您应该在控制器上定义一个 __call 魔术方法来处理任何缺失的方法。