Laravel Http 層 控制器

介紹

不要把所有處理請(qǐng)求的邏輯都放到一個(gè)單獨(dú)的 routes.php 文件里,我們可以使用控制器去組織這些行為。Controller 可以把相關(guān)的處理 HTTP 請(qǐng)求的邏輯放到一個(gè)類里面。一般控制器都放在 app/Http/Controllers 這個(gè)目錄的下面:

app/Http/Controllers
├── Auth
│   ├── AuthController.php
│   └── PasswordController.php
├── Controller.php
├── HomeController.php
└── WelcomeController.php

1 directory, 5 files

基本控制器

定義控制器
下面是一個(gè)基本控制器類的例子。所有的 Laravel 控制器應(yīng)該繼承自 Laravel 自帶的控制器基類 Controller,控制器基類提供了一些很方便的方法如 middleware ,用于添加中間件 到控制器動(dòng)作:

<?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)
                     ]
        );
    }
}

我們可以像這樣定義指向該控制器動(dòng)作的路由:

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

這樣當(dāng)用戶請(qǐng)求訪問 user/{id} 這種類型的地址的時(shí)候,就會(huì)用 UserController 里面的 show 這個(gè)方法來處理這些請(qǐng)求。

注:控制器并不是一定要繼承自基類,不過,那樣的話就不能使用一些便利的方法了,比如 middlewarevalidatedispatch 等。

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

默認(rèn)情況下,RouteServiceProvider在載入 routes.php 文件的時(shí)候,會(huì)包含控制器 根命名空間。

如果你的完整控制器類 App\Http\Controllers\Photos\AdminController,則可以像這樣注冊(cè)路由:

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

單動(dòng)作控制器

如果你想要定義一個(gè)只處理一個(gè)動(dòng)作的控制器,可以在這個(gè)控制器中定義 __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)
                    ]
        );
    }
}

當(dāng)你為這個(gè)單動(dòng)作控制器注冊(cè)路由的時(shí)候,不需要指定方法:

Route::get('user/{id}', 'ShowProfile');

控制器中間件

中間件可以像這樣分配給控制器路由:

Route::get('profile', 'UserController@show')->middleware('auth');

但是,將中間件放在控制器構(gòu)造函數(shù)中更方便,在控制器的構(gòu)造函數(shù)中使用 middleware 方法你可以很輕松的分配中間件給該控制器。你甚至可以限定該中間件應(yīng)用到該控制器類的指定方法:

class UserController extends Controller
{
    /**
     * 實(shí)例化一個(gè)新的 UserController 實(shí)例
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth');
        $this->middleware('log')->only('index');
        $this->middleware('subscribed')->except('store');
    }
}

在控制器中還可以使用閉包注冊(cè)中間件,這為我們定義只在某個(gè)控制器使用的中間件提供了方便,無需定義完整的中間件類:

$this->middleware(function ($request, $next) {
    // ...

    return $next($request);
});

注:你還可以將中間件分配給多個(gè)控制器動(dòng)作,不過,這意味著你的控制器會(huì)變得越來越臃腫,這種情況下,需要考慮將控制器分割成多個(gè)更小的控制器。

資源控制器

Laravel 的資源控制器使得構(gòu)建圍繞資源的 RESTful 控制器變得毫無痛苦,例如,你可能想要在應(yīng)用中創(chuàng)建一個(gè)控制器,用于處理關(guān)于圖片存儲(chǔ)的 HTTP 請(qǐng)求,使用 Artisan 命令 make:controller,我們可以快速創(chuàng)建這樣的控制器:

php artisan make:controller PhotoController --resource

Artisan 命令將會(huì)生成一個(gè)控制器文件 app/Http/Controllers/PhotoController.php,這個(gè)控制器包含了每一個(gè)資源操作對(duì)應(yīng)的方法。

接下來,可以為該控制器注冊(cè)一個(gè)資源路由:

Route::resource('photos', 'PhotoController');

這個(gè)路由聲明包含了處理圖片資源 RESTful 動(dòng)作的多個(gè)路由,相應(yīng)地,Artisan 生成的控制器也已經(jīng)為這些動(dòng)作設(shè)置了對(duì)應(yīng)的處理方法。

資源控制器處理的動(dòng)作

方法 路徑 動(dòng)作 路由名稱
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

指定資源模型

如果你在使用路由模型綁定并且想要在資源控制器的方法中對(duì)模型實(shí)例進(jìn)行類型提示,可以在生成控制器的使用使用 --model選項(xiàng):

php artisan make:controller PhotoController --resource --model=Photo

偽造表單方法
由于 HTML 表單不能發(fā)起PUTPATCHDELETE請(qǐng)求,需要添加一個(gè)隱藏的 _method 字段來偽造 HTTP 請(qǐng)求方式,輔助函數(shù) method_field 可以幫我們做這件事:

{{ method_field('PUT') }}

部分資源路由

聲明資源路由時(shí)可以指定該路由處理的動(dòng)作子集:

Route::resource('photo', 'PhotoController', ['only' => 
    ['index', 'show']
]);

Route::resource('photo', 'PhotoController', ['except' => 
    ['create', 'store', 'update', 'destroy']
]);

命名資源路由

默認(rèn)情況下,所有資源控制器動(dòng)作都有一個(gè)路由名稱,不過,我們可以通過傳入 names 數(shù)組來覆蓋這些默認(rèn)的名字:

Route::resource('photo', 'PhotoController', ['names' => 
    ['create' => 'photo.build']
]);

命名資源路由參數(shù)

默認(rèn)情況下, Route::resource 將會(huì)基于資源名稱的單數(shù)格式為資源路由創(chuàng)建路由參數(shù),你可以通過在選項(xiàng)數(shù)組中傳遞 parameters 來覆蓋這一默認(rèn)設(shè)置。parameters 應(yīng)該是資源名稱和參數(shù)名稱的關(guān)聯(lián)數(shù)組:

Route::resource('user', 'AdminUserController', ['parameters' => [
    'user' => 'admin_user'
]]);

上面的示例代碼會(huì)為資源的 show 路由生成如下URL

/user/{admin_user}

補(bǔ)充資源控制器

如果有必要在默認(rèn)資源路由之外添加額外的路由到資源控制器,應(yīng)該在調(diào)用 Route::resource 之前定義這些路由;否則,通過 resource 方法定義的路由可能無意中優(yōu)先于補(bǔ)充的額外路由:

Route::get('photos/popular', 'PhotoController@method');
Route::resource('photos', 'PhotoController');

注:注意保持控制器的單一職責(zé),如果你發(fā)現(xiàn)指向控制器動(dòng)作的路由超過默認(rèn)提供的資源控制器動(dòng)作集合了,考慮將你的控制器分割成多個(gè)更小的控制器。

依賴注入 & 控制器

構(gòu)造函數(shù)注入

Laravel 使用服務(wù)容器解析所有的 Laravel 控制器,因此,可以在控制器的構(gòu)造函數(shù)中類型聲明任何依賴,這些依賴會(huì)被自動(dòng)解析并注入到控制器實(shí)例中:

<?php

namespace App\Http\Controllers;

use App\Repositories\UserRepository;

class UserController extends Controller
{
    /**
     * 用戶存儲(chǔ)庫實(shí)例.
     */
    protected $users;

