lumen

HTTP路由

  • 基本路由
  • 路由參數
    1. 必填參數
    2. 可選參數
    3. 正則表達式約束
  • 命名路由
  • 路由組
    1. 中間件
    2. 命令空間
    3. 路由前綴

基本路由

你能夠在 route/web.php 文件中定義應用程序的所有路由。最基本的Lumen路由僅接受URL和一個Closure:php

$router->get('foo', function(){
    return 'Hello, World';
});

$router->post('foo', function(){
    //
});

可供使用的路由方法

咱們能夠註冊路由來響應任何方法的HTTP請求:laravel

$router->get($uri, $callback);
$router->post($uri, $callback);
$router->put($uri, $callback);
$router->patch($uri, $callback);
$router->delete($uri, $callback);
$router->options($uri, $callback);

路由參數

必填參數

固然,有時須要在路由中捕獲一些URL片斷。例如,從URL中捕獲用戶的ID,能夠經過經過定義路由參數來執行此操做:web

$router->get('user/{id}', function ($id) {
    return "User:" . $id;
});

也能夠根據須要在路由中定義多個參數:ajax

$router->get('posts/{postId}/comments/{commentId}', function ($postId, $commentId) {
    //
});

路由的參數都會被放在[大括號]內。當運行路由時,參數會傳遞到Closure裏面。正則表達式

注意:路由參數不能包含-字符。請用下劃線_代替。redis

可選參數

你能夠經過將部分路由URI包含在[...]中來定義可選的路由參數。那麼像/foo[bar]將會匹配到/foo和/foobar。可選參數僅支持放在URI的末尾。換句話說,你不能在路由定義的中間位置放置可選參數:數據庫

$router->get('user'[/{name}]', function ($name = null) {
    return $name;
});

正則表達式約束

你能夠經過在路由定義中使用正則表達式來約束路由參數的格式:json

$router->get('user2/{name:[a-zA-Z]}', function () {
    //
});

命名路由

命名路由能夠方便的爲特定路由生成URL或者進行重定向。你可使用as數組鍵指定名稱到路由上:bootstrap

$router->get('profile', ['as' => 'profile', function() {
    //
}]);

你還能夠指定控制器行爲的路由名稱:後端

$router->get('profile', [
    'as' => 'profile',
    'uses' => 'UserController@showProfile',
]);

生成指定路由的URL

爲路由制定了名稱後,就可使用全局輔導函數route來生成連接或者重定向到該路由:

//Generating URLs...
$url = route('profile');

//Generating Redirects...
return redirect()->route('profile');

若是是有定義參數的命名路由,能夠把參數做爲route函數的第二個參數傳入,指定的參數將會自動插入到URL中對應的位置:

$router->get('user/{id}/profile', ['as' => 'profile', function ($id) {
    return $id;
}]);

$url = route('profile', ['id' => 1]);

路由組

路由羣組容許你共用路由屬性,例如:中間件、命名空間,你能夠利用路由組統一爲多個路由設置共同屬性,而不須要在每一個路由都設置一次。共用屬性被指定爲數組格式,當作$router->group方法的第一個參數。

爲了瞭解更多路由羣組的相關內容,咱們能夠經過幾個經常使用樣例來熟悉這些特性。

中間件

要給路由組中全部的路由分配中間件,你能夠在group屬性數組中使用middleware字段。中間件會依照它們在數組中列出的順序來運行:

$router->group(['middleware' => 'auth'], function () use ($router) {
    $router->get('/', function () {
        //使用Auth中間件
    });

    $router->get('user/profile', function () {
        //使用Auth 中間件
    });
});

命名空間

另外一個常見的例子是,指定相同的PHP命名空間給控制器羣組。可使用namespace參數來指定羣組內全部控制器的命名空間:

$router->group(['namespace' => 'Admin'], function () use ($router) {
    //使用"App\Http\Controllers\Admin"命名空間
    $router->group(['namespace' => 'User', function () use ($router) {
        //使用"App\Http\Controllers\Admin\User" 命名空間...
    }]);
});

路由前綴

經過路由羣組數組屬性中的prefix,在路由羣組內爲每一個路由指定的URI加上前綴。例如,你可能想要在路由羣組中將全部的路由URI加上前綴admin:

$router->group(['prefix,' => 'admin'], function () use ($roter) {
    $router->get('users', function () {
        //匹配The "/admin/users"URL
    });
});

你也可使用prefix參數去指定路由羣組中共用的參數:
$router->group(['prefix' => 'accounts/{accountId}'], function () use ($router) {
$router->get('detail', function ($accountId) {
//匹配The "/accounts/{accountId}/detail" URL
});
});

HTTP中間件

  • 簡介
  • 定義中間件
  • 註冊中間件

    • 全局中間件
    • 爲路由指定中間件
  • 中間件參數
  • Terminal中間件

簡介

HTTP中間件提供了一個方便的機制來過濾進入應用程序的HTTP請求。例如,lumen內置了一箇中間件來驗證用戶的身份認證。若是用戶未經過省份證,中間件將會把用戶導向登陸頁面,反之,當用戶經過了身份證,中間件將會經過此請求並接着往下執行。

固然,除了身份證以外,中間件也能夠被用來運行各式各樣的任何,如:CORS中間件負責替換全部即將離開程序的響應加入適當的標頭;而日誌中間件則能夠記錄全部出入應用從程序的請求。

全部的中間件都放在app/Http/Middleware目錄內。

定義中間件

你能夠經過賦值lumen內置的示例文件ExampleMiddleware來建立一箇中間件。在這個中間件中,咱們只容許參數age大於200的請求才能訪問該路由。不然,咱們將此用戶重定向到首頁"home"這個URI上。

正如你所見,假如給定的age參數小於或者等於200,這個中間件將返回一個HTTP重定向到客戶端;不然,請求將進一步傳遞到應用中。要讓請求繼續傳遞到應用程序中(即容許「經過」中間件驗證的),只須要使用$request做爲參數去調用回調函數$next。

最好將中間件想象爲一系列HTTP請求必須通過才能進入你的應用的層。每個都會檢查請求
(是否符合某些條件),(若是不符合)甚至能夠(在請求訪問你的應用以前)徹底拒絕掉。

前置/後置中間件

中間件是在請求以前或者以後運行取決於中間件自己。例如,接下來的這個中間件將在應用處理請求before執行其任務:

<?php
namespace App\Http\Middleware;
use Closure;
class BeforeMiddleware
{
public function handle($request, Closure $next)
{
//執行操做
return $next($request);
}
}

而接下來的這個中間件將在應用處理請求以後執行其任務:

<?php
namespace App\Http\Middelware;
use Closure;

class AfterMiddleware
{
    public function handle($request, Closure $next)
    {
        return $next($request);
    }
}

註冊中間件

全局中間件

如果但願中間件在應用處理每一個HTTP請求期間運行,只須要在bootstrap/app.php文件中的
$app->middleware()方法中列出這個中間件:

$app->middleware([
   App\Http\Middleware\OldMiddleware::class
]);

爲路由分配中間件

若是你想將中間件分配給特定的路由,首先須要在bootstrap/app.php文件中調用$app->routeMiddleware()方法時爲中間件分配一個簡短的鍵:

$app->routeMiddleware([
'auth' => App\Http\Middleware\Authenticate::class,]);

一旦在HTTP內核中定義好了中間件,就能夠在路由選項內使用middleware鍵:

