====== Slim4 ミドルウェア ====== Version 4.5.0 --- //[[http://www.y2sunlight.com|y2sunlight]] 2020-09-23// [[slim:top|Slim に戻る]] 関連記事 * [[slim:4:install|Slim4 インストール]] * [[slim:4:concepts|Slim4 コンセプト]] * [[slim:4:request|Slim4 リクエスト]] * [[slim:4:response|Slim4 レスポンス]] * [[slim:4:routing|Slim4 ルーティング]] * Slim4 ミドルウェア * [[slim:4:cookbook|Slim4 クックブック]] 本章は以下のサイトの **Packaged Middleware** のセクションを翻訳し若干の補足を加えたのもです。 * https://www.slimframework.com/docs/v4/ ----- ===== ルーティング ===== ==== 使用法 ==== ルーティングはミドルウェアとして実装されています。まだデフォルトルーターとしてFastRouteを使用していますが、緊密に結合されているわかではありません。別のルーティングライブラリを実装したい場合は、ルーティングインターフェイスの独自の実装を作成することで可能になります。それは、Slimのコンポーネントとルーティングライブラリの間にブリッジを作成する ''DispatcherInterface''、''RouteCollectorInterface''、''RouteParserInterface''、および ''RouteResolverInterface'' です。もし ''determineRouteBeforeAppMiddleware''を使用していた場合は、以前の動作を維持するために、''run()'' を呼び出す直前に ''Middleware\RoutingMiddleware''ミドルウェアをアプリケーションに追加する必要があります。 addRoutingMiddleware(); // ... $app->run(); \\ ===== エラー処理 ===== 物事はうまくいかない。エラーを予言することはできませんが、予想することはできます。それぞれの Slim Framework アプリケーションには、キャッチされなかったすべてのPHP例外を受け取るエラーハンドラーがあります。このエラーハンドラーは、現在のHTTPリクエスト及びレスポンスオブジェクトも受信します。エラーハンドラは、HTTPクライアントに返される適切なResponseオブジェクトを準備して返す必要があります。 ==== 使用法 ==== addRoutingMiddleware(); /** * @param bool $displayErrorDetails -> Should be set to false in production * @param bool $logErrors -> Parameter is passed to the default ErrorHandler * @param bool $logErrorDetails -> Display error details in error log * which can be replaced by a callable of your choice. * @param \Psr\Log\LoggerInterface $logger -> Optional PSR-3 logger to receive errors * * Note: This middleware should be added last. It will not handle any exceptions/errors * for middleware added after it. */ $errorMiddleware = $app->addErrorMiddleware(true, true, true, $logger); // ... $app->run(); \\ ==== カスタムエラーハンドラーの追加 ==== あらゆるタイプの Exception または Throwable のカスタムハンドラーをマップできるようになります。 addRoutingMiddleware(); // Define Custom Error Handler $customErrorHandler = function ( ServerRequestInterface $request, Throwable $exception, bool $displayErrorDetails, bool $logErrors, bool $logErrorDetails, ?LoggerInterface $logger = null ) use ($app) { $logger->error($exception->getMessage()); $payload = ['error' => $exception->getMessage()]; $response = $app->getResponseFactory()->createResponse(); $response->getBody()->write( json_encode($payload, JSON_UNESCAPED_UNICODE) ); return $response; }; // Add Error Middleware $errorMiddleware = $app->addErrorMiddleware(true, true, true, $logger); $errorMiddleware->setDefaultErrorHandler($customErrorHandler); // ... $app->run(); \\ ==== エラーロギング ==== Slimに同梱されているデフォルトの ''ErrorHandler'' にカスタムエラーロギングをパイプする場合には、2つの方法があります。 最初の方法では、''ErrorHandler'' を拡張し、''logError()'' メソッドをスタブ化するだけです。 addRoutingMiddleware(); // Instantiate Your Custom Error Handler $myErrorHandler = new MyErrorHandler($app->getCallableResolver(), $app->getResponseFactory()); // Add Error Middleware $errorMiddleware = $app->addErrorMiddleware(true, true, true); $errorMiddleware->setDefaultErrorHandler($myErrorHandler); // ... $app->run(); 2番目の方法では、人気のある [[https://github.com/Seldaek/monolog/|Monolog]] ライブラリからのものなど、[[https://www.php-fig.org/psr/psr-3/|PSR-3 規約]]に準拠するロガーを提供できます。 addRoutingMiddleware(); // Instantiate Logger // $logger = ... // Add Error Middleware with Logger $errorMiddleware = $app->addErrorMiddleware(true, true, true, $logger); // ... $app->run(); \\ ==== エラー処理とレンダリング ==== レンダリングは最終的にエラー処理から切り離されています。それでもコンテンツタイプを検出し、''ErrorRenderers'' の助けを借りて適切にレンダリングします。 コアの ''ErrorHandler'' は、完全にリファクタリングされた ''AbstractErrorHandler'' クラスを拡張します。デフォルトでは、サポートされているコンテンツタイプに合わせた ''ErrorRenderer'' が呼び出されます。コアの ''ErrorHandler'' は、次のコンテンツタイプのレンダラーを定義します。 * application/json * application/xml とtext/xml * text/html * text/plain どのコンテンツタイプでも、独自のエラーレンダラーを登録できます。従って、最初に ''\Slim\Interfaces\ErrorRendererInterface'' を実装する新しいエラーレンダラーを定義します。 次に、そのエラーレンダラーをコアエラーハンドラーに登録します。以下の例では、''text/html'' コンテンツタイプに使用されるレンダラーを登録しています。 addRoutingMiddleware(); // Add Error Middleware $errorMiddleware = $app->addErrorMiddleware(true, true, true); // Get the default error handler and register my custom error renderer. $errorHandler = $errorMiddleware->getDefaultErrorHandler(); $errorHandler->registerErrorRenderer('text/html', MyCustomErrorRenderer::class); // ... $app->run(); === エラーレンダリングに特定のコンテンツタイプを強制する === デフォルトでは、エラーハンドラーは、リクエストの ''Accept'' ヘッダーを使用してエラーレンダラーの検出を試みます。エラーハンドラーに特定のエラーレンダラーを使用させる必要がある場合は、次のように記述できます。 $errorHandler->forceContentType('application/json'); \\ ==== 新しいHTTP例外 ==== アプリケーション内に名前付きHTTP例外を追加しています。これらの例外は、ネイティブなレンダラーでうまく機能します。ネイティブHTMLレンダラーが呼び出されたときに、もう少し見識を与えるために、それぞれに ''description'' と ''title'' 属性を設定することもできます。 基本クラス ''HttpSpecializedException'' は ''Exception'' を拡張し、次のサブクラスが付属しています: * HttpBadRequestException * HttpForbiddenException * HttpInternalServerErrorException * HttpNotAllowedException * HttpNotFoundException * HttpNotImplementedException * HttpUnauthorizedException Example if you wanted a 504 gateway timeout exception that behaves like the native ones you would do the following: ベースリポジトリで提供しないと判断した他のレスポンスコードが必要な場合は、''HttpSpecializedException'' クラスを拡張できます。例えば、ネイティブのように動作する504ゲートウェイタイムアウト例外が必要な場合は、次のようにします: class HttpGatewayTimeoutException extends HttpSpecializedException { protected $code = 504; protected $message = 'Gateway Timeout.'; protected $title = '504 Gateway Timeout'; protected $description = 'Timed out before receiving response from the upstream server.'; } \\ ===== メソッドオーバライド ===== メソッドオーバライド ミドルウエアを使用すると、''X-Http-Method-Override'' リクエストヘッダーまたはリクエストボディのパラメータ ''_METHOD'' を使用して、着信リクエストのメソッドをオーバーライドできます。このミドルウェアは、ルーティングミドルウェアが追加された後に配置する必要があります。 ==== 使用法 ==== addRoutingMiddleware(); // Add MethodOverride middleware $methodOverrideMiddleware = new MethodOverrideMiddleware(); $app->add($methodOverrideMiddleware); // ... $app->run(); \\ ===== 出力バッファリング ===== 出力バッファリング ミドルウェアを使用すると、出力バッファリングの2つのモード(''APPEND''(デフォルト)と ''PREPEND'' モード)を切り替えることができます。''APPEND'' モードでは、既存のレスポンスボディを使用してコンテンツを追加します。''PREPEND'' モードは、新しいレスポンスボディ オブジェクトを作成し、既存のレスポンスボディからの出力の前にコンテンツを追加します。このミドルウェアは、最後に実行されるようにミドルウェアスタックの中央に配置する必要があります。 ==== 使用法 ==== add($outputBufferingMiddleware); // ... $app->run(); \\ ===== ボディ解析 ===== Web APIでは、JSONまたはXML形式でデータを送信するのが非常に一般的です。箱から出しも、PSR-7の実装はこれらの形式をサポートしていません。リクエストオブジェクトの ''getBody()'' を自分でデコードする必要があります。これは一般的な要件であるため、Slim4はこのタスクを処理するための ''BodyParsingMiddleware'' を提供します。 ==== 使用法 ==== ''addErrorMiddlware'' を呼び出す前に、ボディ解析ミドルウェアを配置して、スタックが次のようになるようにすることをお勧めします: addBodyParsingMiddleware(); $app->addRoutingMiddleware(); $app->addErrorMiddleware(true, true, true); // ... $app->run(); \\ ==== ポストされたJSON、フォーム、XMLデータ ==== POSTハンドラーを変更する必要はありません。というのは、''BodyParsingMiddleware'' は ''Content-Type'' が ''JSON'' メディアタイプに設定されていることを検出し、デコードされたボディをリクエストの parsed bodyプロパティに配置するからです。 ブラウザからウェブサイトにポストされたデータの場合、$request の ''getParsedBody()'' メソッドを使用できます。 これにより、投稿されたデータの配列が返されます。 $app->post('/', function (Request $request, Response $response, $args): Response { $data = $request->getParsedBody(); $html = var_export($data, true); $response->getBody()->write($html); return $response; }); \\ ==== メディアタイプの検出 ==== * ミドルウェアは、リクエストヘッダーから ''Content-Type'' を読み取り、メディアタイプを検出します。 * この特定のメディアタイプにパーサーが登録されているかどうかを確認します。 * そうでない場合は、構造化された構文サフィックス(RFC 6839)が付いたメディアタイプを探します。例えば: ''application/*'' \\ ==== サポートされているメディアタイプ ==== * application/json * application/x-www-form-urlencoded * application/xml * text/xml \\ ===== Content Length ===== Content Length ミドルウェアは、''Content-Length'' ヘッダーをレスポンスに自動的に追加します。これは、Slim3 から削除された ''addContentLengthHeader'' の設定を置き換えるためのものです。このミドルウェアは、最後に実行されるように、ミドルウェアスタックの中央に配置する必要があります。 ==== 使用法 ==== add($contentLengthMiddleware); // ... $app->run(); \\