====== 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 レスポンス]] * Slim4 ルーティング * [[slim:4:middleware|Slim4 ミドルウェア]] * [[slim:4:cookbook|Slim4 クックブック]] 本章は以下のサイトの **Routing** のセクションを翻訳し若干の補足を加えたのもです。 * https://www.slimframework.com/docs/v4/ ----- SlimFramework のルーターは [[https://github.com/nikic/FastRoute|FastRoute]] コンポーネントの上に構築されており、非常に高速で安定しています。このコンポーネントを使用して全てのルーティングを処理している間は、アプリのコアとそれは完全に分離されており、他のルーティングライブラリを使用をすることを容易にするためにインターフェイスが設置されています。 ===== ルートの作成方法 ===== アプリケーションルートは、''Slim\App'' インスタンス上のプロキシメソッドを使用することにより定義できます。Slim Frameworkは、最も一般的なHTTPメソッドに対するメソッドを提供します。 ==== GET ルート ==== Slimアプリケーションの ''get()'' メソッドを使用して、''GET'' HTTPリクエストのみを処理するルートを追加できます。それは2つの引数を受け入れます: - ルートパターン(オプションで名前付きプレースホルダーを含みます) - ルートコールバック $app->get('/books/{id}', function ($request, $response, array $args) { // Show book identified by $args['id'] }); \\ ==== POST ルート ==== Slimアプリケーションの ''post()'' メソッドを使用して、''POST'' HTTPリクエストのみを処理するルート(route)を追加できます。それは2つの引数を受け入れます: - ルートパターン(オプションで名前付きプレースホルダーを含みます) - ルートコールバック $app->post('/books', function ($request, $response, array $args) { // Create new book }); \\ ==== PUT ルート ==== Slimアプリケーションの ''put()'' メソッドを使用して、''PUT'' HTTPリクエストのみを処理するルートを追加できます。それは2つの引数を受け入れます: -ルートパターン(オプションで名前付きプレースホルダーを含みます) -ルートコールバック $app->put('/books/{id}', function ($request, $response, array $args) { // Update book identified by $args['id'] }); \\ ==== DELETE ルート ==== Slimアプリケーションの ''delete()'' メソッドを使用して、''DELETE'' HTTPリクエストのみを処理するルートを追加できます。それは2つの引数を受け入れます: - ルートパターン(オプションで名前付きプレースホルダーを含みます) - ルートコールバック $app->delete('/books/{id}', function ($request, $response, array $args) { // Delete book identified by $args['id'] }); \\ ==== OPTIONS ルート ==== Slimアプリケーションの ''options()'' メソッドを使用して、''OPTIONS'' HTTPリクエストのみを処理するルートを追加できます。それは2つの引数を受け入れます: -ルートパターン(オプションで名前付きプレースホルダーを含みます) -ルートコールバック $app->options('/books/{id}', function ($request, $response, array $args) { // Return response headers }); \\ ==== PATCH ルート ==== Slimアプリケーションの ''patch()'' メソッドを使用して、''PATCH'' HTTPリクエストのみを処理するルートを追加できます。それは2つの引数を受け入れます: - ルートパターン(オプションで名前付きプレースホルダーを含みます) - ルートコールバック $app->patch('/books/{id}', function ($request, $response, array $args) { // Apply changes to book identified by $args['id'] }); \\ ==== Any ルート ==== Slimアプリケーションの ''any()'' メソッドを使用して、すべてのHTTPリクエストメソッドを処理するルートを追加できます。それは2つの引数を受け入れます: - ルートパターン(オプションで名前付きプレースホルダーを含みます) - ルートコールバック $app->any('/books/[{id}]', function ($request, $response, array $args) { // Apply changes to books or book identified by $args['id'] if specified. // To check which method is used: $request->getMethod(); }); 2番目のパラメーターはコールバックであることに注意してください。Closureの代わりに __invoke() メソッドを実装するクラスを指定できます。その後、別の場所でマッピングを行うことができます。 $app->any('/user', 'MyRestfulController'); \\ ==== Custom Route ==== Slimアプリケーションの ''map()'' メソッドを使用して、複数のHTTPリクエストメソッドを処理するルートを追加できます。それは次の3つの引数を受け入れます: - HTTPメソッドの配列 - ルートのパターン(オプションで名前付きプレースホルダーを含みます) - ルートのコールバック $app->map(['GET', 'POST'], '/books', function ($request, $response, array $args) { // Create new book or list all books }); \\ ===== ルートコールバック ===== 上記の各ルーティングメソッドは、最後の引数としてコールバックルーチンを受け入れます。この引数は、任意のPHP callable が可能であり、それはデフォルトでは3つの引数を受け入れます。 * ''Request'' 最初の引数は、現在のHTTPリクエストを表す ''Psr\Http\Message\ServerRequestInterface'' オブジェクトです。 * ''Response'' 2番目の引数は、現在のHTTP応答を表す ''Psr\Http\Message\ResponseInterface'' オブジェクトです。 * ''Arguments'' 3番目の引数は、現在のルートの名前付きプレースホルダーの値を含む連想配列です。 ==== 応答へのコンテンツの書き込み ==== HTTP応答にコンテンツを書き込む方法は2つあります。まず、ルートコールバックからコンテンツを単に ''echo()'' することができます。このコンテンツは、現在のHTTP応答オブジェクトに追加されます。次に、''Psr\Http\Message\ResponseInterface'' オブジェクトを返すことができます。 \\ ==== クロージャバインディング==== ルートコールバックとして、依存関係コンテナと ''Closure'' インスタンスを使用する場合、クロージャの状態は ''Container'' インスタンスにバインドされています。これは、''$this'' キーワードを介して、クロージャー内のDIコンテナーインスタンスにアクセスできることを意味します: $app->get('/hello/{name}', function ($request, $response, array $args) { // Use app HTTP cookie service $this->get('cookies')->set('name', [ 'value' => $args['name'], 'expires' => '7 days' ]); }); > **注意喚起** > Slimは静的クロージャーをサポートしていません。 \\ ===== リダイレクトヘルパー ===== Slimアプリケーションの ''redirect()'' メソッドを使用して、''GET'' HTTPリクエストを別のURLにリダイレクトするルートを追加できます。それは次の3つの引数を受け入れます: - リダイレクト元 ''from'' のルートパターン(オプションで名前付きプレースホルダーを含みます) - リダイレクト先 ''to'' の場所。文字列または [[https://www.php-fig.org/psr/psr-7/#35-psrhttpmessageuriinterface|Psr\Http\Message\UriInterface]] の場合があります。 - 使用するHTTPステータスコード(オプション:設定されていない場合は ''302'') $app->redirect('/books', '/library', 301); ''redirect()'' ルートは、要求されたステータスコードと、2番目の引数に設定された ''Location'' ヘッダーで応答します。 \\ ===== ルート戦略 ===== ルートコールバックのシグニチャは、ルート戦略によって決定されます。デフォルトでは、Slimは、ルートコールバックがリクエスト、レスポンス、およびルートプレースホルダー引数の配列を受け入れることを期待しています。これは、''RequestResponse'' 戦略と呼ばれます。 ただし、別の戦略を使用するだけで、期待されるルートコールバックシグニチャを変更できます。例として、Slimは、リクエストとレスポンに加えて個々に分かれた引数として各ルートプレースホルダーを受け入れる ''RequestResponseArgs'' と呼ばれる代替戦略を提供します。 この代替戦略の使用例を次に示します: getRouteCollector(); $routeCollector->setDefaultInvocationStrategy(new RequestResponseArgs()); $app->get('/hello/{name}', function ($request, $response, $name) { $response->getBody()->write($name); return $response; }); あるいは、ルートごとに異なる呼び出し戦略を設定することもできます: getRouteCollector(); $route = $app->get('/hello/{name}', function ($request, $response, $name) { $response->getBody()->write($name); return $response; }); $route->setInvocationStrategy(new RequestResponseArgs()); ''Slim\Interfaces\InvocationStrategyInterface'' を実装することにより、独自のルート戦略を提供できます。 \\ ===== ルートプレースホルダー===== 上記の各ルーティングメソッドは、現在のHTTPリクエストURIと照合されるURLパターンを受け入れます。ルートパターンは、名前付きプレースホルダーを使用して、HTTPリクエストURIセグメントを動的に照合できます。 ==== フォーマット ==== ルートパターンのプレースホルダーは ''{'' で始まり、プレースホルダー名が続き、''}'' で終わります。以下は、''name'' という名前のプレースホルダーの例です。 use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; // ... $app->get('/hello/{name}', function (ServerRequestInterface $request, ResponseInterface $response, array $args) { $name = $args['name']; $response->getBody()->write("Hello, $name"); return $response; }); \\ ==== オプションセグメント ==== セクションをオプションにするには、角括弧(''[]'')で囲みます: $app->get('/users[/{id}]', function ($request, $response, array $args) { // responds to both `/users` and `/users/123` // but not to `/users/` return $response; }); ネストする事により、複数のオプションパラメータがサポートされます: $app->get('/news[/{year}[/{month}]]', function ($request, $response, array $args) { // reponds to `/news`, `/news/2016` and `/news/2016/03` // ... return $response; }); オプションパラメータが「無制限」の場合、以下のように行うことができます: $app->get('/news[/{params:.*}]', function ($request, $response, array $args) { // $params is an array of all the optional segments $params = explode('/', $args['params']); // ... return $response; }); 上の例では、URIが ''/news/2016/03/20'' の場合、''['2016', '03', '20']''の3つの要素を含む ''$params'' 配列になります。 \\ ==== 正規表現マッチング ==== デフォルトでは、プレースホルダーは ''{}'' 内に記述され、任意の値を受け入れることができます。ただし、プレースホルダーは、特定の正規表現に一致するようにHTTPリクエストURIを要求することもできます。現在のHTTPリクエストURIがプレースホルダーの正規表現と一致しない場合、ルートは呼び出されません。以下は、1つ以上の数字を必要とする ''id'' という名前のプレースホルダーの例です。 $app->get('/users/{id:[0-9]+}', function ($request, $response, array $args) { // Find user identified by $args['id'] // ... return $response; }); \\ ===== ルート名 ===== アプリケーションルートには名前を付けることができます。これは、RouteParser の ''urlFor()'' メソッドを使用して特定のルートへのURLをプログラムで生成したい場合に役立ちます。上記の各ルーティングメソッドは ''Slim\Route'' オブジェクトを返し、このオブジェクトは ''setName()'' メソッドを公開します。 $app->get('/hello/{name}', function ($request, $response, array $args) { $response->getBody()->write("Hello, " . $args['name']); return $response; })->setName('hello'); この名前付きルートのURLは、アプリケーション RouteParser の ''urlFor()'' メソッドを使用して生成できます。 $routeParser = $app->getRouteCollector()->getRouteParser(); echo $routeParser->urlFor('hello', ['name' => 'Josh'], ['example' => 'name']); // Outputs "/hello/Josh?example=name" RouteParser の ''urlFor()'' メソッドは、次の3つの引数を受け入れます: * ''$routeName'' ルート名。ルートの名前は、''$route->setName('name')'' を介して設定できます。ルートマッピングメソッドは ''Route'' のインスタンスを返すため、ルートをマッピングした直後に名前を設定できます。例:''$app->get('/', function(){...})-> setName('name')'' * ''$data'' ルートパターンのプレースホルダーと置換値の連想配列。 * ''$queryParams'' 生成されたURLに追加されるクエリパラメータの連想配列。 \\ ===== ルートグループ ===== ルートを論理グループに整理するために、''Slim\App'' には ''group()'' メソッドも用意されています。各グループのルートパターンは、そのグループに含まれるルートまたはグループの前に付加され、グループパターン内のプレースホルダー引数は、最終的にネストされたルートで使用できるようになります: use Slim\Routing\RouteCollectorProxy; // ... $app->group('/users/{id:[0-9]+}', function (RouteCollectorProxy $group) { $group->map(['GET', 'DELETE', 'PATCH', 'PUT'], '', function ($request, $response, array $args) { // Find, delete, patch or replace user identified by $args['id'] // ... return $response; })->setName('user'); $group->get('/reset-password', function ($request, $response, array $args) { // Route for /users/{id:[0-9]+}/reset-password // Reset the password for user identified by $args['id'] // ... return $response; })->setName('user-password-reset'); }); グループパターンは空にすることができ、共通のパターンを共有しないルートの論理グループ化を有効にします。 use Slim\Routing\RouteCollectorProxy; // ... $app->group('', function (RouteCollectorProxy $group) { $group->get('/billing', function ($request, $response, array $args) { // Route for /billing return $response; }); $group->get('/invoice/{id:[0-9]+}', function ($request, $response, array $args) { // Route for /invoice/{id:[0-9]+} return $response; }); })->add(new GroupMiddleware()); グループクロージャー内で、Slimはクロージャーをコンテナーインスタンスにバインドすることに注意してください。 * ルートクロージャ内で、''$this'' は ''Psr\Container\ContainerInterface'' のインスタンスにバインドされます \\ ===== ルートミドルウェア ===== ミドルウェアを任意のルートまたはルートグループにアタッチすることもできます。 use Slim\Routing\RouteCollectorProxy; // ... $app->group('/foo', function (RouteCollectorProxy $group) { $group->get('/bar', function ($request, $response, array $args) { // ... return $response; })->add(new RouteMiddleware()); })->add(new GroupMiddleware()); \\ ===== ルーターキャッシュ ===== ''RouteCollector::setCacheFile()'' を介してルーターキャッシュを有効にすることができます。以下の例を参照してください: getRouteCollector(); $routeCollector->setCacheFile('/path/to/cache.file'); \\ ===== コンテナ―ソリユーション ===== ルートに対しては関数を定義することだけに限定されません。Slimでは、ルートのアクション関数を定義するいくつかの異なる方法があります。 関数に加えて、次のものを使用できます: * コンテナ―キー:メソッド * クラス:メソッド * ''__invoke() '' メソッドを実装するクラス * コンテナ―キー この機能は、Slim の Callable Resolver Class によって有効になります。それは、文字列エントリを関数呼び出しに変換します。例: $app->get('/', '\HomeController:home'); または、PHPの ''::class'' 演算子を利用することもできます。これは、IDEのルックアップシステムで適切に機能し、同じ結果を生成します: $app->get('/', \HomeController::class . ':home'); 上記のコードでは、''/'' ルートを定義し、''HomeController'' クラスで ''home()'' メソッドを実行するようにSlimに指示しています。 Slimは最初にコンテナ内の ''HomeController'' のエントリを探します。見つかった場合はそのインスタンスを使用し、そうでない場合はコンテナを最初の引数としてコンストラクタを呼び出します。クラスのインスタンスが作成されると、定義したストラテジーを使用して、指定されたメソッドが呼び出されます。 \\ ==== コントローラーをコンテナーに登録する ==== ''home'' アクションメソッドを伴うコントローラーを作成します。コンストラクターは、必要な依存関係を受け入れる必要があります。 例えば: view = $view; } public function home(ServerRequestInterface $request, ResponseInterface $response, array $args): ResponseInterface { // your code here // use $this->view to render the HTML // ... return $response; } } 依存関係を持つコントローラーをインスタンス化するファクトリをコンテナーに作成します。 use Psr\Container\ContainerInterface; // ... $container = $app->getContainer(); $container->set('HomeController', function (ContainerInterface $container) { // retrieve the 'view' from the container $view = $container->get('view'); return new HomeController($view); }); これにより、依存関係の注入にコンテナーを活用できるため、特定の依存関係をコントローラーに注入できます。 \\ ==== Slimがコントローラーをインスタンス化できるようにする ==== また、クラスがコンテナにエントリされていない場合、Slimはコンテナのインスタンスをそのクラスのコンストラクタに渡します。1つのアクションのみを処理する呼び出し可能なクラスの代わりに、多くのアクションを持つコントローラーを構築できるのです。 container = $container; } public function home(ServerRequestInterface $request, ResponseInterface $response, array $args): ResponseInterface { // your code to access items in the container... $this->container->get(''); return $response; } public function contact(ServerRequestInterface $request, ResponseInterface $response, array $args): ResponseInterface { // your code to access items in the container... $this->container->get(''); return $response; } } このコントローラーメソッドは次のように使用できます。 $app->get('/', \HomeController::class . ':home'); $app->get('/contact', \HomeController::class . ':contact'); \\ ==== インボーク可能なアクションクラスの使用 ==== ルート呼び出しのメソッドを指定する必要はなく、次のようなインボーク可能なアクションクラスとして設定するだけです: container = $container; } public function __invoke(ServerRequestInterface $request, ResponseInterface $response, array $args): ResponseInterface { // your code to access items in the container... $this->container->get(''); return $response; } } このクラスは次のように使用できます。 $app->get('/', \HomeAction::class); 繰り返しになりますが、コントローラーを使った場合と同様に、クラス名をコンテナーに登録すると、ファクトリを作成して、アクションクラスに必要としている特定の依存関係だけを注入できます。 \\