$router->get('admin/profile', ['middleware' => 'auth', function () {
    //
}]);

可使用數組爲路由指定多箇中間件:

$router->get('/', ['middleware' => ['first', 'second'], function () {
    //
}]);

中間件參數

中間件也能夠接受自定義傳參,例如,要在運行特定操做前檢查已驗證用戶是否具有該操做的「角色」,能夠建立RoleMiddleware來接受角色名稱做爲額外的傳參。

附加的中間件參數將會在$next參數以後被傳入中間件:

<?php
namespace App\Http\Middleware;

use Closure;

class RoleMiddleware
{
    /**
    *運行請求過濾
    *
    *@param \Illuminate\Http\Request $request
    *@param \Closure $next
    *@param string $role

    *@return mixed
    */
    public function handle($request, Closure $next, $role)
    {
        if (!$request->user()->hasRole($role)) {
            //重定向...
        }
        
        return $next($request);
    }
}

在路由中可使用冒號:來區隔中間件名稱與指派參數,多個參數可使用逗號做爲分割:

$router->put("post/{id}", ['middleware' => 'role:editor', function($id) {
    //
}]);

Terminable 中間件

有時中間件可能須要在HTTP響應發送到瀏覽器哦以後處理一些工做。例如,「session」中間件會在響應發送到瀏覽器以後將會話數據寫入存儲器中。想要作到這一點,你須要定義一個名爲「terminable」的中間並添加一個terminal方法:

<?php
    
namespace Illuminate\Session\Middleware;

use Closure;

class StartSession
{
    public function handle($request, Closure $next)
    {
        return $next($request);
    }

    public function terminate($request, $response)
    {
        //存儲session數據
    }
}

terminate方法應該同時接受和響應。一旦定義了這個中間件,你應該將它添加路由列表或者bootstrap/app.php文件的全局中間件中。

在你的中間件上條用terminite調用時,lumen會從服務器中解析出一個新的中間件實例。若是你但願在handle及terminate方法被調用時使用一致的中間件實例,只須要在容器中使用容器的singleton方法註冊中間件。

HTTP控制器

簡介

爲了替代把全部的請求處理邏輯都定義在routes.php路由文件中,你或許想要使用控制來組織這些行爲。控制器能夠把相關的請求處理邏輯整合爲一個控制器類。控制器類文件被存儲在app/HTTP/Controllers目錄下。

基礎控制器

這裏有一個基礎控制器的示例。全部lumen的控制器都應該繼承lumen安裝時內置的默認的控制器基類:

<?php

namespace App\Http\Controllers;

use App\User;

class UserController extends Controller
{
/**
 * 獲取指定 ID 的用戶
 *
 * @param  int  $id
 * @return Response
 */
public function show($id)
{
return User::findOrFail($id);
}
}

咱們能夠像下面這樣路由指向控制器的方法:

$router->get("user/{id}", "UserController@show");

如今,當請求匹配到這個特定的URL時,UserController類中的show方法就會執行。固然,路由的參數也一樣傳遞給了這個方法。

控制器和命名空間

有一點很是重要,那就是咱們要注意在定義控制器路由時,不須要指定完整的控制器命名空間。咱們只需定義「根」命名空間App\Http\Controllers以後的類名部分。默認狀況下,bootstrap/app.php文件在加載routes.php時已經把全部路由都配置到了根控制器命名空間。

若是你選擇在App\Htpp\Controllers目錄內層使用PHP命名空間嵌套或者組織控制器,只要使用相對於App\Http\Controllers根命名空間的特定名稱便可。所以,若是你的控制器類全名是App\Http\Controllers\Photos\AdminController,那麼你應該註冊一個路由,以下所示:

$router->get('foo', 'Photos\AdminController@method');

命名控制器路由

像閉包那樣,你能夠給控制器路由指定一個名稱:

$router->get('foo', ['uses' => 'FooController@method', 'as' => 'name']);

你也可使用route輔助函數,來生成指向控制器路由的URL:

$url = route('name');

控制器中間件

中間件可經過以下方式分配到路由中:

$router->get('profile', [
    'middleware' => 'auth',
    'uses' => 'UserController@showProfile'
]);

然而,更方便的方式是在控制器的構造方法裏面使用middleware方法指定中間件。你甚至能夠限制中間件只應用於該控制器類的某些方法:

class UserController extends Controller
{
/**
實例化一個新的UserController實例。
@return void
*/
public function __construct()
{
$this->middleware('auth');

$this->middleware('log', [
        'only' => ['fooAction', 'barAction']
    ]);

    $this->middleware('subscribed', ['except' => [
        'fooAction',
        'barAction',
    ]]);
}

}

依賴注入與控制器

構造器注入

lumen使用[服務容器]來解析全部的控制器的依賴注入。所以,你能夠在控制器的構造函數中使用類型提示須要的任何依賴。這些依賴會自動的解析並注入到控制器實例中:

namespace App\Http\Controllers;

use App\Repositories\UserRepository;

class UserController extends Controller
{
    /**
    *新建一個控制器實例
    *
    *@param UserRepository $users
    *@return void
    */
    public function __contruct(UserRepository $users)
    {
        $this->users = $users;
    }
}

方法注入

除了構造器注入之外,你也能夠在你的控制器方法中使用類型提示依賴。例如,在某個方法中添加Illuminate\Http\Request實例的類型提示:

<?php
    namespace App\Http\Controllers;
    use Illuminate\Http\Request;
    
    class UserController extends Controller
    {
        /**
        *保存一個新用戶
        *@param Request $request
        
        *@return Response
        */
        public function store()
        {
            $name = $request->input('name');
        }
    }

若是你想在控制器裏獲取路由參數,只須要在路由以後列出參數便可。例如,你的路由這樣來定義:
$router->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 string $id
    *@return Response
    */
    public function update(Request $request, $id)
    {
        //
    }
}

HTTP請求

獲取請求實例

要經過依賴注入的方式獲取當前HTTP請求的實例,你應該在控制器構造函數或者方法中使用
Illuminate\Http\Request類,當前請求實例將自動被服務容器注入:

<?php

namespace App\Http\Controller;

use Illuminate\Http\Request;

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

若是你的控制器方法也指望從路由參數中獲取數據,只須要將路由參數放在其餘依賴後面,好比你的路由是這樣定義的:

$router->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 string $id
    *
    *@return Response
    */
    public function update(Request $request, $id)
    {
        //
    }
}

基本請求信息

Illuminate\Http\Request 實例繼承了Symfony\Component\HttpFoundation\Request類,並提供了多種檢查HTTP請求的方法,下面是該類的幾個使用方法:

獲取請求的URI

path方法會返回請求的URI,若是請求的目標是http://domain.com/foo/bar,path方法將會返回foo/bar:

$uri = $request->path();

is方法會返回請求的URI是否與指定規則匹配,你可使用*符號做爲通配符:

if($request->is('admin/*')) {
    //
}

若是要獲取完整的URL而不是URI,可使用url或者fullURL方法:

//不包含請求參數
$url = $request->url();

//包含請求參數
$url = $request->fullUrl();

獲取請求的方法

method方法將會請求的HTTP動做,你可使用isMethod方法校驗HTTP動做是否與指定字符串匹配:

$method = $request->method();

if ($request->isMethod('post')) {
    //
}

PSR-7請求

