Laravel Http 层 控制器

介绍

不要把所有处理请求的逻辑都放到一个单独的 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 ,用于添加中间件 到控制器动作:

<?php

namespace App\Http\Controllers;

use App\User;
use App\Http\Controllers\Controller;

class UserController extends Controller
{
    /**
     * 为指定用户显示详情
     *
     * @param int $id
     * @return Response
     */
    public function show($id)
    {
        return view(
                    'user.profile',
                     [
                        'user' => User::findOrFail($id)
                     ]
        );
    }
}

我们可以像这样定义指向该控制器动作的路由:

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

这样当用户请求访问 user/{id} 这种类型的地址的时候,就会用 UserController 里面的 show 这个方法来处理这些请求。

注:控制器并不是一定要继承自基类,不过,那样的话就不能使用一些便利的方法了,比如 middlewarevalidatedispatch 等。

控制器 & 命名空间
使用控制器的时候,不需要去指定控制器的全部命名空间,可以只用在 App\Http\Controllers(根命名空间) 命名空间之后的部分。

默认情况下,RouteServiceProvider在载入 routes.php 文件的时候,会包含控制器 根命名空间。

如果你的完整控制器类 App\Http\Controllers\Photos\AdminController,则可以像这样注册路由:

Route::get('foo', 'Photos\AdminController@method');

单动作控制器

如果你想要定义一个只处理一个动作的控制器,可以在这个控制器中定义 __invoke 方法:

<?php

namespace App\Http\Controllers;

use App\User;
use App\Http\Controllers\Controller;

class ShowProfile extends Controller
{
    /**
     * 显示给定用户的用户资料
     *
     * @param  int  $id
     * @return Response
     */
    public function __invoke($id)
    {
        return view(
                    'user.profile',
                    [
                      'user' => 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 表单不能发起PUTPATCHDELETE请求,需要添加一个隐藏的 _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 控制器,因此,可以在控制器的构造函数中类型声明任何依赖,这些依赖会被自动解析并注入到控制器实例中:

<?php

namespace App\Http\Controllers;

use App\Repositories\UserRepository;

class UserController extends Controller
{
    /**
     * 用户存储库实例.
     */
    protected $users;

    /**
     * 创建新的控制器实例
     *
     * @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 UserController extends Controller
{
    /**
     * 存储新用户
     *
     * @param Request $request
     * @return Response
     */
    public function store(Request $request)
    {
        $name = $request->input('name');

        //
    }
}

如果控制器方法期望输入路由参数,只需要将路由参数放到其他依赖之后,例如,如果你的路由定义如下:

Route::put('user/{id}', 'UserController@update');

你需要通过定义控制器方法如下所示来类型提示 Illuminate\Http\Request 并访问路由参数id

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    /**
     * 更新指定用户
     *
     * @param Request $request
     * @param int $id
     * @return Response
     * @translator http://laravelacademy.org
     */
    public function update(Request $request, $id)
    {
        //
    }
}

路由缓存

如果你在网站上只用控制器路由,你可以使用 Laravel 的路由缓存。使用路由缓存可以很大程序的减少注册所有网站所有的路由所用的时间。在有些情况下,可以快一百倍。生成路由缓存,只需要使用 route:cache 这个 Artisan 命令:

php artisan route:cache

完成以后,就会使用路由缓存来代替 app/Http/routes.php 文件。注意如果你添加了新的路由,你需要生成新的路由缓存,因为这个,只在部署项目的时候才会使用 oute:cache 命令。

想要删除掉路由缓存,可以使用 route:clear命令:

php artisan route:clear
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • 原文链接 必备品 文档:Documentation API:API Reference 视频:Laracasts ...
    layjoy阅读 8,516评论 0 121
  • 上图列出了 Laravel HTTP 层的相关知识大纲。由于目前自己的工作中网页、App、小程序等都采用前后台分离...
    胖福哥阅读 1,764评论 0 21
  • 0.1配置1.模板继承2.控制器3.git4.支付宝支付的流程5.路由6.中间件7.请求8.laravel 学习笔...
    云龙789阅读 784评论 0 5
  • 1.基本控制器 所有的 Laravel 控制器应该继承自 Laravel 自带的控制器基类 Controller ...
    lmem阅读 559评论 0 0