iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 1
0
Modern Web

Laravel 8: For Beginners系列 第 5

Base Features (Part 2)

綱要

  • 請求、驗證與回應(Request, Validation and Response)
  • 中介層(Middleware)

請求、驗證與回應

請求(Request)

HTTP Request 是一個在 HTTP Protocol 中定義的資料傳遞方式。

在 Laravel 中,簡化了這樣的資料獲取模式,比起 $_GET$_POST ,它在使用上更加容易

<?php

// app/Http/Controllers/WelcomeController.php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class WelcomeController extends Controller
{
	public function __invoke(Request $request)
	{
		// 無論是來自於 GET 或 POST,甚至是路由參數,都可以直接取得值
		$request->user_id;

		// 對於可能不存在的值,可以用第二個參數設定預設值
		$request->input('name', 'World');

		// 對於比較複雜的資料(如陣列或 JSON),可以用 input 輔助取得值
		$request->input('user.name');
	}
}

其餘的用法

Request 還有許多其它的用法,如檔案上傳或是 Cookie 等,礙於篇幅不一一說明,這部份應該參閱官方文件

驗證(Validation)

在 Laravel 中,我們可以簡單地驗證資料是否符合我們的需求。

<?php

use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;

$validator = Validator::make(['name' => 'Jack'], [
	'name' => 'required|string'
]);

if ($validator->fails()) {
	// 驗證失敗的情況
	throw new ValidationException($validator);
}

使用 Validator 時,第一個參數是「想要驗證的資料」,第一個參數則是「驗證的規則」。

驗證規則中,Key 表示要驗證的欄位,Value 表示驗證的規則,Value 大部份時候可以是 | 分隔的規則字串,或是一個陣列。

<?php

use Illuminate\Support\Facades\Validator;

$validator = Validator::make(['name' => 'Jack'], [
	'name' => ['required', 'string'],
]);

// ...

多維陣列的驗證

對於多維陣列,可以在規則中加入 . 做設計。

<?php

use Illuminate\Support\Facades\Validator;

$validator = Validator::make(['user' => ['name' => 'Jack']], [
	'user' => 'required|array',
	'user.name' => 'required|string',
]);

使用 Request 在 Controller 中簡化驗證器

在 Controller 中通常會頻繁使用到 Validation,所以我們可以利用 $request->validate() 進行驗證

<?php

// ...

class WelcomeController extends Controller
{
	public function __invoke(Request $request)
	{
		$request->validate(['name' => 'required|string']);

		// 驗證失敗後,會自動丟出 ValidationException,到這邊能夠確定 name 存在且為 string
		$request->name;
	}
}

獨立的 FormRequest

對於較複雜的情況,我們可以建立一個獨立的 FormRequest 編寫規則

$ php artisan make:request [request-name]

剛建立好的 FormRequest 位於 app/Http/Requests 之中,內容大致類似於

<?php

// app/Http/Requests/ExampleRequest.php

// ...

public function authorize()
{
	return false;
}

public function rules()
{
	return [
		//
	];
}

// ...

使用時,將 authorize() 改為 true ,並在 rules() 中編寫驗證邏輯即可。

註:authroize() 這個 method 是用於驗證使用者是否能進行此 Request。

<?php

// app/Http/Requests/AdminRequest.php

public function authorize()
{
    // 如此一來,只要不是 Admin 的用戶就不能執行這個 Request
    return $this->user()->isAdmin();
}

最後,在 Controller 裡使用 FormRequest

<?php

// app/Http/Controllers/WelcomeController.php

// ...

use App\Http\Requests\ExampleRequest;

class WelcomeController extends Controller
{
	public function __invoke(ExampleRequest $request)
	{
		// 此處的 $request 已經被驗證過,資料一定符合規則中所寫的
	}
}

回應(Response)

在 Controller 中使用 return view() 或是 return ['name' => 'Jack'] 的方式回傳視圖或是 JSON,事實上它們是 Laravel 提供的語法糖,若要更細緻地操作 HTTP Response,應該使用 response()

<?php

// ...

public function __invoke(): Response
{
	return response('Hello World', 202); // 設定 HTTP Status Code
}

中介層(Middleware)

有時候,我們在 HTTP Request 觸及到應用程式之前,需要先做一些檢查(例如確定用戶是已登入狀態),此時我們會用中介層去避免重複撰寫相同的邏輯。

中介層的運作邏輯可以用一張圖簡略概括

https://ithelp.ithome.com.tw/upload/images/20190930/20104201yBrcVYOE9M.png

建立中介層

利用以下指令可以快速建立一個中介層

$ php artisan make:middleware [middleware-name]

剛建立的中介層位於 app/Http/Middleware ,內容大致如下(省略了 PHPDocs)

<?php

namespace App\Http\Middleware;

use Closure;

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

$request 是用戶請求的資料,在中介層中可以任意讀取或修改它(如果有需要的話)

如同上圖所示,中介層是一層層推疊起來的,所以參數中會有一個 $next 作為前往下一層的呼叫。

使用中介層

全域中介層

可以在 app/Http/Kernel.php 中指定要使用哪些中介層,內容大致如下

<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
	protected $middleware = [
		// ...
	];

	protected $middlwareGroups = [
		'web' => [
			// ...
		],
		'api' => [
			// ...
		],
	];

	protected $routeMiddleware = [
		'auth' => \App\Http\Middleware\Authenticate::class,
		// ...
	],
}
  • $middleware property 表示所有的請求都會經過這些中介層。
  • $middlewareGroups ,可以讓 web 路由經過指定的中介層,並讓 api 路由經過不同的中介層。(例如「啟動 Session」通常是只有 web 才會用到的功能,API 是不需要使用的)
    • 事實上,routes/api.phproutes/web.php 的差異僅在使用的 Middleware Group 不同
  • $routeMiddleware 中有指定某些中介層的別名,利於記憶與使用。

區域性中介層

可以在 Route 上指定要使用哪些中介層

<?php

Route::middleware('auth')->group(function () {
	// 在這個區域內,僅有已登入的用戶才能存取
	Route::get('/home', fn() => 'Hello World');
});

也可以在 Controller 中指定要使用哪些中介層

<?php

class WelcomeController extends Controller
{
	public function __construct()
	{
		// 表示這個 Controller 中所有的 Method 都是已登入的用戶才能存取
		$this->middleware('auth');
	}

	public function __invoke()
	{
		return 'Hello World';
	}
}

上一篇
Base Features (Part 1)
下一篇
Base Feature (Part 3)
系列文
Laravel 8: For Beginners14

尚未有邦友留言

立即登入留言