PSR-7標準規定了HTTP消息接口包含了請求及響應,若是你想得到PSR-7的請求實例,就須要先
安裝幾個庫,laravel使用Symfony的HTTP消息橋組件,將原laravel的氫氣及響應轉換至PSR-7所支持的實現:

composer require symfony/psr-http-message-bridge

composer require zendframework/zend-diactors

安裝完這些庫後,你就能夠在路由或者控制器中,簡單的對請求類型使用類型提示來獲取PSR-7請求:

use Psr\Http\Message\ServerRequestInterface;

$router->get('/', function (ServerReuestInterface $request) {
    //
});

若是你從路由或者控制器反悔了一個PSR-7的響應實例,那麼它會被框架自動轉換爲laravel的響應實例並顯示。

獲取輸入數據

獲取指定輸入值

你能夠經過Illuminate\Http\Request實例,使用幾個簡單的方法來獲取全部的用戶輸入數據,而不須要擔憂請求的HTTP動做,由於它們的獲取方式是相同的:

$name = $request->input('name');

你能夠在input方法的第二個參數中傳入一個默認值,當請求參數不存在時,就會返回默認值:

$name = $request->input('name', 'Sally');

當數據是以數組形式輸入時,你可使用「點」符號來獲取數組:

$name = $request->input('products.0.name');

$name = $request->input('products.*.name');

確認輸入值是否存在

你能夠經過has方法判斷輸入值是否存在,輸入值存在時has方法將會返回true:

if($request->has('name')) {
    //
}

當給定一個數組時,has方法將確認是否全部指定值都存在:

if ($request->has(['name', 'email'])) {
    //
}

若是你想肯定請求中是否存在值而且不爲空,可使用filled方法:

if($request->filled('name')) {
    //
}

獲取全部輸入數據

你可使用all方法以數組形式獲取全部的輸入數據:

$input = $request->all();

獲取部分輸入數據

若是你想獲取數據的子集,你能夠是only和except方法,這兩個方法都接受單個數組或者動態列表做爲參數:

$input = $request->only(['username', 'password']);

$input = $request->only('username', 'password');

$input = $request->except(['credit_card']);

$input = $request->except('credit_card');

文件上傳

獲取上傳文件

你可使用Illuminate\Http\Request實例中的發file方法獲取上傳的文件,file方法返回的對象是Symfony\Component\HttpFoundation\File\UploadFile類的實例,這個類繼承了PHP的SplFileInfo類,而且提供了多種與文件交互的方法:

$file = $request->file('photo');

你可使用hasFile方法確認上傳的文件是否存在:

if ($request->hasFile('photo')) {
    //
}

驗證上傳是否成功

除了檢查文件是否存在以外,你還能夠經過isValid方法驗證上傳是否存在問題:

if ($request->file('photo')->isValid()) {
    //
}

移動上傳文件

要將上傳的文件移動到新的位置,你應該使用move方法,這個方法會將文件從臨時位置(由PHP配置決定)移動到你指定永久存儲位置:

$request->file('photo')->move($destinationPath);

$request->file('photo')->move($destinationPath, $fileName);

其餘上傳文件方法

UploadFile實例還有不少其餘可用的方法,能夠到該類的API文檔瞭解這些方法的詳細信息。

HTTP響應

基本響應

固然,全部的路由及控制器必須返回某個類型的響應,併發送回用戶的瀏覽器。laravel提供了集中不一樣的方法來返回響應。最基本的響應就是從路由或者控制器簡單的返回一個字符串:

$router->get('/', function () {
    return 'Hello World';
});

指定的字符串會被框架自動轉爲HTTP響應。

響應對象

可是,對於大多數路由和控制器行爲操做,你將返回完整的Illuminate\Http\Response實例。返回完整的Response實例容許你自定義響應的HTTP狀態碼和標題。一個Response實例繼承自Symfony\Componet\HttpFoundation\Response類,而且提供了多種構建HTTP響應的方法:

use Illuminate\Http\Response;

$router->get('home', function () {
    return (new Response($content, $status))
        ->header('Content-Type', $value);
});

爲了方便起見,你可使用response輔助函數:

$router->get('home', function () {
    return response($content, $status)
        ->header('Content-Type', $value);
});

注意:有關Response方法的完整列表能夠參考API文檔一級Symfony api文檔。

附加標頭至響應

大部分的響應方法是能夠鏈式調用的,折讓你能夠順暢的建立響應。舉例來講,你能夠在響應發送給用戶以前,使用header方法增長一系列的標頭至響應:

return response($content)
    ->header('Content-Type', $type)
    ->header('X-header-One', 'header Value')
    ->header('X-Header-Two', 'header Value');

或者你可使用withHeaders方法來設置數組標頭:
return response($content)
->withHeaders([
'Content-Type' => $type,
'X-header-One' => 'Header Value',
'X-header-Two' => 'Header Value',
]);

其餘響應類型

使用輔助函數response能夠輕鬆的生成其餘類型的響應實例、當你調用輔助函數response而且不帶任何參數時,將會返回Laravel\Lumen\Http\ResponseFactory contract的實現。此Contract提供了一些有用的方法來生成響應。

JSON響應

json方法會自動將標頭的Content-Type設置爲application/json。而且經過PHP的接送_encode函數將制定的數組轉換爲json:

return response()->json(['name' => 'Abigail', 'state' => 'CA']);

你能夠選擇提供一個狀態碼和一個額外的標題數組:

return response()->json(['error' => 'Unauthorized'], 401, ['X-Header-One' => 'Header Value']);

若是你想建立一個JSONP響應,則可使用json方法並加上setCallback方法:

return response()
    ->json(['name' => 'Abigail', 'state' => 'CA'])
    ->setCallback($request->input('callback'));

文件下載

download方法能夠用於生成強制讓用戶的瀏覽器下載指定路勁文件的響應。download方法接受文件名稱做爲方法的第二個參數,此名稱爲用戶下載文件時看見的文件名稱。最後,你能夠傳遞一個標頭的數組做爲第三個參數傳入該方法:

return reponse()->download($pathToFile);

return response()->download($pathToFile, $name, $headers);

注意:管理文件下載的擴展包Symfony HTTPFoundation,要求下載文件必須是ASCII文件名。

重定向

重定向響應是類illuminate\Http\RedirectResponse的實例,而且包含用戶要重定向至另外一個URL所需的正確標頭。有幾種方法能夠生成RedirectResponse的實例。最簡單的方法就是經過redirect輔助函數:

$router->get('dashboard', function () {
    return redirect('home/dashboard');
});

重定向至命名路由

當你調用redirect輔助函數而且不帶任何參數時,將會返回laravel\Lumen\Http\Redirecotr的實例,你能夠對該Redirector的實例調用任何方法。舉個例子,要生成一個RedirectResponse到一個命名路由,你可使用route方法:

return redirect()->route('login');

若是你的路由有參數,則能夠將參數放進route方法的第二個參數,以下:

//For a route with follwing URI:profile/{id}
return redirect()->route('profile', ['id' => 1]);

若是你要重定向至路由而且路由的參數爲Eloquent模型的[ID],則能夠直接將模型傳入,ID將會自動被提取:

return redirect()->route('profile', [$user]);

用戶認證

簡介

lumen雖然與laravel使用了相同的底層類庫實現,可是因lumen面向的是無狀態API的開發,不支持session,因此默認的配置不一樣。lumen必須使用無狀態的機制來實現認證,如api令牌(Token)。

開始

認證服務提供者

注意:在使用lumen的認證功能前,請取消bootstrap/app.php文件中的AuthServiceProvider調用代碼的註釋。

AuthServiceProvider存放在app/Providers文件夾中,此文件中只有一個Auth::viaRequest調用。viaRequest會在系統須要認證的時候被調用,此方法接受一個Closure(匿名函數)參數。在此closure(匿名函數)內,你能夠任意的解析App\User並返回,或者在解析失敗時返回null:

$this->app['auth']->viaRequest('api', function ($request) {
    //返回User或者null...
});

一樣,你可使用你指望的方式取得用戶認證,好比在請求頭或者查詢字符串中使用api令牌、請求中的bearer令牌,或者使用應用程序須要的任何其餘方法。

若是你的項目沒有使用Eloquent,你須要返回一個Illuminate\Auth\GenericUser類的實例。這個類接受一個屬性數組做爲構造函數的惟一參數:

use Illuminate\Auth\GenericUser;

return new GenericUser(['id' => 1, 'name' => 'Taylor']);

緩存

簡介

laravel爲各類緩存系統提供了統一的api。緩存配置位於.env文件中。在該文件中你能夠指定應用默認使用哪一個緩存驅動。laravel支持當前流行的後端緩存,例如memcached和Redis。

不一樣於laravel

lumen緩存驅動與laravel緩存驅動使用了徹底相同的代碼。除配置以外,在lumen中使用緩存和在laravel中使用緩存沒有區別;所以,請參閱laravel文檔來獲取使用示例。

注意:在使用cache facade以前,請確保在bootstrap/app.php文件中沒有註釋掉$app->withFacaes()方法的調用。

Redis支持

在使用lumen的Redis緩存以前,你須要經過composer安裝illuminate/redis(5.5.*)包。而後,你須要在bootstrap/app.php文件中註冊illuminate\Redis\RedisServiceProvider。

若是你沒有在bootstrap/app.php文件中調用$app->withEloquent(),那麼你應該在bootstrap/app.php文件中調用$app->configure('database');以確保正確加載Redis數據庫配置。

緩存

簡介

laravel爲各類緩存系統提供了統一的api。緩存配置位於.env文件中。在該文件中你能夠指定應用默認使用哪一個緩存驅動。laravel支持當前流行的後端緩存,例如Memcached和Redis。

不一樣於laravel

lumen緩存驅動與laravel緩存驅動使用了徹底相同的代碼。除配置以外,在lumen中使用緩存和在laravel中使用緩存沒有區別;所以,請參閱laravel文檔來獲取使用示例。

注意:在使用Cache Facade以前,請確保在bootstrap/app.php文件中沒有註釋掉$app->withFacdes()方法的調用。

Redis支持

在使用lumen的Redis緩存以前,你須要經過composer安裝illuminate/redis(5.5.*)包。而後,你須要在bootstrap/app.php文件中註冊illuminate\Redis\RedisServiceProvider。

若是你沒有在bootstrap/app.php文件中調用$app->withEloquent()。那麼你應該在bootstrap/app.php文件中調用$app->configure();以確保正確加載Redis數據庫配置。

數據庫

配置

lumen讓鏈接數據庫和執行查詢變得很是簡單。目前lumen支持四種數據庫系統:MySQL,Postgres,SQLite和SqlServer。

你能夠在.env配置文件中使用DB_*選項配置數據庫設置,例如數據庫驅動、host、用戶名和密碼。

基本用法

注意:若是你想使用DB facade,你應該去掉在bootstrap/app.php文件中$app->withFacades()的調用的註釋。

例如,在不啓用facades時,你能夠經過app輔助函數鏈接數據庫:

$result = app('db')->select("SELECT * FROM users");

或者,在啓用facades後,你能夠經過DB facade來鏈接數據庫:

$result = DB::select("SELECT * FROM users");

基本查詢

要了解如何經過數據庫組件執行基本的原始SQL查詢,請參考laravel文檔

查詢構造器

lumen一樣支持Eloquent ORM的流式查詢構造器。要了解這個特性的更多信息,請參閱laravel文檔。

Eloquent ORM

若是你喜歡使用Eloquent ORM,你應該去掉bootstrap/app.php文件中對$app->withQloquent()調用的註釋。
固然,你能夠在lumen中很是容易的使用完整的Eloquent ORM。要了解如何使用Eloquent,請參考laravel文檔。

遷移

關於如何建立數據庫表和執行遷移的更多文檔,請參考laravel文檔中的遷移。

加密與解密

配置

在使用lumen的加密以前,你應該先把.env文件中APP_KEY選項設置爲32位隨機字符串。若是沒有適當地設置這個值,全部被lumen加密的值都將是不安全的。

基本用法

加密一個值

你可使用crypt門面來加密一個值。全部的加密值都使用OpenSSL和AES-256-CBC來進行加密。此外,全部加密過的值都會使用消息認證碼(MAC)來進行簽名,以檢測加密字符串是否被篡改過:

例如,咱們可使用encrypt方法加密機密信息,並把它保存在Eloquent模型:

<?php
namespace App\Http\Controllers;

use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Crypt;

class UserController extends Controller
{
    /**
    * 保存用戶的機密信息。
    * @param Request $request
    * @param int $id
    * @return Response
    */
    public function storeSecret(Request $request, $id)
    {
        $user = User::findOrFail($id);
        
        $user->fill([
            'secret' => Crpty::encrypt($request->secret)
        ])->save();
    }
}

加密一個值

固然,你可使用crypt門面的decrypt方法來解密值。若是該值不可以被正確的解密。例如當MAC(消息認證碼)無效時,就會拋出異常Illuminate \Contracts\Encryption\DecryptException:

use Illuminate\Contracts\Encryption\DecryptException;

try{
    $desrypted = Crypt::decrypt($encryptedValue);
}catch (DecryptException $e){
    //
}

錯誤與日誌

簡介

當你開始一個新的Lumen項目時,lumen就已經幫你配置好錯誤和異常處理的操做。另外,lumen也集成了Monolog日誌函數庫,Monolog支持和提供多種強大的日誌處理功能。

有關錯誤的更多信息,請參閱完整的laravel錯誤文檔。
有關日誌的更多信息,請參閱完整的laravel的日誌文檔。

錯誤處理

介紹

當你啓動一個新的laravel項目時,錯誤及異常處理是已爲你配置好了的。
App\Exceptions\Handler類負責記錄應用程序觸發的全部異常並呈現給用戶。在本文檔中,咱們將深刻探討這個類。

配置

你的config/app.php配置文件中的debug選項決定了對於一個錯誤實際上講顯示多少信息給用戶。默認狀況下,該選項的設置將遵循存儲在.env文件中的APP_DEBUG環境變量的值。

對於本地開發,你應該將APP_DEBUG環境變量的值設置爲true。在生產環境中,該值贏始終未false。若是在生產將該值設置爲true,則可能會將敏感配置暴露給應用程序的最終用戶。

異常處理器

report方法

全部異常都是由App\Exceptions\Handler類處理。這個類包含兩個方法:report和rendor。咱們將詳細剖析這些方法。report方法用戶記錄異常或將它們發送給如Bugsnag或者Sentry等外部服務。默認狀況下,report方法將異常傳遞給記錄異常的基類。不過,你能夠任何本身喜歡的方式來記錄異常。

例如,若是你須要以不一樣方式報告不一樣類型的異常,則可使用PHP的instanceof比較運算符:

