はじめに

これは Laravel Advent Calendar 2017 19日目の記事です。

カスタム例外処理(クラス)の作成と使用方法について書いていきます。

例外処理というと難解そうですが、結構簡単な内容なのですぐ読み終わると思います。

環境

  • PHP: 7.1.5
  • Laravel: 5.5.24

前提

  • 今回は具体的な例として、バリデーションエラーの例外クラスを作成する
  • レスポンスは JSON 形式

作成手順

例外クラスを作成する

  • artisan コマンドで作成できる
    • php artisan make:exception ValidationException

作成した例外クラスを編集する

app/Exceptions/ValidationException.php
<?php

namespace App\Exceptions;

use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

class ValidationException extends Exception
{
    public $request;
    public $message;

    public function __construct(Request $request, array $message)
    {
        $this->request = $request;
        // 複数のバリデーションエラー時には , で区切る
        $this->message = implode(',', $message);
    }

    public function report()
    {
        $xRequestId = array_key_exists('x-request-id', $this->request->header()) ? $this->request->header()['x-request-id'][0] : '';
        Log::info(
            $xRequestId,
            [
                'client_ip'      => $this->request->getClientIp(),
                'request_params' => $this->request->all(),
                'response_body'  => $this->message,
            ]
        );
    }

    public function render()
    {
        return response()->json(
            $this->message,
            422
        );
    }
}

解説

  • report() ではログとして表示させたい内容を設定している
  • render() ではレスポンスとして返したい内容を設定している

作成した例外クラスを呼ぶ

会員登録の Controller で呼び出してみる

app/Http/Controllers/Account/V1/RegisterController.php
<?php

namespace App\Http\Controllers\Account\V1;

use App\Exceptions\ValidationException;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class RegisterController extends Controller
{
    public function apply(Request $request)
    {
        $validation = \Validator::make(
            [
                'mail_to'        => $request->get('mail_to'),
                'register_token' => $request->get('register_token'),
            ],
            [
                'mail_to'        => 'required|email|max:128',
                'register_token' => 'required|alpha_num|size:64',
            ]
        );

        if ($validation->fails()) {
            throw new ValidationException($request, $validation->errors()->all());
        }

        ...
    }
}    

ルーティング

routes/account/v1.php
Route::put('registers/apply', 'Account\V1\RegisterController@apply');

例外を発生させてみる

不正なリクエスト

  • 必須パラメータである register token なし
curl -kv -X PUT -H "X-Request-Id: abc123" -d "mail_to=test@gmail.com" https://***-api.***.jp/account/v1/registers/apply

例外レスポンスの例

> 
* upload completely sent off: 37 out of 37 bytes
< HTTP/1.1 422 Unprocessable Entity
< Server: nginx/1.12.1
< Content-Type: application/json
< Transfer-Encoding: chunked
< Connection: keep-alive
< Cache-Control: no-cache, private
< Date: Mon, 11 Dec 2017 09:41:04 GMT
< X-RateLimit-Limit: 60
< X-RateLimit-Remaining: 57
< 
* Curl_http_done: called premature == 0
* Connection #0 to host ***-api.***.jp left intact
"The register token field is required."

解説

  • register token がリクエストパラメータに含まれていないため、The register token field is required. というようにエラーレスポンスを返している
  • ステータスコードも ValidationException で設定した 422 になっている

例外ログの例

[2017-12-11 09:41:04] local.INFO: test123 {"client_ip":"192.168.**.**","request_params":{"mail_to":"test@gmail.com"},"response_body":"The register token field is required."} 

おまけ

去年の Laravel Advent Calendar にも参加していたので良かったらどうぞ。

Laravel でカスタムバリデーションとそのテスト