    /**
     * 創(chuàng)建新的控制器實(shí)例
     *
     * @param UserRepository $users
     * @return void
     */
    public function __construct(UserRepository $users)
    {
        $this->users = $users;
    }
}

當(dāng)然,你還可以類型提示任何 Laravel 契約,如果容器可以解析,就可以進(jìn)行類型提示。注入依賴到控制器可以讓應(yīng)用更加易于測(cè)試。

方法注入
除了構(gòu)造函數(shù)注入之外,還可以在控制器的動(dòng)作方法中進(jìn)行依賴的類型提示,例如,我們可以在某個(gè)方法中類型提示 Illuminate\Http\Request實(shí)例:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    /**
     * 存儲(chǔ)新用戶
     *
     * @param Request $request
     * @return Response
     */
    public function store(Request $request)
    {
        $name = $request->input('name');

        //
    }
}

如果控制器方法期望輸入路由參數(shù),只需要將路由參數(shù)放到其他依賴之后,例如,如果你的路由定義如下:

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

你需要通過定義控制器方法如下所示來類型提示 Illuminate\Http\Request 并訪問路由參數(shù)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)
    {
        //
    }
}

路由緩存

如果你在網(wǎng)站上只用控制器路由,你可以使用 Laravel 的路由緩存。使用路由緩存可以很大程序的減少注冊(cè)所有網(wǎng)站所有的路由所用的時(shí)間。在有些情況下,可以快一百倍。生成路由緩存,只需要使用 route:cache 這個(gè) Artisan 命令:

php artisan route:cache

完成以后,就會(huì)使用路由緩存來代替 app/Http/routes.php 文件。注意如果你添加了新的路由,你需要生成新的路由緩存,因?yàn)檫@個(gè),只在部署項(xiàng)目的時(shí)候才會(huì)使用 oute:cache 命令。

想要?jiǎng)h除掉路由緩存,可以使用 route:clear命令:

php artisan route:clear
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,924評(píng)論 18 139
  • 原文鏈接 必備品 文檔:Documentation API:API Reference 視頻:Laracasts ...
    layjoy閱讀 8,626評(píng)論 0 121
  • 上圖列出了 Laravel HTTP 層的相關(guān)知識(shí)大綱。由于目前自己的工作中網(wǎng)頁、App、小程序等都采用前后臺(tái)分離...
    胖福哥閱讀 1,882評(píng)論 0 21
  • 0.1配置1.模板繼承2.控制器3.git4.支付寶支付的流程5.路由6.中間件7.請(qǐng)求8.laravel 學(xué)習(xí)筆...
    云龍789閱讀 841評(píng)論 0 5
  • 1.基本控制器 所有的 Laravel 控制器應(yīng)該繼承自 Laravel 自帶的控制器基類 Controller ...
    lmem閱讀 591評(píng)論 0 0