/**
*報告或者記錄異常
*
*此處是發送異常給sentry、Bugsnag等外部服務的好位置。
*
*@param \Exception $exception
*@return void
*/
public function report()
{
    if ($exception instance CustomException) {
        //
    }
    return parent::report($exception);
}

{tip}不要在report方法中進行太多的instanceof檢查,而應該考慮使用[可報告異常(reportable exception)]
{(/docs/laravel/5.7/errors#renderable-exceptions)}。

Report輔助函數

有時你可能須要報告異常,但又不但願終止當前請求的處理。report輔助函數容許你使用異常處理器的report方法在不顯示錯誤頁面的狀況下快速報告異常:

public function isValid()
{
    try{
    }catch(Exception $e){
        report($e);
        return false;
    }
}

按類型忽略異常

異常處理器的$dontReport屬性包含一組不會被記錄的異常類型。例如,由04錯誤致使的異常一級其餘幾種類型的錯誤不會寫入日誌文件。你能夠根據須要添加其餘異常類型到此數組中:

/**
*不該被報告的異常類型清單。
*
*@var array
*/
protected $dontReport = [
    \Illuminate\Auth\AuthenticationException::class,
    \Illuminate\Auth\Access\AuthorizationException::class,
    \Symfony\Component\HttpKernel\Exception\HttpException::class,
    \Illuminate\DataBase\Eloquent\ModelNotFoundException::class,
    \Illuminate\Validation\ValidationException::class,
];

Render方法

Rendor方法負責將給定的異常轉換爲將被髮送回瀏覽器的HTTP響應。默認值狀況下,異常將傳遞給你生成響應的基類。不過,你能夠按本身意願檢查異常類型或者返回本身的自定義響應:

/**
*將異常1轉換爲HTTP響應。

  • @param \Illuminate\Http\Request $request
    @param \Illuminate\Exception $exception
    @return \Illuminate\Http\Response
    /
    public funtion render($request, Exception $exception)
    {
    if ($exception instanceof CustomException) {
    return response()->view('errors.custom', [], 500);
    }

return parent::render($request, $exception);
}

Reportable & Renderable 異常

除了在異常處理器的report和render方法中檢查異常類型,你還能夠直接在定義異常上定義report和render方法。當定義了這些方法時,它們會被框架自動調用:

<?php
namespace App\Exceptions;
use Exception;
class RenderException exteds Exception
{
/**
* 報告異常

@return void
*/
public function report()
{
//
}

/**
     * 轉換異常爲 HTTP 響應
     *
     * @param  \Illuminate\Http\Request
     * @return \Illuminate\Http\Response
     */
    public function render($request)
    {
        return response(...);
    }
}

HTTP異常

一些異經常使用描述產生自服務器的HTTP錯誤代碼。例如,[頁面未找到]錯誤(404),【未經受權的錯誤】(401),甚至能夠是開發人員引發的500錯誤。你可使用abort輔助函數從應用程序的任何地方生成這樣的響應:

abort(404);

輔助函數abort會當即引起一個由異常處理器渲染的異常。你還能夠選擇性地提供響應文本:
abort(403, 'Unauthorized action.');

自定義HTTP錯誤頁面

laravel能夠輕鬆顯示各類HTTP狀態代碼的自定義錯誤頁面。例如,若是你但願自定義404HTTP狀態碼的錯誤頁面,能夠建立一個resources/views/errors/404.blade.php視圖文件。該文件將被用於你的應用程序產生的全部404錯誤。此目錄中的視圖文件的命名應匹配它們對應的HTTP狀態碼。由abort函數引起的HTTPException實例將做爲$exception變量傳遞給視圖:

{{ $exception->getMessage() }}

日誌

簡介

爲了幫助你更多的瞭解應用程序中到底發生了什麼,laravel提供了強大的日誌服務,容許你將日誌消息,系統錯誤日誌記錄到文件,甚至使用slack通知到你的整個團隊。

在laravel框架中,laravel使用monolog庫,它爲各類強大的日誌處理提供支持。laravel使用配置這些處理程序變得簡單,容許泥混合並匹配它們自定義的應用程序日誌處理。

配置

全部的應用程序日誌系統配置都位於config/logging.php配置文件中。這個文件容許你配置你的應用程序日誌通訊,
因此務必查看每一個可用的通訊及它們的選項。固然,咱們將在下面回顧一些經常使用的選項。

默認狀況下,laravel將使用stack去記錄日誌消息。stack通道被用來將多個日誌通道聚合到一個單一的通道中。關於堆棧的更多信息,查看如下文檔。

配置通道名稱

默認強狂下,monolog使用與當前環境匹配的【通道名稱】進行實例化,好比production或者local。要改變這個值,需添加一個name選項到你的通道配置中:

'stack' => [
    'driver' => 'stack',
    'name' => 'channel-name',
    'channels' => ['single', 'slack'],
];

可用的通道驅動

名稱 描述
single 一個便於建立[多通道]通道的包裝器
daily 單個文件或者基於日誌通道的路徑(StreamHandler)
slack 一個天天輪換的基於monolog驅動的RotatingFileHandler
syslog 一個基於monolog驅動的sysloghandler
errorlog 一個基於monolog驅動的errorlogHandler
monolog 一個能夠任何支持monolog處理程序的monolog工廠驅動程序
custom 一個調用指定工廠建立通訊通道的驅動程序

{tip}有關monolog和custom驅動,查看高級通道自定義

配置slack通道

slack通道須要url配置選項。這個URL應當與你爲slack團隊配置的一個incoming webhook相匹配。

構建日誌棧

如前所述,stack驅動容許你將多個通道合併到一個單一日誌通道中。爲了說明如何使用日誌棧,讓咱們看一個你可能在生產應用配置中看到的實例配置:

'channels' => [
    'stack' => [
        'driver' => 'stack',
        'channels' => ['syslog', 'slack'],
    ],
        
    'syslog' => [
        'driver' => 'slack',
        'url' => env('LOG_SLACK_WEBHOOK_URL'),
        'username' => 'Laravel Log',
        'emoji' => ':boom:',
        'level' => 'critical',
    ],
],

讓咱們剖析這個配置。首先,注意咱們的stack通道經過它的Channels選項聚合其它兩個通道:syslog和slack。所以,當記錄日誌消息時,這兩個通道都有機會去記錄日誌消息。

日誌級別

注意上面實例中在syslog和slack通道配置中存在的level配置選項。這個選項決定了一個消息必須被通道記錄的最小[level]。monolog爲laravel的日誌服務提供了RFC-542規範中定義的全部日誌級別:emergency,
alert,critical,error,warning,notice,info和debug。

所以,假設咱們記錄一個日誌消息使用debug方法:

Log::debug('An informational message.');

根據咱們的配置,syslog通道將寫消息到系統日誌;然而,因爲錯誤消息不是critical或者這個級別之上,它將不被髮送到slack。可是,若是咱們記錄一個emergency消息,它將被同時發送到系統日誌和slack,由於emergency級別高於咱們對兩個通道最低級別的閾值:

Log::emergency('The system is down!');

記錄日誌消息

你能夠經過Log外觀類將信息寫入到日誌。如前所述,日誌器提供在RPC 5424規範中定義的八個日誌級別:

emergency,alert,critical,error,warning,notice,info和debug:

Log::emergency($message);
Log::alert($message);
Log::critical($message);
Log::error($mesage);
Log::warning($message);
Log::notice($message);
Log::info($message);
Log::debug($message);

所以,你能夠調用這些方法中的任何一個去記錄相應級別的一個日誌消息。默認狀況下,消息將寫入到你的config/logging.php配置文件配置的默認日誌通道中:
<?php
namespace App\Http\Controllers;

use App\User;
use Illuminate\Support\Facades\Log;
use App\Http\Controllers\Controllers;

class UserController extendx Controller
{
/**
* Show the profile for the given user.

@param int $id
* @return Response
*/
public function showProfile($id)
{
Log::info('Showing user profile for user: '.$id);

return view('user.profile', ['user' => User::findOrFail($id)]);
}

}

記錄日誌到指定通道

有時候你可能但願將日誌記錄到非默認通道。你可使用log facade中的channel方法,將日誌記錄到應用配置中存在的任何聚到:

Log::channel('stack')->info('Something happened!');

若是你想按須要建立多個渠道的日誌堆棧,你可使用stack方法:

Log::stack(['single', 'slack'])->info("Something happened!");

先進的monolog日誌通道定製

自定義monolog日誌通道

首先你可能須要徹底配置monolog現有的通道。例如:你想要爲現有通道自定義一個monolog formatterInterface實現。

首先,在頻道配置文件中定義一個tap數組。tap數組應該該包含所需的類列表,這些類就是Monolog實例建立後須要自定義(或者開發)的類:

'single' => [
'driver' => 'single',
'tap' => [],],

事件

簡介

lumen事件提供了簡單的監聽器實現,容許你訂閱和監聽事件,事件類一般被保存在app/Events目錄下,而它們的偵聽器被保存在app/Listeners目錄下。

與laravel的差別

一般,lumen中的事件方法剛好與laravel全棧框架功能一致,因此,請閱讀完整的laravel文檔。lumen一樣支持事件廣播,它容許客戶端的JavaScript監聽服務器的事件。然而,這裏仍是有些差別值得談論。

生成器

lumen中沒有能夠用來生成事件和監聽器的命令,你能夠經過簡單賦值ExampleEvent或者ExampleListener文件來定義你本身的事件和監聽器,這兩個示例文件提供了每一個事件和監聽器的基礎類結構。

註冊事件或者監聽器

像laravel框架同樣,lumen應用內置的EventServiceProvider提供了一個註冊全部事件監聽器的地方。listen屬性一個數組,它包含了全部的事件(鍵)和監聽器(值)。因此,你能夠根據應用程序的須要添加事件到這個數組:

/**
*應用程序的事件監聽器映射。
*
*@var array
*/
protected $listen = [
    'App\Events\ExampleEvent => [
        'App\Listeners\ExampleListener',
    ],
];

