まず、Slim\App
クラスをインスタンス化します。これはSlimアプリケーションオブジェクトです。インスタンス化の中で、Slimはアプリケーションの依存関係ごとにデフォルトのサービスを登録します。
次に、アプリケーションインスタンスの get()
、post()
、put()
、delete()
、patch()
、head()
、および options()
ルーティングメソッドを使用してルートを定義します。これらのインスタンスメソッドは、アプリケーションのルーターオブジェクトにルートを登録します。各ルーティングメソッドは Route インスタンスを返すため、Route インスタンスのメソッドをすぐに呼び出して、ミドルウェアを追加したり、名前を割り当てたりできます。
3番目に、アプリケーションインスタンスの run()
メソッドを呼び出します。このメソッドは、次のプロセスを開始します。
run()
メソッドは、アプリケーションのミドルウェア・スタックを内側に横断し始めます。これは、ミドルウェア層の同心円構造で、Slimアプリケーションの実行前(および実行後)に Environment、Request、および Responseオブジェクトを受信(またはオプションで操作)します。Slimアプリケーションは、同心円状のミドルウェア構造の最内層にあります。各ミドルウェア層は、最外層から内側に向かって呼び出されていきます。
the Not Found or Not Allowed handler is invoked.
run()
メソッドが最も内側のミドルウェア層に到達すると、アプリケーションのインスタンスを呼び出し、現在のHTTPリクエストを適切なアプリケーションのルート(route)オブジェクトにディスパッチします。ルート(route)がHTTPメソッドとURIに一致する場合、ルート(route)のミドルウェアと呼び出し可能(callable)オブジェクトが呼び出されます。一致するルートが見つからない場合は、NotFound または NotAllowed ハンドラーが呼び出されます。
アプリケーションのディスパッチプロセスが完了すると、各ミドルウェアレイヤーは、最も内側のレイヤーから始めて、外側に向かって制御を取り戻します。
最も外側のミドルウェア層が制御を引き渡した後、アプリケーションのインスタンスはHTTPレスポンスを準備し、シリアル化し、そして返します。HTTPレスポンスヘッダーはPHPのネイティブな header()
メソッドで設定され、HTTPレスポンスボディーは現在の出力バッファーに出力されます。
Slimは、Request オブジェクトと Response オブジェクトの PSR-7 インターフェイスをサポートしています。これにより、任意のPSR-7実装を使用できるようになるので、Slimはフレキシブルなものになります。例えば、GuzzleHttp\Psr7\CachingStream
のインスタンス、または GuzzleHttp\Psr7\stream_for()
関数によって返される任意のインスタンスを返すことができます。
Slimは、箱から出してすぐに機能するように、独自のPSR-7実装を提供します。但し、SlimのデフォルトのPSR-7オブジェクトをサードパーティの実装に自由に置き換えることができます。アプリケーションコンテナのrequest と response サービスをオーバーライドするだけで、それぞれ Psr\Http\Message\ServerRequestInterface
と Psr\Http\Message\ResponseInterface
のインスタンスが返されます。
Slimアプリケーションの前後にコードを実行して、必要に応じてRequestオブジェクトとResponseオブジェクトを操作できます。これはミドルウェアと呼ばれます。なぜこれが望まれるのでしょうか?おそらく、CSRFからアプリを保護したいからでしょうか。また、アプリを実行する前にリクエストを認証したい場合もあります。ミドルウェアはこれらのシナリオに最適です。
ミドルウェアは、PSR-15 ミドルウェアインターフェイスを実装します。
Psr\Http\Message\ServerRequestInterface
— PSR-7 リクエストオブジェクトPsr\Http\Server\RequestHandlerInterface
— PSR-15 リクエストハンドラオブジェクト
これらのオブジェクトを使えば、適切なことは何でもできます。唯一の難しい要件は、ミドルウェアが Psr\Http\Message\ResponseInterface
のインスタンスを返さなければならないことです( MUST
)。 各ミドルウェアは、次のミドルウェアをインボークして、引数としてリクエストオブジェクトとレスポンスオブジェクトを渡す必要があります( SHOULD
)。
フレームワークが異なれば、ミドルウェアの使用方法も異なります。Slimは、コアアプリケーションを囲む同心円状のレイヤーとしてミドルウェアを追加します。新しいミドルウェア層はそれぞれ、既存のミドルウェア層を囲みます。同心円構造は、ミドルウェア層が追加されると外側に拡張します。
追加された最後のミドルウェア層が最初に実行されます。
Slimアプリケーションを実行すると、Requestオブジェクトはミドルウェア構造を外側から内側に横断します。最初に最も外側のミドルウェアに入り、そして次に外側のミドルウェアに入り(というように)、最終的にSlimアプリケーション自体に到達します。Slimアプリケーションが適切なルート(route)をディスパッチした後、結果のResponseオブジェクトがSlimアプリケーションを終了し、ミドルウェア構造を内側から外に横断していきます。最後に、最終的なResponseオブジェクトは、最も外側のミドルウェアを出て、生のHTTPレスポンスにシリアル化され、HTTPクライアントに返されます。ミドルウェアのプロセスフローを示す図は次のとおりです。
ミドルウェアは、2つの引数を受け入れる呼び出し可能オブジェクト(callable)です。それは Request
オブジェクトと RequestHandler
オブジェクトです。各ミドルウェアは、Psr\Http\Message\ResponseInterface
のインスタンスを返さなければなりません(MUST)。
このサンプルのミドルウェアはクロージャです。
<?php use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Server\RequestHandlerInterface as RequestHandler; use Slim\Factory\AppFactory; use Slim\Psr7\Response; require __DIR__ . '/../vendor/autoload.php'; $app = AppFactory::create(); /** * Example middleware closure * * @param ServerRequest $request PSR-7 request * @param RequestHandler $handler PSR-15 request handler * * @return Response */ $beforeMiddleware = function (Request $request, RequestHandler $handler) { $response = $handler->handle($request); $existingContent = (string) $response->getBody(); $response = new Response(); $response->getBody()->write('BEFORE' . $existingContent); return $response; }; $afterMiddleware = function ($request, $handler) { $response = $handler->handle($request); $response->getBody()->write('AFTER'); return $response; }; $app->add($beforeMiddleware); $app->add($afterMiddleware); // ... $app->run();
このサンプルミドルウェアは、__invoke() マジックメソッドを実装する呼び出し可能な(invokable)クラスです。
<?php use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Server\RequestHandlerInterface as RequestHandler; use Slim\Psr7\Response; class ExampleBeforeMiddleware { /** * Example middleware invokable class * * @param ServerRequest $request PSR-7 request * @param RequestHandler $handler PSR-15 request handler * * @return Response */ public function __invoke(Request $request, RequestHandler $handler): Response { $response = $handler->handle($request); $existingContent = (string) $response->getBody(); $response = new Response(); $response->getBody()->write('BEFORE' . $existingContent); return $response; } }
<?php use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Server\RequestHandlerInterface as RequestHandler; class ExampleAfterMiddleware { /** * Example middleware invokable class * * @param ServerRequest $request PSR-7 request * @param RequestHandler $handler PSR-15 request handler * * @return Response */ public function __invoke(Request $request, RequestHandler $handler): Response { $response = $handler->handle($request); $response->getBody()->write('AFTER'); return $response; } }
これらのクラスをミドルウェアとして使用するには、 $app
のルートマッピングメソッド get()、post()、put()、patch()、delete()、options()、any()、または group()の後に 関数チェーンとして add(new ExampleMiddleware());
を使用でき、以下のコードでは、これらの内の一つを含んでいます。
<?php use Slim\Factory\AppFactory; require __DIR__ . '/../vendor/autoload.php'; $app = AppFactory::create(); // Add Middleware On App $app->add(new ExampleMiddleware()); // Add Middleware On Route $app->get('/', function () { ... })->add(new ExampleMiddleware()); // Add Middleware On Group $app->group('/', function () { ... })->add(new ExampleMiddleware()); // ... $app->run();
ミドルウェアは、全てのSlimアプリケーション、個別のSlimアプリケーションルート、またはルートグループに追加できます。全てのシナリオは同じミドルウェアを受け入れ、同じミドルウェアインターフェースを実装します。
アプリケーションミドルウェアは、全ての着信HTTPリクエストに対してインボークされます。Slimアプリケーションインスタンスの add()
メソッドを使用してアプリケーションミドルウェアを追加します。この例では、上記のクロージャミドルウェアの例を追加します。
<?php use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Server\RequestHandlerInterface as RequestHandler; use Slim\Factory\AppFactory; use Slim\Psr7\Response; require __DIR__ . '/../vendor/autoload.php'; $app = AppFactory::create(); $app->add(function (Request $request, RequestHandler $handler) { $response = $handler->handle($request); $existingContent = (string) $response->getBody(); $response = new Response(); $response->getBody()->write('BEFORE ' . $existingContent); return $response; }); $app->add(function (Request $request, RequestHandler $handler) { $response = $handler->handle($request); $response->getBody()->write(' AFTER'); return $response; }); $app->get('/', function (Request $request, Response $response, $args) { $response->getBody()->write('Hello World'); return $response; }); $app->run();
これにより、次のHTTP応答本文が出力されます:
BEFORE Hello World AFTER
ルートミドルウェアは、そのルートが現在のHTTPリクエストメソッドとURIに一致する場合にのみインボークされます。ルートミドルウェアは、Slimアプリケーションのルーティングメソッド(get()
や post()
など)を呼び出した直後に指定されます。各ルーティングメソッドは \Slim\Route
のインスタンスを返し、このクラスはSlimアプリケーションインスタンスと同じミドルウェアインターフェイスを提供します。Route
インスタンスの add()
メソッドを使用して、ミドルウェアを Route
に追加します。この例では、上記のクロージャミドルウェアの例を追加します。
<?php use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Server\RequestHandlerInterface as RequestHandler; use Slim\Factory\AppFactory; require __DIR__ . '/../vendor/autoload.php'; $app = AppFactory::create(); $mw = function (Request $request, RequestHandler $handler) { $response = $handler->handle($request); $response->getBody()->write('World'); return $response; }; $app->get('/', function (Request $request, Response $response, $args) { $response->getBody()->write('Hello '); return $response; })->add($mw); $app->run();
これにより、次のHTTPレスポンスボディーが出力されます:
Hello World
アプリケーション全体、及びミドルウェアを受け入れることができる標準的なルート(route)に加えて、group()
マルチルート定義機能も、内部的に個別のルート(route)に許可されています。ルートグループミドルウェアは、そのルートがグループから定義されたHTTPリクエストメソッド及びURIの1つと一致する場合にのみ呼び出されます。コールバック内でミドルウェアを追加するには、group()
メソッドの後に add()
をチェーンすることによってグループ全体のミドルウェアを設定します。
以下は、URLハンドラーのグループでコールバックミドルウェアを利用するサンプルアプリケーションです。
<?php use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Server\RequestHandlerInterface as RequestHandler; use Slim\Factory\AppFactory; use Slim\Routing\RouteCollectorProxy; require __DIR__ . '/../vendor/autoload.php'; $app = AppFactory::create(); $app->get('/', function (Request $request, Response $response) { $response->getBody()->write('Hello World'); return $response; }); $app->group('/utils', function (RouteCollectorProxy $group) { $group->get('/date', function (Request $request, Response $response) { $response->getBody()->write(date('Y-m-d H:i:s')); return $response; }); $group->get('/time', function (Request $request, Response $response) { $response->getBody()->write((string)time()); return $response; }); })->add(function (Request $request, RequestHandler $handler) use ($app) { $response = $handler->handle($request); $dateOrTime = (string) $response->getBody(); $response = $app->getResponseFactory()->createResponse(); $response->getBody()->write('It is now ' . $dateOrTime . '. Enjoy!'); return $response; }); $app->run();
/utils/date
メソッドを呼び出すと、次のような文字列が出力されます。
It is now 2015-07-06 03:11:01. Enjoy!
/utils/time
にアクセスすると、次のような文字列が出力されます。
It is now 1436148762. Enjoy!
ただし、/
(domain-root)にアクセスすると、ミドルウェアが割り当てられていないため、次の出力が生成されると思います。
Hello World
ミドルウェアから変数を渡す最も簡単な方法は、リクエストの属性を使用することです。
ミドルウェアでの変数の設定:
$request = $request->withAttribute('foo', 'bar');
その変数をルートコールバックで取得する:
$foo = $request->getAttribute('foo');
要求を満たすPSR-15ミドルウェアクラスがすでに作成されている場合があります。検索する非公式のリストをいくつか示します。
Slimは、オプションの依存性コンテナーを使用して、アプリケーションの依存関係を準備、管理、および注入します。Slimは、PHP-DI のような PSR-11 を実装するコンテナーをサポートします。
PSR-11の邦訳はこちらにあります。
依存関係コンテナを必ず提供する必要があるとは限りません。但し、そうする場合は、App
を作成する前に、コンテナのインスタンスを AppFactory
に与える必要があります。
<?php use DI\Container; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Slim\Factory\AppFactory; require __DIR__ . '/../vendor/autoload.php'; // Create Container using PHP-DI $container = new Container(); // Set container to create App with on AppFactory AppFactory::setContainer($container); $app = AppFactory::create();
そして、コンテナにサービスを追加します:
$container->set('myService', function () { $settings = [...]; return new MyService($settings); });
次のように、明示的にコンテナからからだけでなく、Slimアプリケーションルートの内からサービスをフェッチできます:
/** * Example GET route * * @param ServerRequestInterface $request PSR-7 request * @param ResponseInterface $response PSR-7 response * @param array $args Route parameters * * @return ResponseInterface */ $app->get('/foo', function (Request $request, Response $response, $args) { $myService = $this->get('myService'); // ...do something with $myService... return $response; });
コンテナを使用する前にサービスがコンテナに存在するかどうかをテストするには、次のように has()
メソッドを使用します:
/** * Example GET route * * @param ServerRequestInterface $request PSR-7 request * @param ResponseInterface $response PSR-7 response * @param array $args Route parameters * * @return ResponseInterface */ $app->get('/foo', function (Request $request, Response $response, $args) { if ($this->has('myService')) { $myService = $this->get('myService'); } return $response; });
コンテナに依存性が既に定義されている App
を作成する場合は、AppFactory::createFromContainer()
メソッドが使用できます。
例題
<?php use App\Factory\MyResponseFactory; use DI\Container; use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseFactoryInterface; use Slim\Factory\AppFactory; require_once __DIR__ . '/../vendor/autoload.php'; // Create Container using PHP-DI $container = new Container(); // Add custom response factory $container->set(ResponseFactoryInterface::class, function (ContainerInterface $container) { return new MyResponseFactory(...); }); // Configure the application via container $app = AppFactory::createFromContainer($container); // ... $app->run();
サポートされているアプリの依存関係は次のとおりです: