LoginSignup
4
4

More than 5 years have passed since last update.

Slim 3(php)でカスタムExceptionを追加する

Last updated at Posted at 2016-12-22

概要

  • Slim 3に、カスタムのException(BadRequestException)を追加する
  • BadRequestExceptionがthrowされた場合、HTTP Status Code 400とエラーメッセージを返す
  • Controller等でValidationがNGの場合、throw BadRequestException('リクエストが不正です');だけすればOKに

前置き

  • 追加する前にSlimがどのようにExceptionをハンドリングしているか見てみる

どこでExceptionがcatchされるか

  • Controllerなどの内部でtry cacheがなければ、Slim\Appクラスのprocessメソッドでcachtされる
  • handleExceptionメソッドが呼ばれる
vender/slim/Slim/App.php
public function process(ServerRequestInterface $request, ResponseInterface $response)
{
    // ~省略~
    // Traverse middleware stack
    try {
        $response = $this->callMiddlewareStack($request, $response);
    } catch (Exception $e) {
        $response = $this->handleException($e, $request, $response); // ←ココ
    } catch (Throwable $e) {
        $response = $this->handlePhpError($e, $request, $response);
    }

    $response = $this->finalize($response);

    return $response;
}
  • handleExceptionメソッドは、Exceptionのinstance毎に対応するコンテナに登録されているHandlerを呼ぶ
  • NotAllowed、NotFound、SlimException以外のExceptionがthrowされた場合、errorHandlerとしてコンテナに登録されているHandlerが呼ばれる
  • コンテナのerrorHandlerには、デフォルトでSlim\Handlers\Errorクラスが登録されている
vender/slim/Slim/App.php
protected function handleException(Exception $e, ServerRequestInterface $request, ResponseInterface $response)
{
    if ($e instanceof MethodNotAllowedException) {
        $handler = 'notAllowedHandler';
        $params = [$e->getRequest(), $e->getResponse(), $e->getAllowedMethods()];
    } elseif ($e instanceof NotFoundException) {
        $handler = 'notFoundHandler';
        $params = [$e->getRequest(), $e->getResponse()];
    } elseif ($e instanceof SlimException) {
        // This is a Stop exception and contains the response
        return $e->getResponse();
    } else {
        // Other exception, use $request and $response params
        $handler = 'errorHandler';
        $params = [$request, $response, $e];
    }

    if ($this->container->has($handler)) {
        $callable = $this->container->get($handler);
        // Call the registered handler
        return call_user_func_array($callable, $params); // ←ここでコンテナのhandlerが呼ばれる
    }

    // No handlers found, so just throw the exception
    throw $e;
}
  • なので、BadRequestExceptionをハンドリングするHandlerを作成し、コンテナのerrorHandlerに上書き登録しておけばよい

実装

前置きが長くなってしまったが、本題に入る
BadRequestExceptionクラスとerrorHandlerに登録するHandlerを作成する

BadRequestExceptionの作成

  • Exceptionを継承するだけ。今回は特に特別な処理は行わない
app/exception/BadRequestException.php
<?php
namespace App\Exception;

use Exception;

class BadRequestException extends Exception
{
}

Handlerの作成

  • Slim\Handlers\Errorクラスを継承することで、BadRequest以外の処理は Slim\Handlers\Errorで処理されるようにする
app/handler/error.php
<?php
namespace App\Handler;

use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use App\Exception\BadRequestException;

final class Error extends \Slim\Handlers\Error
{
    public function __construct($displayErrorDetails)
    {
        // エラーの詳細表示の有無設定(Slim\Handlers\Errorで必須)
        parent::__construct($displayErrorDetails);
    }

    public function __invoke(Request $request, Response $response, \Exception $e)
    {
        if ($e instanceof BadRequestException)
        {
            // Jsonで返す
            $response = $response
                ->withStatus(400)
                ->withHeader('Content-type', 'application/json')
                ->withJson(['message' => $e->getMessage()]);
        } else {
            // BadRequest以外のExceptionはSlim\Handlers\Errorへ
            $response = parent::__invoke($request, $response, $e);
        }
        return $response;
    }
}

コンテナにHandlerを登録

  • dependencies.phpにて、errorHandlerにErrorクラスを上書き登録
dependencies.php
// ↓を追加
$container['errorHandler'] = function ($c) {
    return new App\Handler\Error($c->get('settings')['displayErrorDetails']);
};

以上で、throw BadRequestException($error_message);をすれば、HTTP Status Code 400のResponseが返るはず。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4