觸發事件

你可使用event輔助函數或者event門面在lumen應用程序中觸發事件。一樣,這些函數的行爲與laravel框架一致:

event(new ExampleEvent);

Event::dispatch(new ExampleEvent);

隊列

簡介

lumen的隊列服務給不一樣的後端隊列提供統的API。隊列容許你延遲處理消失的任務,例如在遠程服務器上執行任務直到更晚的時間,而同一時間你的應用程序能夠快速的處理web應用程序的請求。

就像該框架的許多其餘部分同樣,lumen的隊列服務跟laravel的隊列服務功能相同。所以,若是要了解更多關於lumen的隊列,則能夠參閱laravel消息隊列文檔。

配置

隊列配置選項對話都在.env文件中。

若是您想要徹底自定義的配置,必須您將vendor/laravel/lumen-framework/config/queue.php文件完整的複製到你的項目目錄根中config目錄,而且要調整必要的配置。若是config目錄不存在,則要建立。

驅動程序先決條件

數據庫

使用爲了database隊列驅動程序,您將須要數據庫表保存做業和失敗狀況:

Schema::create('jobs', function (Blueprint $table) {
    $table->bigIncrement('id');
    $table->string('queue');
    $table->longText('payload');
    $table->tinyInteger('attempts')->unsigned();
    $table->unsignedInteger('reserved_at')->nullable();
    $table->unsignedInteger('available_at');
    $table->unsignedInteger('created_at');
    $table->index(['queue', 'reserved_at']);
});


Schema::create('failed_jobs', function (Blueprint $table) {
    $table->increment('id');
    $table->text('connection');
    $table->text('queue');
    $table->longText('payload');
    $table->longText('exception');
    $table->timestamp('failed_at')->useCurrent();
});

Redis的

要想使用Redis隊列驅動程序,須要先經過composer安裝illuminate/redis(5.5.*)擴展包。而後再bootstrap/app.php文件中註冊Illuminate\Redis\RedisServiceProvider;

其餘隊列驅動程序的依賴包

下面列出其餘隊列驅動程序所須要的依賴擴展包:
亞馬遜SQS:aws/aws-sdk-php ~3.0
Beanstalked:pda/pheanstalk ~3.0

與laravel的差別

與框架的許多其餘部分同樣,lumen隊列做業的功能與laravel的隊列做業功能相同。所以,要了解lumen隊列做業功能,請查看完整的laravel隊列文檔。

不過呢,咱們如今講討論兩個框架間的一些細微差別。首先,咱們來談談lumen中如何生成隊列做業。

生成器

lumen不包括用於自動建立新job類的生成器。所以你須要賦值框架所帶的exampleJob類。這個類提供了每一個job類共享的基本結構。examplejob所繼承的job基類已包含所需的interactswithqueue,queueable和serializesmodels特性:

<?php

namespace App\Jobs;

class ExampleJob extendx Job
{
/**

  • 建立一個新的做業實例。
  • @return void
    */
    public function __construct()
    {
    //
    }

/**

  • 執行做業。
  • @return void
    */
    public function handle()
    {
    //
    }
    }

調度做業

再次重申,你應該查閱完整的laravel文檔以獲取有關調節隊列做業的完整信息;和laravel框架同樣,你可使用dispatch函數從lumen應用程序中的任意位置調度做業:

dispatch(new ExampleJob);

固然,你也可使用Queue facade。若是你選擇使用facade,請務必在bootstrap/app.php文件中取消對$app->withFacades()調用的註釋:

Queue::push(new ExampleJob);

服務容器:

簡介

laravel的服務容器是一個管理類依賴和執行依賴注入的強力工具。依賴注入是個花俏的名字,事實上是指:類的依賴經過構造器或者在某些狀況下經過【setter】方法【注入】。

與laravel的差別

lumen使用了與laravel框架相同的服務器。因此,你可使用它們全部強大的功能。有關容易的完整文檔,請閱讀laravel容器文檔。

獲取服務容器

laravel\lumen\application實例是Illuminate\Container\Container的擴展,因此你能夠當作服務容器來使用。
一般咱們會在服務提供者註冊咱們的容器解析規則。固然,你可使用bind、singleton’instance、以及容器提供的其餘方法。請記住,全部這些方法都記錄在laravel服務器容易文檔中。
解析實例

想要從服務容器中解析實例,你能夠在大部分的功能類裏自動解析(依賴注入),如路由closure,控制器的構造方法、控制器方法、中間件、事件監聽器,或者隊列等。或者,你也能夠在應用程序中的任何地方使用App函數來進行解析:

$instance = app(Something::class);

服務提供者

簡介
服務提供者是全部lumen應用程序啓動的中心所在。包括你本身的應用程序,以及全部的核心服務,都是服務提供者啓動的。

