Version 4.5.0
— y2sunlight 2020-09-23
関連記事
本章は以下のサイトの Routing のセクションを翻訳し若干の補足を加えたのもです。
SlimFramework のルーターは FastRoute コンポーネントの上に構築されており、非常に高速で安定しています。このコンポーネントを使用して全てのルーティングを処理している間は、アプリのコアとそれは完全に分離されており、他のルーティングライブラリを使用をすることを容易にするためにインターフェイスが設置されています。
アプリケーションルートは、Slim\App
インスタンス上のプロキシメソッドを使用することにより定義できます。Slim Frameworkは、最も一般的なHTTPメソッドに対するメソッドを提供します。
Slimアプリケーションの get()
メソッドを使用して、GET
HTTPリクエストのみを処理するルートを追加できます。それは2つの引数を受け入れます:
$app->get('/books/{id}', function ($request, $response, array $args) { // Show book identified by $args['id'] });
Slimアプリケーションの post()
メソッドを使用して、POST
HTTPリクエストのみを処理するルート(route)を追加できます。それは2つの引数を受け入れます:
$app->post('/books', function ($request, $response, array $args) { // Create new book });
Slimアプリケーションの put()
メソッドを使用して、PUT
HTTPリクエストのみを処理するルートを追加できます。それは2つの引数を受け入れます:
$app->put('/books/{id}', function ($request, $response, array $args) { // Update book identified by $args['id'] });
Slimアプリケーションの delete()
メソッドを使用して、DELETE
HTTPリクエストのみを処理するルートを追加できます。それは2つの引数を受け入れます:
$app->delete('/books/{id}', function ($request, $response, array $args) { // Delete book identified by $args['id'] });
Slimアプリケーションの options()
メソッドを使用して、OPTIONS
HTTPリクエストのみを処理するルートを追加できます。それは2つの引数を受け入れます:
$app->options('/books/{id}', function ($request, $response, array $args) { // Return response headers });
Slimアプリケーションの patch()
メソッドを使用して、PATCH
HTTPリクエストのみを処理するルートを追加できます。それは2つの引数を受け入れます:
$app->patch('/books/{id}', function ($request, $response, array $args) { // Apply changes to book identified by $args['id'] });
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');
Slimアプリケーションの map()
メソッドを使用して、複数のHTTPリクエストメソッドを処理するルートを追加できます。それは次の3つの引数を受け入れます:
$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
の場所。文字列または Psr\Http\Message\UriInterface の場合があります。302
)$app->redirect('/books', '/library', 301);
redirect()
ルートは、要求されたステータスコードと、2番目の引数に設定された Location
ヘッダーで応答します。
ルートコールバックのシグニチャは、ルート戦略によって決定されます。デフォルトでは、Slimは、ルートコールバックがリクエスト、レスポンス、およびルートプレースホルダー引数の配列を受け入れることを期待しています。これは、RequestResponse
戦略と呼ばれます。 ただし、別の戦略を使用するだけで、期待されるルートコールバックシグニチャを変更できます。例として、Slimは、リクエストとレスポンに加えて個々に分かれた引数として各ルートプレースホルダーを受け入れる RequestResponseArgs
と呼ばれる代替戦略を提供します。
この代替戦略の使用例を次に示します:
<?php use Slim\Factory\AppFactory; use Slim\Handlers\Strategies\RequestResponseArgs; require __DIR__ . '/../vendor/autoload.php'; $app = AppFactory::create(); /** * Changing the default invocation strategy on the RouteCollector component * will change it for every route being defined after this change being applied */ $routeCollector = $app->getRouteCollector(); $routeCollector->setDefaultInvocationStrategy(new RequestResponseArgs()); $app->get('/hello/{name}', function ($request, $response, $name) { $response->getBody()->write($name); return $response; });
あるいは、ルートごとに異なる呼び出し戦略を設定することもできます:
<?php use Slim\Factory\AppFactory; use Slim\Handlers\Strategies\RequestResponseArgs; require __DIR__ . '/../vendor/autoload.php'; $app = AppFactory::create(); $routeCollector = $app->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()
を介してルーターキャッシュを有効にすることができます。以下の例を参照してください:
<?php use Slim\Factory\AppFactory; require __DIR__ . '/../vendor/autoload.php'; $app = AppFactory::create(); /** * To generate the route cache data, you need to set the file to one that does not exist in a writable directory. * After the file is generated on first run, only read permissions for the file are required. * * You may need to generate this file in a development environment and comitting it to your project before deploying * if you don't have write permissions for the directory where the cache file resides on the server it is being deployed to */ $routeCollector = $app->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
アクションメソッドを伴うコントローラーを作成します。コンストラクターは、必要な依存関係を受け入れる必要があります。 例えば:
<?php use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Slim\Views\Twig; class HomeController { private $view; public function __construct(Twig $view) { $this->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はコンテナのインスタンスをそのクラスのコンストラクタに渡します。1つのアクションのみを処理する呼び出し可能なクラスの代わりに、多くのアクションを持つコントローラーを構築できるのです。
<?php use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; class HomeController { private $container; // constructor receives container instance public function __construct(ContainerInterface $container) { $this->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');
ルート呼び出しのメソッドを指定する必要はなく、次のようなインボーク可能なアクションクラスとして設定するだけです:
<?php use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; class HomeAction { private $container; public function __construct(ContainerInterface $container) { $this->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);
繰り返しになりますが、コントローラーを使った場合と同様に、クラス名をコンテナーに登録すると、ファクトリを作成して、アクションクラスに必要としている特定の依存関係だけを注入できます。