介绍
不要把所有处理请求的逻辑都放到一个单独的 routes.php
文件里,我们可以使用控制器去组织这些行为。Controller
可以把相关的处理 HTTP 请求的逻辑放到一个类里面。一般控制器都放在 app/Http/Controllers
这个目录的下面:
app/Http/Controllers
├── Auth
│ ├── AuthController.php
│ └── PasswordController.php
├── Controller.php
├── HomeController.php
└── WelcomeController.php
1 directory, 5 files
基本控制器
定义控制器
下面是一个基本控制器类的例子。所有的 Laravel 控制器应该继承自 Laravel 自带的控制器基类 Controller
,控制器基类提供了一些很方便的方法如 middleware
,用于添加中间件 到控制器动作:
User::findOrFail($id)
]
);
}
}
我们可以像这样定义指向该控制器动作的路由:
Route::get('user/{id}', 'UserController@show');
这样当用户请求访问 user/{id}
这种类型的地址的时候,就会用 UserController 里面的 show
这个方法来处理这些请求。
注:控制器并不是一定要继承自基类,不过,那样的话就不能使用一些便利的方法了,比如
middleware
、validate
和dispatch
等。
控制器 & 命名空间
使用控制器的时候,不需要去指定控制器的全部命名空间,可以只用在 App\Http\Controllers
(根命名空间) 命名空间之后的部分。
默认情况下,RouteServiceProvider
在载入 routes.php
文件的时候,会包含控制器 根命名空间。
如果你的完整控制器类 App\Http\Controllers\Photos\AdminController
,则可以像这样注册路由:
Route::get('foo', 'Photos\AdminController@method');
单动作控制器
如果你想要定义一个只处理一个动作的控制器,可以在这个控制器中定义 __invoke
方法:
User::findOrFail($id)
]
);
}
}
当你为这个单动作控制器注册路由的时候,不需要指定方法:
Route::get('user/{id}', 'ShowProfile');
控制器中间件
中间件可以像这样分配给控制器路由:
Route::get('profile', 'UserController@show')->middleware('auth');
但是,将中间件放在控制器构造函数中更方便,在控制器的构造函数中使用 middleware
方法你可以很轻松的分配中间件给该控制器。你甚至可以限定该中间件应用到该控制器类的指定方法:
class UserController extends Controller
{
/**
* 实例化一个新的 UserController 实例
*
* @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);
});
注:你还可以将中间件分配给多个控制器动作,不过,这意味着你的控制器会变得越来越臃肿,这种情况下,需要考虑将控制器分割成多个更小的控制器。
资源控制器
Laravel 的资源控制器使得构建围绕资源的 RESTful 控制器变得毫无痛苦,例如,你可能想要在应用中创建一个控制器,用于处理关于图片存储的 HTTP 请求,使用 Artisan
命令 make:controller
,我们可以快速创建这样的控制器:
php artisan make:controller PhotoController --resource
该 Artisan
命令将会生成一个控制器文件 app/Http/Controllers/PhotoController.php
,这个控制器包含了每一个资源操作对应的方法。
接下来,可以为该控制器注册一个资源路由:
Route::resource('photos', 'PhotoController');
这个路由声明包含了处理图片资源 RESTful
动作的多个路由,相应地,Artisan
生成的控制器也已经为这些动作设置了对应的处理方法。
资源控制器处理的动作
方法 | 路径 | 动作 | 路由名称 |
---|---|---|---|
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 PhotoController --resource --model=Photo
伪造表单方法
由于 HTML 表单不能发起PUT
、PATCH
和DELETE
请求,需要添加一个隐藏的 _method
字段来伪造 HTTP
请求方式,辅助函数 method_field
可以帮我们做这件事:
{{ method_field('PUT') }}
部分资源路由
声明资源路由时可以指定该路由处理的动作子集:
Route::resource('photo', 'PhotoController', ['only' =>
['index', 'show']
]);
Route::resource('photo', 'PhotoController', ['except' =>
['create', 'store', 'update', 'destroy']
]);
命名资源路由
默认情况下,所有资源控制器动作都有一个路由名称,不过,我们可以通过传入 names
数组来覆盖这些默认的名字:
Route::resource('photo', 'PhotoController', ['names' =>
['create' => 'photo.build']
]);
命名资源路由参数
默认情况下, Route::resource
将会基于资源名称的单数格式为资源路由创建路由参数,你可以通过在选项数组中传递 parameters
来覆盖这一默认设置。parameters
应该是资源名称和参数名称的关联数组:
Route::resource('user', 'AdminUserController', ['parameters' => [
'user' => 'admin_user'
]]);
上面的示例代码会为资源的 show
路由生成如下URL
:
/user/{admin_user}
补充资源控制器
如果有必要在默认资源路由之外添加额外的路由到资源控制器,应该在调用 Route::resource
之前定义这些路由;否则,通过 resource
方法定义的路由可能无意中优先于补充的额外路由:
Route::get('photos/popular', 'PhotoController@method');
Route::resource('photos', 'PhotoController');
注:注意保持控制器的单一职责,如果你发现指向控制器动作的路由超过默认提供的资源控制器动作集合了,考虑将你的控制器分割成多个更小的控制器。
依赖注入 & 控制器
构造函数注入
Laravel 使用服务容器解析所有的 Laravel 控制器,因此,可以在控制器的构造函数中类型声明任何依赖,这些依赖会被自动解析并注入到控制器实例中:
users = $users;
}
}
当然,你还可以类型提示任何 Laravel 契约,如果容器可以解析,就可以进行类型提示。注入依赖到控制器可以让应用更加易于测试。
方法注入
除了构造函数注入之外,还可以在控制器的动作方法中进行依赖的类型提示,例如,我们可以在某个方法中类型提示 Illuminate\Http\Request
实例:
input('name');
//
}
}
如果控制器方法期望输入路由参数,只需要将路由参数放到其他依赖之后,例如,如果你的路由定义如下:
Route::put('user/{id}', 'UserController@update');
你需要通过定义控制器方法如下所示来类型提示 Illuminate\Http\Request
并访问路由参数id
:
路由缓存
如果你在网站上只用控制器路由,你可以使用 Laravel 的路由缓存。使用路由缓存可以很大程序的减少注册所有网站所有的路由所用的时间。在有些情况下,可以快一百倍。生成路由缓存,只需要使用 route:cache
这个 Artisan
命令:
php artisan route:cache
完成以后,就会使用路由缓存来代替 app/Http/routes.php
文件。注意如果你添加了新的路由,你需要生成新的路由缓存,因为这个,只在部署项目的时候才会使用 oute:cache
命令。
想要删除掉路由缓存,可以使用 route:clear
命令:
php artisan route:clear