可是,咱們所說的啓動值得是什麼?通常而言,咱們指的是註冊事物,包括註冊服務容易綁定、事件偵聽器、中間件,甚至路由、服務提供者設置你的應用程序的中心所在。

若你打開lumen的bootstrap/app.php文件,你將會看到$app->register()方法的調用。你也許須要額外的調用來註冊你的服務提供者。

編寫服務提供者

全部的服務提供者都集成了illuminate\Support\ServiceProvider這個類。這個抽象類要求你在你的提供者上定義至少一個方法:register。在register方法內,你應該只須要將事物綁定到服務容器中。永遠不要試圖在register方法中註冊任何事件偵聽器,路由或者任何其餘功能。

註冊方法

如前面所講,在register方法中,你只要將事物綁定到【服務容器中】。永遠不要試圖在register方法中註冊任何事件偵聽器、路由或者任何其它功能。不然,你有可能會之外的使用到還沒有加載的服務提供者提供的服務。

如今,讓咱們來看一個基本的服務提供者代碼:

<?php

namespace App\Providers;

use Riak\Connection;
use Illuminate\Support\ServiceProvider;

class RiakServiceProvider extends ServiceProvder
{
    /**
    *註冊綁定到容器中
    *
    *@return void
    */
    public function register()
    {
        $this->app->singleton(Connection::class, function ($app) {
            return new Connection(config('riak'));
        });
    }
}

這個服務提供者自定義了一個register方法,而且用這個方法在服務容器中綁定了Riak\Connection的一個實例。若是你不是很瞭解服務容器的運行原理,請查看[its documentation]。

啓動方法

那麼,若是咱們要在服務提供者當中註冊一個視圖組件呢?這應該在boot方法內完成。此方法在全部其餘服務提供者都註冊以後才能調用,也就意味着能夠訪問已經被框架註冊的全部服務:

<?php
namespace App\Providers;

use Queue;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvier
{
    //其餘服務提供者屬性。。。
    /**
    *引導任何應用程序服務。
    *@return void
    */
    public function boot()
    {
        Queue::failing(function ($envent) {
            
        });
    }
}

註冊服務提供者

全部的服務提供者在bootstrap/app.php文件中被註冊。這個文件中包含對$app->register()方法調用。你也行須要額外的調用$app->register()來註冊你的服務提供者。

測試

簡介

lumen在建立時就已考慮到測試部分。事實上,lumen默認就支持用PHPunit來作測試,併爲你的應用程序建立好了phpunit.xml文件。框架還提供了一些便利的輔助函數,讓你能夠更直觀的測試應用程序的json響應。

測試環境

在運行測試時,lumen自動配置講緩存驅動配置爲array,意味着在測試的時候不會保存任何的緩存數據。

你能夠隨意建立其餘必要的測試配置環境。testing的環境變量能夠在phpunit.xml文件中進行修改;

定義和運行測試

要建立一個測試用例,直接將新的測試文件建立到tests文件夾下便可。測試文件必須繼承TestCase。接着就能夠像日常使用PHPunit同樣來定義測試方法。要運行測試只須要在命令行上運行PHPunit命令便可:

<?php

class FooTest extends TestCase
{
    public function testSomethingIsTrue()
    {
        $this->assertTrue(true);
    }
}

注意:若是要在你的類自定義setUp方法,請確保調用了parent::setUp。

應用測試

lumen提供了一個很是好用的api,使用它用來向你的應用發起HTTP請求,並查看輸出結果。

測試json api接口

lumen一樣提供了幾個測試用於測試json api接口和響應數據的助手。例如,get,post,put,patch和delete方法能夠被用於發起各類HTTP請求方式,而且聲明以json格式返回一個指定的數組:

<?php
    
class ExampleTest extends TestCase
{
    /**
    *一個簡單的測試例子
    *
    *@return void
    */
    public function testBasicExample()
    {
        $this->json('POST', '/user', ['name' => 'Sally']);
            ->seeJson([
                'created' => true,
            ]);
    }
}

seeJson方法數組轉換爲json,並驗證這個json片斷髮生在應用返回的整個json響應的任意位置。因此,即便在json響應中存在其餘屬性,只要指定的片斷存在,這個測試任然會成功!

驗證徹底匹配的json

若是你想驗證傳入的數組是否與應用程序返回的json徹底匹配,你能夠用seeJsonEquals方法:
<?php

class ExampleTest extendx TestCase
{
    /**
    *一個簡單的測試例子
    *
    *@return void
    */
    public function testBasicExample()
    {
        $this->post('/user', ['name' => 'Sally'])
            ->seeJsonEquals([
                'created' => true,
            ]);
    }
}

認證

actingAs輔助函數提供了簡單的方式來讓指定的用戶認證爲當前的用戶:
<?php

class ExampeTest exntends TestCase
{
    public function testApplication()
    {
        $user = factory('App\User')->create();
        $this->actingAs($user)
            ->get('/user');
    }
}

自定義HTTP請求

若是你想要建立一個自定義的HTTP請求到應用程序上,並獲取完整的 Illuminate\Http\Response對象,可使用call方法:

public function testApplication()
{
    $response = $this->call('GET', '/');
    $this->assertEquals(200, $response->status());
}

若是你想構造POST,PUT,或者PATCH請求,能夠在請求時傳入一個數組做爲請求參數,固然,你也能夠在路由及控制器中經過請求實例來獲取傳過來的參數:

$response = $this->call('POST', '/user', ['name' => 'Taylor']);

使用數據庫

爲了使得測試使用了數據庫的應用更加簡便,lumen提供了各類有用的工具。首先,你可使用seeInDatabase助手函數來斷言數據庫中是否存在給定條件的數據。例如,咱們想要驗證users表中的有一條email的值爲Sally@example.com的記錄,咱們能夠按以下操做:

public function testDatabse()
{
    //Make call to application...
    
    $this->seeInDatabase('users', ['email' => 'sally@foo.com']);
}

固然,seeInDatabase方法和相似的助手方法就是會爲了方便使用。你也能夠在測試中自由使用PHPunit的內置斷言方法。

每次測試以後重置數據庫

在每次測試後重置數據庫時很是有必要的,這樣以前的測試數據不會響應後面的測試。

使用遷移

有一個選擇是每次測試以後回滾數據庫,而且在下一次測試以前將其遷移。lumen提供了一個簡單的DatabaseMigrations特性,它能夠自動位您處理。簡單的在您的測試類中運用這個特性以下:

<?php

use Laravel\Lumen\Testing\DatabaseMigrations;
use Laravel\Lumen\Testing\DatabaseTransactions;

class ExampleTest extends TestCase
{
    use DatabaseMigrations;
    
    /**
    *A basic functional test example.
    *
    *@return void
    */
    public function testBasicExample()
    {
        $this->get('/foo');
    }
}

使用事務

另外一個選擇是將每個測試用例包裝在數據庫事務中。擼們提供了便利的DatabaseTransactions特性,能夠爲您自動的執行這些:

<?php

use Laravel\Lumen\Testing\DatabaseMigrations;
use Laravel\Lumen\Testing\DatabaseTransactions;

