控制器


基本控制器

与在单个routes.php文件中定义所有的路由逻辑不同,你可能想要使用多个控制器类来组织控制器逻辑行为。控制器可以将与之相关的路由逻辑组织进一个类中,同时控制器也能使用一些更加高级的框架特性例如自动依赖注入。

控制器一般放在app/controllers目录下,这个目录默认会在你的composer.json文件的classmap选项中被注册。但是,从技术上来说,控制器可以存放在任意目录或者子目录中。路由声明并不依赖于控制器类文件在磁盘中的具体为止。因此,只要Composer能够知道在怎样自动加载控制器类,具体的控制器文件可以放在任何你想存放的地方。

下面是一个基本控制器类的例子:

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类。现在,我们可以像下面的代码一样路由到这整个控制器的行为:

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

如果你选择使用PHP命名空间嵌套或者组织你的控制器,可以在定义路由时简单是使用完整的类名:

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

注意: 由于我们使用Composer来自动加载我们的PHP类,控制器可以存放在文件系统中的任何地方,只要composer知道应该在哪里加载它们。在你的应用中,控制器不会被强制要求以某种特定的文件结构存放。路由到该控制器的逻辑和文件系统之前完全解耦。

你也可以在控制器路由中指定一个名词:

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

为了给控制器行为生成一个URL,你可以使用URL::action方法或者action辅助方法:

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

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

你可以使用currentRouteAction方法来获得目前正在运行的控制器名称:

$action = Route::currentRouteAction();

控制器过滤器

过滤器 可以在控制器的路由中指定,它和"一般的"路由很相似:

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

然而,你也可以在你的控制器内部指定过滤器:

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')));
    }

}

你可以使用一个闭包来内联的指定控制器过滤器:

class UserController extends BaseController {

    /**
     * 生成一个UserController实例
     */
    public function __construct()
    {
        $this->beforeFilter(function()
        {
            //
        });
    }

}

如果你想要在控制器中将另一个方法作为过滤器使用,你可以使用@语法来定义这个过滤器:

class UserController extends BaseController {

    /**
     * 生成一个UserController实例
     */
    public function __construct()
    {
        $this->beforeFilter('@filterRequests');
    }

    /**
     * 过滤进入该控制器的请求
     */
    public function filterRequests($route, $request)
    {
        //
    }

}

隐式控制器

Laravel允许你在控制器中通过简单的定义一个单一的路由就能处理所有行为。首先,使用Route::controller方法来定义路由:

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

controller方法接收两个参数。第一个参数是控制器处理的基本URI,第二个参数是控制器的类名。其次,为你的控制器添加方法,并在方法名称之前加上对应的HTTP动词:

class UserController extends BaseController {

    public function getIndex()
    {
        //
    }

    public function postProfile()
    {
        //
    }

    public function anyLogin()
    {
        //
    }

}

index方法将会想要由控制器处理的根URI,在上面的例子中,即users

如果你的控制器行为包含多个词,你可以在URI中使用"破折号"语法。例如,在我们的UserController类中,下面的控制器行为将会响应users/admin-profileURI:

public function getAdminProfile() {}

RESTful 风格的资源控制器

使用资源控制器能够围绕资源构建RESTful风格的控制器。例如,你可能想要创建一个控制器来管理存放在你的应用中的"照片"。通过使用Artisan命令行工具的controller:make命令以及Route::resource方法,我们可以快速的构建出这样一个控制器。

执行下面的命令,通过命令行创建一个控制器:

php artisan controller:make PhotoController

现在我们可以为这个控制器注册一个resourceful风格的路由:

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

这个简单的路由声明创建了多个路由来处理与照片资源相关的一系列RESTful行为。与此同时,生成的控制器也已经具备了一系列的方法来处理每一种路由。

资源控制器处理的行为

动词 路径 动作 路由名称
GET /resource index resource.index
GET /resource/create create resource.create
POST /resource store resource.store
GET /resource/{resource} show resource.show
GET /resource/{resource}/edit edit resource.edit
PUT/PATCH /resource/{resource} update resource.update
DELETE /resource/{resource} destroy resource.destroy

有时你只想要处理资源行为的一个子集:

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

php artisan controller:make PhotoController --except=index

同时,你也也可以在路由中制定一个行为的子集:

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

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

默认情况下,所有的资源控制器行为都有一个路由名称;然而,你可以通过在选项中使用一个name数组重载这些名称:

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

为资源控制器添加额外的路由

如果你需要为你的资源控制器添加默认资源路由之外的路由,你应该在调用Route::resource方法之前定义这些路由:

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

处理缺失的方法

当使用 Route::controller时,你可以在控制器中定义一个万能的方法,用来处理不能被其他所有方法处理的请求。这个方法的名称必须为missingMethod,它接收这个未被处理的请求的方法和参数数组作为参数。

定义一个万能方法

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

如果你正在使用资源控制器,你应当在控制器中定义一个 __call 魔术方法,用于处理对任何不存在的方法的调用。