教程 > laravel 教程 > 阅读:51

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, validatedispatch 这些方法。

控制器和命名空间

在定义控制器路由时,我们不需要指定完整的控制器的。 由于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指令可以创建此字段:

@method('put')

分解资源路由

当我们定义资源路由的时候,我们可能希望对该资源控制器的一部分操作控制器可以单独的执行,不用执行一遍该控制器的一系列的action。可以通过下面的方式实现

route::resource('photos', 'photocontroller')->only([
    'index', 'show'
]);
route::resource('photos', 'photocontroller')->except([
    'create', 'store', 'update', 'destroy'
]);

api 资源路由

声明将由api使用的资源路由时,通常会希望排除呈现html模板(例如createedit)的路由。 为了方便起见,我们可以使用apiresource方法自动排除这两个路由:

route::apiresource('photos', 'photocontroller');

同样,我们可以通过数组一次性注册多个api资源路由

route::apiresources([
    'photos' => 'photocontroller',
    'posts' => 'postcontroller',
]);

如果想快速的生成一个api资源控制器,该控制器不带createedit 方法,可以在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。 如果需要本地化createedit动作动词,则可以使用route::resourceverbs方法。 这可以在appserviceproviderboot方法中完成:

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

查看笔记

扫码一下
查看教程更方便
网站地图