class ExampleTest extends TestCase
{
use DatabaseTransactions;
/**
A basic functional test example


/
}

模型工廠

在測試時,在執行測試以前咱們須要將少許的數據插入到數據庫中很常見的。當建立這些數據的時候,lumen不會手動指定這些列的值。而是容許您使用「factories」爲每一個Eloquent models定義一組默認屬性。首先,在您的應用中看看database/factories/ModelFactory.php文件。這個文件包含一個工廠定義:

$factory->define('App\User', function ($faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->email,
    ];
});

在做爲工廠定義的閉包中,您能夠返回模型上全部屬性的默認測試值。閉包將接收Faker PHP庫的一個實例,它將容許您便利的生成各類隨機數據以方便測試。

固然,您能夠將您本身的額外的工廠添加到ModelFactory.php文件中。

多種工廠類型

有時您可能但願同一個Eloquent模型有多種工廠。例如,可能您會但願除了普通的用戶以外還有管理員用戶的工廠。您可能會使用defineAs方法定義這些工廠:

$factory->defineAs('App\User', 'admin', function ($faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->email,
        'admin' => true,
    ];
});

您可使用raw方法檢索其基本屬性,而不是複製基本用戶工廠中的全部屬性。一旦擁有這些屬性,只須要使用您須要的任何附加值補充它們:

$factory->defineAs('App\Users', 'admin', function ($faker) use ($factory) {
    $user = $factory->raw('App\User');
    return array_merge($user, ['admin' => true]);
});

在測試中使用工廠

在工廠定之後,就能夠在測試或者是數據庫的填充文件中,經過全局的factory函數來生成模型實例。接着讓咱們先來看看幾個建立模型的例子。首先咱們會使用make方法建立模型,但不將他們保存至數據庫:
public function testDatabase()
{
$user = factory('App\User')->make();
}

若是你想要寫模型中的某些默認值,則能夠傳遞一個包含數值的數組至make方法。只有指定的數值會被替換,其餘剩餘的數值則會安裝工程指定的默認值來設置:

$user = factory('App\User')->make([
'name' => 'Abigail',]);

你還能夠建立許多模型的集合或者建立給定類型的模型:

//Create three App\User isntance...

$users = factory('App\User', 3)->make();

//Create an App\User "admin" instance...
$user = factory('App\User', 'admin')->make();

//Create three App\User "admin" instances...
$users = factory("App\User", 'admin', 3)->make();

維持工廠模式
可使用create方法建立模型實例,還可使用save方法將數據保存到數據庫:

public function testDatabase()
{
    $user = factory("App\User")->create();
    // Use model in tests...
}

一樣,你也可使用數組的方式使用create方法將數據寫入模型

$user = factory('App\User')->create([
    'name' => 'abigail',
]);

添加關聯至模型

你甚至能夠保存多個模型到數據庫上。在本例中,咱們還會增長關聯至咱們所建立的模型。當使用create方法建立多個模型時,它會返回一個Eloquent集合實例,讓你能使用集合提供的便利方法,例如each方法:
$users = factory('App\User', 3)
->create()
->each(function ($u) {
$u->posts()->save(factory('App\Posts')->make);
});

模擬
模擬事件
若是你大量地使用lumen的事件系統,你可能會但願在測試中止或者模擬某些事件。例如,若是你在測試你的註冊功能,你可能不但願全部的UserRegistered事件被觸發,由於它們會觸發「歡迎」郵件的發送。

lumen提供了簡單的expectsEvents方法,以驗證預期的事件有沒有被運行,可防止該事件的任何處理進程被進行:
<?php

class ExampleTest extends TestCase
{
    public function testUserRegistration()
    {
        $this->expectsEvents('App\Events\UserRegistered');
        //測試用戶註冊功能...
    }
}

若是你想阻止全部的事件處理程序運行,你可使用withoutEvents方法:

<?php
class Example extends TestCase
{
    public function testUserRegistraction()
    {
        $this->withoutEvents();
        //Test user registraction code。。。
    }
}

模擬任務

有時你可能但願當請求發送至應用程序時,簡單地對控制器所派送的任務進行測試。這麼作可以讓你隔離測試路由或者控制器,設置除了任務之外的邏輯。固然,在此以後你也能夠在一個單獨的測試案例中測試該任務。

lumen提供了一個簡便的expectsJob方法,以驗證預期的任務有沒有被派送,但任務自己不會被運行:

<?php
class Example extends TestCase
{
    public function testPurchasePodcast()
    {
        $this->expectsJobs('App\Jobs\PurchasePodcast');
        //測試購買博客代碼...
    }
}

注意:該方法只檢測經過全局豬手函數dispatch或者路由或控制器中的$this->dispatch方法派送的任務。它並不會檢測被直接發送到Queue::push的任務。

模擬facades

在測試時,常常須要模擬對lumen facade的調用。例如,考慮以下控制器的操做:
<?php
namespace App\Http\Controllers;

use Cache;
class UserController extends Controller
{
/**
* 展現應用程序全部用戶的列表。

@return Response
*/
public function index()
{
$value = Cache::get('key');

//
}

}

咱們可使用shouldReceive方法來模擬調用Cache門面它會返回一個mockery模擬的實例。由於門面實際上已經被lumen的服務容器,解析和管理,它們比通常的靜態類更具備可測性。例如,讓咱們模擬調用cache門面:
<?php
class FooTest extends TestCase
{
public function testGetIndex()
{
Cache::shouldReceive('get')
->once()
->with('key')
->andReturn('value');

$this->get('/users');
    }
}

注意:你不該該模擬Request門面。應該在測試時使用如call及post這樣的HTTP輔助函數來傳遞你想要的數據。

數據驗證

簡介

lumen提供了數種不一樣的方法來驗證傳入應用程序的數據。默認狀況下,lumen的基本控制器類使用名爲ProvidesConvenienceMethods的trait,其提供了一種便捷的方法來使用各類強大的驗證規則驗證傳入的HTTP請求。

通常來講,lumen中的數據驗證與laravel中的數據驗證並沒有多大區別,所以你應該查過完整的laravel數據驗證文檔以熟悉其使用;不過,它們之間也存在少量重要的差別。

與laravel的差別

表單請求

lumen不支持表單請求。若是想使用表單請求,則贏使用完整的laravel框架。

$this->validate方法

在lumen中可用的$this->validate輔助方法將始終返回帶有相關錯誤消息的json響應。而該方法的laravel版本,若是請求不是ajax請求,返回的則是重定向響應。因爲lumen是無狀態的,且不支持會話,因此閃存錯誤信息在會話中是不可能的。若是想要使用重定向及閃存錯誤數據,應該使用完整的laravel框架。

與laravel不一樣的是,lumen支持在Route閉包中訪問validate方法:

use Illuminate\Http\Request;

$router->post('/user', function (Request $request) {
    $this->validate($request, [
        'name' => 'required',
        'email' => 'required|email|unique:users',
    ]);

    //存儲用戶
});

固然,你能夠自由地使用Validator::make facade方法手動建立驗證器實例,就像在laravel中同樣。

exists和unique規則

若是想要使用exists或者unique驗證規則,則應該在bootstrap/app.php文件中取消$app->withEloquent()方法調用的註釋。

視圖變量$errors

lumen不支持session,所以在laravel中每一個視圖均可用的$errors視圖變量在lumen中式不可用的。若是驗證失敗,那麼$this->validate輔助方法會拋出Illuminate\ValidationException異常,期中嵌入了包含全部相關錯誤消息的json響應,若是你並不是只構建僅發送json響應的無狀態api,則應使用完整的laravel框架。tongzhuo_examination_db

相關文章
相關標籤/搜索