Laravel 文档阅读:控制器
我们的业务代码不能都写在路由文件(比如:routes/web.php
)里。路由的形式有两种:基于闭包和基于控制器的。我们最好把一些相关的路由请求放在一个控制器内管理,对应的,业务代码也转移到了控制器里。Larave 的控制器位于 app/Http/Controllers
目录下。
基础控制器
定义控制器
下面,就是一个基础控制器。这个控制器继承了 Laravel 提供的基类控制器。在基类控制器中提供了几个便捷的方法可以使用,比如 middleware
这个方法,就是用来给 控制器 action 附加中间件的。
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
class UsersController extends Controller
{
/**
* Show the profile for the given user.
*
* @param int $id
* @return Response
*/
public function show($id)
{
return view('users.profile', ['user' => User::findOrFail($id)]);
}
}
指向这个控制器 action 的路由是这样定义的:
Route::get('users/{id}', 'UserController@show');
当浏览器发起 users/xxx
路径请求的时候,UsersController
的 show
方法就会被调用,路由参数也会传递给这个方法。
需要注意的是, 我们的控制器不是非要继承基类控制器的,只不过,如果不继承基类控制器的话,一些非常好用的方法,比如 middleware
、validate
和 dispatch
就无法使用了。
控制器 & 命名空间
细心观察的话会发现,我们在定义控制器路由的时候,并没有使用控制器的完整命名空间。这是因为在 RouteServiceProvider
中,已经为 routes/web.php
和 routes/api.php
文件中的所有路由预设了 App\Http\Controllers
的命名空间前缀,所以我们在定义控制器路由时,只需指定 App\Http\Controllers
后面那部分的内容即可。
如果 App\Http\Controllers
目录中的控制器有更深的嵌套层级,比如,我们有一个控制器的完整路径是 App\Http\Controllers\Photos\AdminController
,那么在注册控制器路由的时候,就要像这样:
Route::get('foo', 'Photos\AdminController@method');
单 Action 控制器
有时,一个控制器只有唯一的一个方法,那么这时只要在控制器中定义一个 __invoke
方法就行:
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
class ShowProfile extends Controller
{
/**
* Show the profile for the given user.
*
* @param int $id
* @return Response
*/
public function __invoke($id)
{
return view('users.profile', ['user' => User::findOrFail($id)]);
}
}
指向这个单 Action 控制器的路由,定义起来就变成下面这样了:
Route::get('users/{id}', 'ShowProfile');
控制器中间件
在我们的路由文件里,可以为控制器路由指定中间件:
Route::get('profile', 'UsersController@show')->middleware('auth');
但是,在控制器构造方法里指定中间件更加方便,直接使用 middleware
方法,就可以轻松地为我们的控制器 action 分配中间件了:
class UsersController extends Controller
{
/**
* Instantiate a new controller instance.
*
* @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);
});
我们有时会对控制器的一个 action 子集做中间件处理。但这可能说明你的控制器是臃肿的,尝试去把这个控制器拆分成多个、职能更加单一的控制器吧。
资源控制器
资源控制器就是指包含 index
、create
、store
、show
、edit
、update
和 destroy
这 7 个方法的控制器。之所以称为「资源控制器」,是因为这 7 个方法包括了操作某个资源所需的全部基本操作,也就是 CRUD 操作。
在 Laravel 中,在使用 Artisan 命令 make:controller
时,通过传递一个额外选项 --resource
就可以快速创建这样一个资源控制器,我们以操作图片资源的 PhotosController
为例:
php artisan make:controller PhotosController --resource
这样就在 app/Http/Controllers/PhotosController.php
的地方创建了一个控制器,接下来在为资源控制器注册资源路由。
Route::resource('photos', 'PhotosController');
通过这一句代码,我们就定义了 7 个指向到 PhotosController
中相应方法的所有路由。我们来看一下:
对应到资源控制器相应方法的 7 个资源路由。
请求类型 | URI | 控制器 Action | 路由别名 |
---|---|---|---|
GET | /photos | index | photos.index |
GET | /photos/create | create | photos.create |
POST | /photos | store | photos.store |
GET | /photos/{photo} | show | photos.show |
GET | /photos/{photo}/edit | edit | photos.edit |
PUT/PATCH | /photos/{photo} | update | photos.update |
DELETE | /photos/{photo} | destroy | photos.destroy |
指定资源模型
在生成资源控制器的时候,还可以通过指定 -model
选项,为控制器中的方法指定模型类型。
php artisan make:controller --resource --model=Photo
表单方法伪造
由于 HTML 表单不能发出 PUT
、PATCH
和 DELETE
类型的请求,所以想要使用这些请求类型的话,就必须得伪造。Laravel 中使用隐藏表单域 _method
来告诉应用程序我们的请求类型。我们可以通过 method_field
辅助函数来生成这个表单域:
{{ method_field('PUT') }}
或者手动添加:
<input name="_method" type="hidden" value="PUT">
都是一样的。
部分资源路由
我们在使用 Route::resource
定义资源路由的时候,并不想生成全部 7 个路由,比如只需要定义其中的 2 个或者 4 个路由,Route::resource
同样可以满足这样的需求,这时需要为它指定第三个参数:
Route::resource('photos', 'PhotosController', ['only' => [
'index', 'show'
]]);
Route::resource('photos', 'PhotosController', ['except' => [
'create', 'store', 'update', 'destroy'
]]);
命名资源路由
默认,所有的资源路由都有一个名字,当然你也可以按情况覆盖掉相应方法。这是需要用到 names
这个数组选项:
Route::resource('photos', 'PhotosController', ['names' => [
'create' => 'photos.build'
]]);
命名资源路由参数
默认,所有的资源路由的路由参数是使用资源名的「单数」形式(如果资源名本身是单数形式,那么路由参数直接使用单数形式)。
Route::resource('users', 'AdminUserController');
// 生成的 `show` 路由
/users/{user}
Route::resource('user', 'AdminUserController');
// 生成的 `show` 路由
/user/{user}
当然,你也可以覆盖这个约定。这时要用到 parameters
这个数组选项:
Route::resource('users', 'AdminUserController', ['parameters' => [
'users' => 'admin_user'
]]);
// 生成的 `show` 路由
/users/{admin_user}
本地化资源 URIs
默认,Route::resource
生成的路由地址中包含 create
和 edit
这两个英语动词。如果需要本地化这两个动词,需要使用 Route::resourceVerbs
方法,这个方法可以在 AppServiceProvider
的 boot
方法里设定:
use Illuminate\Support\Facades\Route;
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Route::resourceVerbs([
'create' => 'crear',
'edit' => 'editar',
]);
}
定义好后,使用 Route::resource('fotos', 'PhotoController')
生成的资源路由会产生下面两个的 URIs:
/fotos/crear
/fotos/{foto}/editar
fotos、crear 和 editar 是西班牙语里的照片、创建和编辑。
补充资源控制器
如果你还要定义除了默认 7 个资源路由之外的其他路由,那么你应该在调用 Route::resource
之前定义这些路由,否则通过 resource
方法定义的路由可能会意外覆盖你额外添加的路由:
Route::get('photos/popular', 'PhotoController@method');
Route::resource('photos', 'PhotoController');
记住,要保证你的控制器职能单一,如果发现除了一些在资源控制器中普遍存在的方法之外,还需要定义一些其他的方法,那么请考虑将控制器拆分成两个或者多个更小的控制器。
依赖注入 & 控制器
通过构造方法注入
Laravel 中的控制器都是使用服务容器解析的。所以,你可以在控制器的构造方法里使用依赖注入。声明的依赖会自动注入到控制器实例中:
<?php
namespace App\Http\Controllers;
use App\Repositories\UserRepository;
class UsersController extends Controller
{
/**
* The user repository instance.
*/
protected $users;
/**
* Create a new controller instance.
*
* @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;
class UsersController extends Controller
{
/**
* Store a new user.
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$name = $request->name;
//
}
}
如果路由包含参数,那么这些参数要列在这些依赖项之后。例如,如果路由是这样的:
Route::put('users/{id}', 'UsersController@update');
在控制器方法里,就要在 Illuminate\Http\Request
依赖声明之后,获取咱们的用户 ID:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class UsersController extends Controller
{
/**
* Update the given user.
*
* @param Request $request
* @param string $id
* @return Response
*/
public function update(Request $request, $id)
{
//
}
}
路由缓存
先声明!使用闭包形式定义的路由时无法缓存的。要想用缓存,必须将闭包路由转换为控制器路由。
如果应用程序中,全部使用的是基于控制器方法的路由,那么这时候就可以充分利用 Laravel 路由缓存的功能了!使用路由缓存可以大大地减少应用程序中注册所有路由花费的时间。有些情况,注册路由的过程可能会提升 100 倍!生成路由缓存,执行 Artisan 命令 route:cache
即可:
php artisan route:cache
执行这条命令后,路由缓存文件会在每次请求时被加载。需要注意的是,应用程序中每当添加了一个新的路由,都需要重新执行 route:cache
命令方可生效。因此,你应该只在项目部署时才执行 route:cache
命令。
清除路由缓存使用 route:clear
就 OK 了!
php artisan route:clear
本作品采用《CC 协议》,转载必须注明作者和本文链接
控制器方法里注入 比较常用
不错
你好,这段时间我也在学laravel,可以加你qq或微信一起学习嘛? 谢谢