你能夠在 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', ]);
爲路由制定了名稱後,就可使用全局輔導函數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
});
});
註冊中間件
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) { // }]);
有時中間件可能須要在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方法註冊中間件。
爲了替代把全部的請求處理邏輯都定義在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請求的實例,你應該在控制器構造函數或者方法中使用
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請求的方法,下面是該類的幾個使用方法:
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標準規定了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文檔瞭解這些方法的詳細信息。
固然,全部的路由及控制器必須返回某個類型的響應,併發送回用戶的瀏覽器。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。
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,你應該去掉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方法在不顯示錯誤頁面的狀況下快速報告異常:
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, ];
Rendor方法負責將給定的異常轉換爲將被髮送回瀏覽器的HTTP響應。默認值狀況下,異常將傳遞給你生成響應的基類。不過,你能夠按本身意願檢查異常類型或者返回本身的自定義響應:
/**
*將異常1轉換爲HTTP響應。
return parent::render($request, $exception);
}
除了在異常處理器的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錯誤代碼。例如,[頁面未找到]錯誤(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變量傳遞給視圖:
爲了幫助你更多的瞭解應用程序中到底發生了什麼,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通道須要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外觀類將信息寫入到日誌。如前所述,日誌器提供在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目錄下。
一般,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隊列驅動程序,須要先經過composer安裝illuminate/redis(5.5.*)擴展包。而後再bootstrap/app.php文件中註冊Illuminate\Redis\RedisServiceProvider;
下面列出其餘隊列驅動程序所須要的依賴擴展包:
亞馬遜SQS:aws/aws-sdk-php ~3.0
Beanstalked:pda/pheanstalk ~3.0
與框架的許多其餘部分同樣,lumen隊列做業的功能與laravel的隊列做業功能相同。所以,要了解lumen隊列做業功能,請查看完整的laravel隊列文檔。
不過呢,咱們如今講討論兩個框架間的一些細微差別。首先,咱們來談談lumen中如何生成隊列做業。
lumen不包括用於自動建立新job類的生成器。所以你須要賦值框架所帶的exampleJob類。這個類提供了每一個job類共享的基本結構。examplejob所繼承的job基類已包含所需的interactswithqueue,queueable和serializesmodels特性:
<?php
namespace App\Jobs;
class ExampleJob extendx Job
{
/**
/**
再次重申,你應該查閱完整的laravel文檔以獲取有關調節隊列做業的完整信息;和laravel框架同樣,你可使用dispatch函數從lumen應用程序中的任意位置調度做業:
dispatch(new ExampleJob);
固然,你也可使用Queue facade。若是你選擇使用facade,請務必在bootstrap/app.php文件中取消對$app->withFacades()調用的註釋:
Queue::push(new ExampleJob);
laravel的服務容器是一個管理類依賴和執行依賴注入的強力工具。依賴注入是個花俏的名字,事實上是指:類的依賴經過構造器或者在某些狀況下經過【setter】方法【注入】。
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請求,並查看輸出結果。
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數據驗證文檔以熟悉其使用;不過,它們之間也存在少量重要的差別。
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