laravel 控制器——迹忆客-ag捕鱼王app官网
简介
我们不希望将所有的请求逻辑都定义为路由文件中的closures,而是希望使用controller类来实现这些逻辑。 controller可以将相关的请求处理逻辑封装为一个类。 控制器存储在app/http/controllers
目录中。
控制器基础
定义控制器
下面是一个基本控制器的示例。 请注意,该控制器继承了laravel的基本控制器类controller
。 基类提供了一些便利的方法,例如中间件方法,该方法可用于将中间件附加到控制器的action上:
user::findorfail($id)]);
}
}
我们可以使用下面代码定义一个路由到控制器的映射
route::get('user/{id}', 'usercontroller@show');
现在,当有一个和上面的路由匹配的请求到来时,usercontroller
控制器中的show
方法就会执行。同时,路由的参数也会传给show
方法
我们定义的控制器类不是必须要继承controller这个控制器基类的。只是如果我们不继承的话,就不能很方便的使用
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
方法
user::findorfail($id)]);
}
}
当为这种单一操作的控制器分配路由的时候,不需要指定控制器中的方法名,只需要指定控制器类名即可
route::get('user/{id}', 'showprofile');
我们可以在artisan命令make:controller
后面加上 --invokable
参数来生成这种具有单一操作的控制器
$ php artisan make:controller showprofile --invokable
控制器中间件
中间件也可以分配给定义的控制器的路由
route::get('profile', 'usercontroller@show')->middleware('auth');
除此之外,还可以在控制器的构造方法__construct()
中使用middleware
函数指定该控制器的中间件。甚至我们也可以使用only
方法为控制器中特定的某些方法加上中间件
class usercontroller 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');
}
}
控制器还允许我们使用closure注册中间件。 这提供了一种为单个控制器定义中间件的便捷方法,而无需定义整个中间件类:
$this->middleware(function ($request, $next) {
// ...
return $next($request);
});
您可以将中间件分配给控制器操作的子集; 但是,这在另一方面表明我们的控制器过大。 要考虑将控制器分成多个较小的控制器。
资源控制器
laravel资源路由通过单行代码将经典的“ crud”路由分配给控制器。 例如,我们可能希望创建这样的一个控制器,该控制器处理应用程序存储的所有针对“photos”的http请求。 使用artisan命令make:controller
,我们可以快速的创建这样的控制器:
$ php artisan make:controller photocontroller --resource
上面的命令将在app/http/controllers/photocontroller.php
中创建一个photocontroller
控制器,控制器将为每个可用资源的操作包含一个方法。
下面我们将为这个控制器注册一个路由
route::resource('photos', 'photocontroller');
上面单个路由声明创建了多个路由来处理资源上的各种操作。 生成的控制器已经为每个操作添加了方法,包括向我们通知它们所处理的http动词和uri。
我们可以通过数组的方式一次性注册多个资源控制器路由
route::resources([
'photos' => 'photocontroller',
'posts' => 'postcontroller',
]);
verb | uri | action | route name |
---|---|---|---|
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
如果使用路由模型绑定,并且希望资源控制器的方法指定一个模型实例,则可以在生成控制器时使用--model
选项:
$ php artisan make:controller photocontroller --resource --model=photo
隐藏form的提交方式
由于html表单无法发出put,patch或delete请求,因此我们需要添加一个隐藏的_method
字段来伪造这些http动词。 @method blade
指令可以创建此字段:
分解资源路由
当我们定义资源路由的时候,我们可能希望对该资源控制器的一部分操作控制器可以单独的执行,不用执行一遍该控制器的一系列的action。可以通过下面的方式实现
route::resource('photos', 'photocontroller')->only([
'index', 'show'
]);
route::resource('photos', 'photocontroller')->except([
'create', 'store', 'update', 'destroy'
]);
api 资源路由
声明将由api使用的资源路由时,通常会希望排除呈现html模板(例如create
和edit
)的路由。 为了方便起见,我们可以使用apiresource
方法自动排除这两个路由:
route::apiresource('photos', 'photocontroller');
同样,我们可以通过数组一次性注册多个api资源路由
route::apiresources([
'photos' => 'photocontroller',
'posts' => 'postcontroller',
]);
如果想快速的生成一个api资源控制器,该控制器不带create
和edit
方法,可以在artisan命令make:controller
后面添加--api
参数
$ php artisan make:controller api/photocontroller --api
嵌套的资源
有时我们可能需要定义到嵌套资源的路由。 例如,照片资源具有可以附加到照片的多个注释。 要嵌套资源控制器,请在路由声明中使用“.
”表示法:
route::resource('photos.comments', 'photocommentcontroller');
该路由将注册一个嵌套资源,该资源可以通过如下所示的uri进行访问:
/photos/{photo}/comments/{comment}
浅层嵌套
通常,在uri中同时包含父id和子id并不是完全必要的,因为子id已经是唯一的标识符。 当使用诸如自动递增主键之类的唯一标识符来标识uri段中的模型时,我们可以选择使用“浅层嵌套”:
route::resource('photos.comments', 'commentcontroller')->shallow();
上面的路由定义,可以生成下面这些路由
verb | uri | action | route name |
---|---|---|---|
get | /photos/{photo}/comments |
index | photos.comments.index |
get | /photos/{photo}/comments/create |
create | photos.comments.create |
post | /photos/{photo}/comments |
store | photos.comments.store |
get | /comments/{comment} |
show | comments.show |
get | /comments/{comment}/edit |
edit | comments.edit |
put/patch | /comments/{comment} |
update | comments.update |
delete | /comments/{comment} |
destroy | comments.destroy |
给资源路由的参数命名
默认情况下,route::resource
将基于资源名称的“单数”模式为我们的资源路由创建路由参数。 我们可以使用parameters
方法轻松地在每个资源的基础上重写此方法。 传递给parameters
方法的数组应该是资源名称和参数名称的关联数组:
route::resource('users', 'adminusercontroller')->parameters([
'users' => 'admin_user'
]);
上面的示例为资源的显示路线生成以下uri
/users/{admin_user}
资源路由的作用范围
有时,当在资源路由定义中隐式绑定多个eloquent模型时,您可能希望对第二个eloquent模型进行范围划分,使其必须是第一个eloquent模型的子作用域。 例如,考虑这种情况,该情况是通过slug为特定用户检索博客文章的:
use app\http\controllers\postscontroller;
route::resource('users.posts', postscontroller::class)->scoped();
我们可以通过将数组传递给scoped
方法,以此来覆盖默认的模型路由的键名:
use app\http\controllers\postscontroller;
route::resource('users.posts', postscontroller::class)->scoped([
'post' => 'slug',
]);
当使用自定义键隐式绑定作为嵌套的路由参数时,laravel将自动确定范围,以使用一些约定的规则来猜测其父级上的关系名称,从而由其父级检索嵌套模型。 在这种情况下,将假定用户模型具有一个名为post(路由参数名称的复数)的关系,该关系可用于检索post模型。
本地化资源uri
默认情况下,route::resource
将使用英语动词创建资源uri。 如果需要本地化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')
之类的资源路由注册将产生以下uri:
/fotos/crear
/fotos/{foto}/editar
补充资源控制器
如果您需要向资源控制器添加默认路由以外的其他路由,则应在调用route::resource
之前定义这些路由。 否则,由resource方法定义的路由可能会无意中优先于我们要添加的路由:
route::get('photos/popular', 'photocontroller@method');
route::resource('photos', 'photocontroller');
记住要使我们的控制器尽量功能单一。 如果发现自己通常需要一组典型的资源操作之外的方法,请考虑将控制器分为两个较小的控制器。
依赖注入和控制器
构造器注入
laravel 用于解析所有laravel控制器。 因此,我们可以在控制器的构造方法中对任何依赖进行类型限定。 声明的依赖项将自动解析并注入到控制器实例中:
users = $users;
}
}
如果容器中可以解析接口,我们也可以使用接口进行类型限定,只要是实现了该接口的实例都可以注入到控制器的构造方法中。
方法中注入
除了可以在控制器的构造方法中进行注入之外,还可以在控制器的自定义方法中进行注入。一个典型的应用示例就是在方法中注入illuminate\http\request
的实例。
name;
//
}
}
如果我们的控制器方法也希望从route传入参数,可以在其他依赖项之后列出route参数。 例如,如果路由是这样定义的:
route::put('user/{id}', 'usercontroller@update');
我们仍然可以通过如下定义控制器方法,键入illuminate\http\request
并访问id参数:
路由缓存
如果应用程序仅使用基于控制器的路由,则应利用laravel的路由缓存。 使用路由缓存将大大减少注册所有应用程序路由所需的时间。 在某些情况下,我们的路由注册速度甚至可能提高100倍。 要生成路由缓存,只需执行artisan命令route:cache
:
$ php artisan route:cache
运行此命令后,缓存的路由文件将在每个请求中加载。 请记住,如果添加任何新路由,那么需要生成新的路由缓存。 因此,我们仅应在项目部署期间运行route:cache
命令。
我们可以使用route:clear
命令清除路由缓存
php artisan route:clear
查看笔记