PHP-Slim Framework-log
Slim framework
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
require __DIR__ . '/../vendor/autoload.php';
$app = AppFactory::create();
$app->get('/hello/{name}', function (Request $request, Response $response, array $args) {
$name = $args['name'];
$response->getBody()->write("Hello, $name");
return $response;
});
$app->run();
Step1 Composerのインストール
Step2 Slimをインストール
プロジェクトを作りたいところに移動してcomposerのコマンドをうってSlimをダウンロードする。
vendor/というフォルダに必要なものがダウンロードされるらしい。
(ComposerはプロジェクトごとにライブラリをDLする)
cd F:\xampp\htdocs\
mkdir slim-test
cd slim-test
composer require slim/slim:"4.*"
Step3 PSR-7 Implementation と ServerRequest Creator をインストールする
公式サイトだと以下を選択して入れろといっている
- Slim PSR-7
- Nyholm PSR-7 and Nyholm PSR-7 Server
- Guzzle PSR-7
- For usage with Guzzle PSR-7 version 1:
- Laminas Diactoros
とりあえずSlim PSR-7をいれておく(フレームワークと同じ名前のやついれとけばええやろ精神)
Step 4: Hello World
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
require __DIR__ . '/../vendor/autoload.php';
$app = AppFactory::create();
-$app->get('/', function (Request $request, Response $response, $args) {
+$app->get('/slim-test/public/', function (Request $request, Response $response, $args) {
$response->getBody()->write("Hello world!");
return $response;
});
$app->run();
xammpのhdocsにpublicフォルダとその中にindex.phpを作って http://localhost/slim-test/public/ にアクセス。
hello worldが表示された。ワッショイ。
そのままだと動かなかったのでgetしてる先のパスを書き換えた。
参考URL:
Composer?
Composer は、PHP のプロジェクトが必要とするライブラリやパッケージを管理する「ライブラリ依存管理ツール」です。 その PHP プロジェクトで必要なパッケージ(ライブラリ)は何かを列挙すると、それらを自動的にインストールしてくれる機能を持ちます。
ははーん。npmとかnodeとかpipとかなんかそんな感じね????
Composerのインストール(Win)
Get Started
ComposerインストールしたのでGet Startedどおりに進めていく。
Slim は、シンプルかつ強力な Web アプリケーションや API を素早く作成するのに役立つ PHP のマイクロフレームワークです。Slim の中核となるのは、HTTP リクエストを受け取り、適切なコールバック ルーチンを呼び出して HTTP 応答を返すディスパッチャです。それだけです。
何が言いたいのか?
Slim は、データを消費、再利用、または公開する API を作成するための理想的なツールです。また、Slim はラピッドプロトタイピングのための素晴らしいツールでもあります。さらに、ユーザー インターフェースを備えたフル機能のウェブ アプリケーションを構築することもできます。さらに重要なのは、Slim は超高速で、コードがほとんどないことです。
Slim の中核となるのは、HTTP リクエストを受け取り、適切なコールバック ルーチンを呼び出して、HTTP レスポンスを返すディスパッチャです。これだけです。
Symfony や Laravel のような厨二病的なソリューションが常に必要なわけではありません。確かにこれらは素晴らしいツールです。しかし、これらはしばしば過剰になりがちです。その代わり、Slimは必要なことを行う最小限のツールセットだけを提供し、それ以外のことは行いません。
どのように動作するのでしょうか?
まず、Nginx や Apache のようなウェブサーバーが必要です。適切なすべてのリクエストを 1 つの「front-controller」PHP ファイルに送信するように、ウェブサーバーを設定する必要があります。この PHP ファイルで Slim アプリをインスタンス化し、実行します。
Slim アプリには、特定の HTTP リクエストに応答するルートが含まれています。各ルートはコールバックを呼び出して、HTTP レスポンスを返します。開始するには、まず Slim アプリケーションをインスタンス化して構成します。次に、アプリケーションのルートを定義します。最後に、Slim アプリケーションを実行します。とても簡単です。以下は、アプリケーションの例です。
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
require __DIR__ . '/../vendor/autoload.php';
/**
* Instantiate App
*
* In order for the factory to work you need to ensure you have installed
* a supported PSR-7 implementation of your choice e.g.: Slim PSR-7 and a supported
* ServerRequest creator (included with Slim PSR-7)
*/
$app = AppFactory::create();
/**
* The routing middleware should be added earlier than the ErrorMiddleware
* Otherwise exceptions thrown from it will not be handled by the middleware
*/
$app->addRoutingMiddleware();
/**
* Add Error Middleware
*
* @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
* @param LoggerInterface|null $logger -> Optional PSR-3 Logger
*
* 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);
// Define app routes
$app->get('/hello/{name}', function (Request $request, Response $response, $args) {
$name = $args['name'];
$response->getBody()->write("Hello, $name");
return $response;
});
// Run app
$app->run();
🤔?
リクエストとレスポンス
Slim アプリを構築する際には、多くの場合 Request と Response オブジェクトを直接操作することになります。これらのオブジェクトは、Web サーバーが受信した実際の HTTP リクエストと、最終的にクライアントに返される HTTP レスポンスを表します。
すべての Slim アプリのルートには、そのコールバックルーチンの引数として現在の Request および Response オブジェクトが渡されます。これらのオブジェクトは、一般的な PSR-7 インターフェースを実装しています。Slim アプリのルートは、必要に応じてこれらのオブジェクトを検査または操作することができます。最終的に、各 Slim アプリルートは PSR-7 応答オブジェクトを返さなければなりません(MUST)。
独自のコンポーネントを導入する
Slim は、他の PHP コンポーネントともうまく連携できるように設計されています。Slim-Csrf や Slim-HttpCache、Slim-Flash など、Slim のデフォルトの機能をベースにしたファーストパーティーのコンポーネントを追加登録することが可能です。また、Packagist に掲載されているサードパーティーのコンポーネントを簡単に統合することができます。
このドキュメントの読み方
Slim を初めて利用する場合は、このドキュメントを最初から最後まで読むことをお勧めします。すでにSlimに慣れている方は、代わりに適切なセクションに直接ジャンプすることができます。
このドキュメントは、Slim の概念とアーキテクチャの説明から始まり、リクエストとレスポンスの処理、ルーティング、エラー処理などの特定のトピックに踏み込みます。
🤔🤔?
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
ライブラリの使用を宣言している(と思われる)
Javaのimportみたいにフォルダになってるのかと思ったけどそうでもないみたい。
ResponseInterface.phpの中にnamespace Psr\Http\Message
と定義されてた。
$app = AppFactory::create();
SlimFrameworkのAppクラスを生成。
アプリケーションのコア的な部分なのかな。
$app->addRoutingMiddleware();
Appが持つaddRoutingMiddleware()関数を呼ぶ。なにしてるかは知らんけど、ルーティングっていってるんだからルーティングの下準備でしょ!
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
エラーハンドリングするミドルウェア?を追加してる?
// Define app routes
$app->get('/hello/{name}', function (Request $request, Response $response, $args) {
$name = $args['name'];
$response->getBody()->write("Hello, $name");
return $response;
});
Getリクエストの処理?
/hello/ほげほげにアクセスされたらfunction~を実行。
functionは $argsからnameを取得、レスポンスのBodyに hello,名前を書き込んでresponseとして返してる。
結果、ページに hello,名前が出るって感じか。
匿名関数のところがよくわからんけどここで深堀するのはハマりそうだからいったんこのまま。
PHP built-in server
ターミナルで以下のコマンドを実行し、localhostのWebサーバーを起動します。./public/が公開可能なディレクトリで、index.phpファイルがあると仮定します。
警告内蔵のウェブサーバーは、アプリケーションの開発を支援するために設計されています。また、テスト目的や制御された環境で実行されるアプリケーションのデモにも有用です。これは、全機能を備えたウェブサーバーとして意図されているわけではありません。公共のネットワークで使用するべきではありません。
PHPにビルドインされてるWebサーバを使うけど、本番環境とかでは使うなよ!って話。
// ここは各WEBサーバにインストールするところの手順っぽいから後回し。
Deployment
おめでとうございます!ここまで来られたということは、Slimを使って何か素晴らしいものを作ることに成功されたのだと思います。しかし、パーティーをする時間はまだ来ていません。まだ、アプリケーションを本番サーバーにプッシュしなければならないのです。
これを行うには多くの方法がありますが、このドキュメントの範囲を超えています。このセクションでは、さまざまなセットアップのためのいくつかのメモを提供します。
// ここも本番サーバにDeployするところ関連のようなので後回し
Slim-Skeleton
Github URL
このスケルトン・アプリケーションを使用して、新しい Slim Framework 4 アプリケーションをすばやくセットアップして作業を開始することができます。このアプリケーションでは、最新の Slim 4 と Slim PSR-7 の実装、および PHP-DI コンテナーの実装を使用しています。また、Monolog ロガーを使用しています。
このスケルトン・アプリケーションは Composer 用に作成されています。これにより、新しい Slim Framework アプリケーションを迅速かつ簡単にセットアップすることができます。
インストール
新しい Slim Framework アプリケーションをインストールするディレクトリから、このコマンドを実行します。PHP 7.4 またはそれ以降が必要です。
composer create-project slim/slim-skeleton [my-app-name]
my-app-name]を新しいアプリケーションのディレクトリ名に置き換えてください。したくなるはずです。
バーチャルホストのドキュメントルートを、新しいアプリケーションの public/ ディレクトリに指定します。
logs/ がウェブ書き込み可能であることを確認します。
composer create-project slim/slim-skeleton myapp
を実行。
実行結果
Creating a "slim/slim-skeleton" project at "./myapp"
Info from https://repo.packagist.org: #StandWithUkraine
Installing slim/slim-skeleton (4.5.0)
Failed to download slim/slim-skeleton from dist: The zip extension and unzip/7z commands are both missing, skipping.
The php.ini used by your command-line PHP is: F:\xampp\php\php.ini
Now trying to download from source
- Syncing slim/slim-skeleton (4.5.0) into cache
- Installing slim/slim-skeleton (4.5.0): Cloning 1997d86c18 from cache
Created project in F:\xampp\htdocs\myapp
Loading composer repositories with package information
Updating dependencies
Lock file operations: 55 installs, 0 updates, 0 removals
- Locking doctrine/instantiator (2.0.0)
- Locking fig/http-message-util (1.1.5)
- Locking jangregor/phpstan-prophecy (1.0.0)
- Locking laravel/serializable-closure (v1.3.0)
- Locking monolog/monolog (2.9.1)
- Locking myclabs/deep-copy (1.11.0)
- Locking nikic/fast-route (v1.3.0)
- Locking nikic/php-parser (v4.15.3)
- Locking phar-io/manifest (2.0.3)
- Locking phar-io/version (3.2.1)
- Locking php-di/invoker (2.3.3)
- Locking php-di/php-di (6.4.0)
- Locking php-di/phpdoc-reader (2.2.1)
- Locking phpdocumentor/reflection-common (2.2.0)
- Locking phpdocumentor/reflection-docblock (5.3.0)
- Locking phpdocumentor/type-resolver (1.6.2)
- Locking phpspec/prophecy (v1.17.0)
- Locking phpspec/prophecy-phpunit (v2.0.1)
- Locking phpstan/extension-installer (1.2.0)
- Locking phpstan/phpstan (1.10.3)
- Locking phpunit/php-code-coverage (9.2.25)
- Locking phpunit/php-file-iterator (3.0.6)
- Locking phpunit/php-invoker (3.1.1)
- Locking phpunit/php-text-template (2.0.4)
- Locking phpunit/php-timer (5.0.3)
- Locking phpunit/phpunit (9.6.4)
- Locking psr/container (1.1.2)
- Locking psr/http-factory (1.0.1)
- Locking psr/http-message (1.0.1)
- Locking psr/http-server-handler (1.0.1)
- Locking psr/http-server-middleware (1.0.1)
- Locking psr/log (3.0.0)
- Locking ralouphie/getallheaders (3.0.3)
- Locking sebastian/cli-parser (1.0.1)
- Locking sebastian/code-unit (1.0.8)
- Locking sebastian/code-unit-reverse-lookup (2.0.3)
- Locking sebastian/comparator (4.0.8)
- Locking sebastian/complexity (2.0.2)
- Locking sebastian/diff (4.0.4)
- Locking sebastian/environment (5.1.5)
- Locking sebastian/exporter (4.0.5)
- Locking sebastian/global-state (5.0.5)
- Locking sebastian/lines-of-code (1.0.3)
- Locking sebastian/object-enumerator (4.0.4)
- Locking sebastian/object-reflector (2.0.4)
- Locking sebastian/recursion-context (4.0.5)
- Locking sebastian/resource-operations (3.0.3)
- Locking sebastian/type (3.2.1)
- Locking sebastian/version (3.0.2)
- Locking slim/psr7 (1.6)
- Locking slim/slim (4.11.0)
- Locking squizlabs/php_codesniffer (3.7.2)
- Locking symfony/polyfill-php80 (v1.27.0)
- Locking theseer/tokenizer (1.2.1)
- Locking webmozart/assert (1.11.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 55 installs, 0 updates, 0 removals
Failed to download phpstan/phpstan from dist: The zip extension and unzip/7z commands are both missing, skipping.
The php.ini used by your command-line PHP is: F:\xampp\php\php.ini
Now trying to download from source
- Syncing phpstan/phpstan (1.10.3) into cache
なんかエラーでた。
Failed to download slim/slim-skeleton from dist: The zip extension and unzip/7z commands are both missing
zip展開用のなにかが足りなくて怒られてるらしい。
上記のログ以降もモリモリ足りないと怒られた。
ぐぐる。
For PHP8.2 (Windows)
As stated here: https://www.php.net/manual/en/zip.installation.php#zip.installation.new.windows
As of PHP 8.2.0, php_zip.dll DLL must be enabled in php.ini. Previously, this extension was built-in.
You will need to manually enable this extension within your php.ini by adding extension=php_zip.dll
For a list of installed extensions you can run:
php -m or if you have grep installed even easier would be:
php -m | grep "zip"
php.ini のextensionが書かれているところにextension=php_zip.dll
を追加。
php -m | grep "zip"でzipがあることを確認。
一度作ったmyapp
を削除してもう一度コマンドを叩く。
できたっぽい!
apache のdocument rootを作成したmyapp/publicに変更しろって書いてあるのでXAMPPのapache設定変えた.
-DocumentRoot "F:/xampp/htdocs"
+DocumentRoot "F:/xampp/htdocs/myapps/public"
-<Directory "F:/xampp/htdocs">
+<Directory "F:/xampp/htdocs/myapps/public">
apacheが起動できなくなったのでやめた。
phpのwebサーバあるみたいなので叩いてみる
php -S localhost:8080 -t public .\public\index.php
-S ビルドインWebサーバ localhost:8080 と指定する
-t public? .\public\index.php をドキュメントルートにする
ブラウザでhttp://localhost:8080/にアクセス
→hello worldが表示された。
skeletonだけど解説がすくなくてよくわからん!!UserGuideに戻る
アプリケーションのライフサイクル
1.インスタンス化
まず、SlimApp クラスをインスタンス化します。これは、Slim アプリケーション・オブジェクトです。インスタンス化の際に、Slim は各アプリケーションの依存関係に対してデフォルトのサービスを登録します。
2.ルートの定義
次に、アプリケーションのインスタンスの get()、post()、put()、delete()、patch()、head()、および options() ルーティングメソッドを使用して、ルートを定義します。これらのインスタンスメソッドは、アプリケーションのRouterオブジェクトにルートを登録します。各ルーティングメソッドはRouteインスタンスを返すので、Routeインスタンスのメソッドをすぐに呼び出してミドルウェアを追加したり、名前を割り当てたりすることができます。
3.アプリケーションランナー
3つ目は、アプリケーションインスタンスのrun()メソッドを呼び出すことです。このメソッドにより、以下の処理が開始されます。
A.ミドルウェアスタックに入る
run() メソッドは、アプリケーションのミドルウェア・スタックを内側に走査し始めます。これは、Slim アプリケーションの実行前 (および実行後) に環境、要求、および応答オブジェクトを受け取り (オプションで操作し)、ミドルウェア層が同心円状に配置された構造です。Slim アプリケーションは、同心円状のミドルウェア構造の最も内側の層です。各ミドルウェア層は、一番外側の層から内側に向かって呼び出されます。
B.実行アプリケーション
run() メソッドが最内層のミドルウェア層に到達すると、アプリケーションのインスタンスが呼び出され、現在の HTTP リクエストが適切なアプリケーションルートオブジェクトにディスパッチされます。HTTPメソッドとURIにマッチするルートがあれば、そのルートのミドルウェアとcallableが呼び出されます。一致するルートが見つからない場合は、Not Found または Not Allowed ハンドラが呼び出されます。
C.ミドルウェアスタックの終了
アプリケーションのディスパッチ処理が完了すると、各ミドルウェア層は、最も内側の層から順に、外側に制御を取り戻します。
D.HTTPレスポンスの送信
最外層のミドルウェア層が制御を引き継いだ後、アプリケーションインスタンスは HTTP レスポンスを準備し、シリアライズして返します。HTTP レスポンスヘッダは PHP のネイティブな header() メソッドで設定され、 HTTP レスポンスボディは現在の出力バッファに出力されます。
PSR-7 and Value Objects
Slim は、リクエストとレスポンス オブジェクトのために PSR-7 インターフェイスをサポートしています。これにより、Slim は任意の PSR-7 の実装を使用できるため、柔軟性があります。例えば、GuzzleHttpPsr7CachingStreamのインスタンスやGuzzleHttpPsr7Cachingstream_for()関数が返す任意のインスタンスを返すことができます。
Slim は、独自の PSR-7 実装を提供します。ただし、サードパーティ製の実装をインストールすることは自由です。
Value objects
リクエストオブジェクトとレスポンスオブジェクトは、イミュータブルなバリューオブジェクトです。これらは、更新されたプロパティ値を持つ複製されたバージョンを要求することによってのみ、「変更」することができます。値オブジェクトは、そのプロパティが更新されたときに複製されなければならないので、わずかなオーバーヘッドがあります。このオーバーヘッドは、性能に影響を与えることはありません。
PSR-7 インタフェースメソッド (これらのメソッドには通常 with というプレフィックスがつきます) を呼び出すことで、バリューオブジェクトのコピーを要求することができます。たとえば、PSR-7 のレスポンスオブジェクトには withHeader($name, $value) メソッドがあり、 新しい HTTP ヘッダーを持つクローンされた値オブジェクトを返します。
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
require __DIR__ . '/../vendor/autoload.php';
$app = AppFactory::create();
$app->get('/foo', function (Request $request, Response $response, array $args) {
$payload = json_encode(['hello' => 'world'], JSON_PRETTY_PRINT);
$response->getBody()->write($payload);
return $response->withHeader('Content-Type', 'application/json');
});
$app->run();
PSR-7 インタフェースは、Request および Response オブジェクトを変換するために、これらのメソッドを提供する。
withProtocolVersion($version)
withHeader($name, $value)
withAddedHeader($name, $value)
withoutHeader($name)
withBody(StreamInterface $body)
PSR-7 インターフェイスは、Request オブジェクトを変換するための メソッドを提供します。
withMethod($method)
withUri(UriInterface $uri, $preserveHost = false)
withCookieParams(array $cookies)
withQueryParams(array $query)
withUploadedFiles(array $uploadedFiles)
withParsedBody($data)
withAttribute($name, $value)
withoutAttribute($name)
PSR-7 インターフェイスは、レスポンスオブジェクトを変換するためのメソッドを提供します。
withStatus($code, $reasonPhrase = '')
これらのメソッドについての詳細な情報は、 PSR-7 のドキュメントを参照ください。
Middleware
Slim アプリケーションの前後にコードを実行し、Request と Response オブジェクトを自由に操作することができます。これはミドルウェアと呼ばれます。なぜ、このようなことをしたいのでしょうか?クロスサイト・リクエスト・フォージェリからアプリを保護するためでしょうか。あるいは、アプリを実行する前にリクエストを認証したいかもしれません。ミドルウェアはこのようなシナリオに最適です。
ミドルウェアとは?
ミドルウェアは、PSR-15 ミドルウェアインタフェースを実装しています。
PsrHttpServerRequestInterface - PSR-7 リクエストオブジェクト
PsrHttpMessageGuideServerRequestInterface - PSR-15リクエストハンドラーオブジェクト
これらのオブジェクトに対して、適切な処理を行うことができる。唯一のハード要件は、ミドルウェアがPsrHttpMessageのResponseInterfaceのインスタンスを返さなければならない(MUST)ことである。各ミドルウェアは、次のミドルウェアを起動し、Requestオブジェクトを引数として渡す べきである(SHOULD)。
ミドルウェアはどのように機能するのですか?
フレームワークによって、ミドルウェアの使い方は異なります。Slim は、コア アプリケーションを囲む同心円状の層としてミドルウェアを追加します。新しいミドルウェアの層は、既存のミドルウェアの層を取り囲みます。同心円状の構造は、ミドルウェアの追加に伴って外側に広がっていきます。
最後に追加されたミドルウェアの層が、最初に実行されます。
Slim アプリケーションを実行すると、Request オブジェクトはミドルウェア構造を外側から内側へと横断します。まず一番外側のミドルウェアに入り、次に次の一番外側のミドルウェアに入り (以下同様)、最終的に Slim アプリケーション自体に到達します。Slim アプリケーションが適切なルートをディスパッチした後、生成された応答オブジェクトは Slim アプリケーションを出て、ミドルウェア構造を内側から外側へと走査します。最終的に、Response オブジェクトは一番外側のミドルウェアを出て、生の HTTP 応答にシリアライズされ、HTTP クライアントに返されます。以下は、ミドルウェアの処理の流れを示す図です。
ミドルウェアはどのように書けばよいのですか?
ミドルウェアは、RequestオブジェクトとRequestHandlerオブジェクトの2つの引数を受け付けるcallableです。各ミドルウェアは、PsrHttpMessageのResponseInterfaceのインスタンスを返さなければなりません(MUST)。
クロージャミドルウェアの例
このミドルウェアの例は、Closure.
<?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() を実装したインボーカブルクラスです。
<?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;
}
}
ミドルウェアを追加する方法を教えてください。
ミドルウェアは、Slim アプリケーション、Slim アプリケーションの個別のルート、またはルート グループに追加することができます。すべてのシナリオで、同じミドルウェアを受け入れ、同じミドルウェアインターフェースを実装します。
<?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
Route middleware
ルートミドルウェアは、そのルートが現在の HTTP リクエストメソッドと URI に一致する場合にのみ呼び出されます。ルートミドルウェアは、Slim アプリケーションのルーティングメソッド (例: get() や post()) を呼び出した直後に指定します。各ルーティング・メソッドは \SlimRoute のインスタンスを返し、このクラスは Slim アプリケーションのインスタンスと同じミドルウェア・インターフェースを提供します。Route にミドルウェアを追加するには、Route インスタンスの add() メソッドを使用します。この例では、上記の Closure ミドルウェアの例を追加しています。
<?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
Group middleware
アプリケーション全体や標準ルートがミドルウェアを受け入れるだけでなく、group()の複数ルート定義機能により、内部で個別のルートも受け入れることができます。ルートグループのミドルウェアは、そのルートがグループ内で定義されたHTTPリクエストメソッドとURIのいずれかにマッチする場合にのみ呼び出されます。コールバック内でミドルウェアを追加し、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');
``
ルートコールバックで変数を取得する。
```php
$foo = $request->getAttribute('foo');
利用可能なミドルウェアを探す
PSR-15 ミドルウェアのクラスがすでに書かれていて、あなたのニーズを満たすものが見つかるかもしれません。ここでは、いくつかの非公式なリストを紹介します。
Slim Framework v4.x 用ミドルウェア wiki
middlewares/awesome-psr15-middlewares (英語)
requestとresponseの間に色々挟めるよ~って機能だと理解。
実装方法とかは一旦置いておく。こういう機能があるよってだけ頭の隅に置く。
Dependency Container
Slim は、アプリケーションの依存関係を準備、管理、注入するために、オプションの依存関係コンテナを使用します。Slim は、PHP-DI のような PSR-11 を実装するコンテナーをサポートします。
Example usage with PHP-DI (PHP-DIによる使用例)
<?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;
});
🤔
Application
Application SlimAppはSlimアプリケーションのエントリーポイントで、コールバックやコントローラーにリンクするルートを登録するために使用します。
code
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
require __DIR__ . '/../vendor/autoload.php';
// Instantiate app
$app = AppFactory::create();
// Add Error Handling Middleware
$app->addErrorMiddleware(true, false, false);
// Add route callbacks
$app->get('/', function (Request $request, Response $response, array $args) {
$response->getBody()->write('Hello World');
return $response;
});
// Run application
$app->run();
Advanced Notices and Warnings Handling
警告と通知は、デフォルトでは捕捉されません。もし、これらの現象が発生したときにエラーページを表示させたい場合は、以下のindex.phpのようなコードを実装する必要があります。
code
<?php
use MyApp\Handlers\HttpErrorHandler;
use MyApp\Handlers\ShutdownHandler;
use Slim\Exception\HttpInternalServerErrorException;
use Slim\Factory\AppFactory;
use Slim\Factory\ServerRequestCreatorFactory;
require __DIR__ . '/../vendor/autoload.php';
// Set that to your needs
$displayErrorDetails = true;
$app = AppFactory::create();
$callableResolver = $app->getCallableResolver();
$responseFactory = $app->getResponseFactory();
$serverRequestCreator = ServerRequestCreatorFactory::create();
$request = $serverRequestCreator->createServerRequestFromGlobals();
$errorHandler = new HttpErrorHandler($callableResolver, $responseFactory);
$shutdownHandler = new ShutdownHandler($request, $errorHandler, $displayErrorDetails);
register_shutdown_function($shutdownHandler);
// Add Routing Middleware
$app->addRoutingMiddleware();
// Add Error Handling Middleware
$errorMiddleware = $app->addErrorMiddleware($displayErrorDetails, false, false);
$errorMiddleware->setDefaultErrorHandler($errorHandler);
$app->run();
Advanced Custom Error Handler
code
<?php
namespace MyApp\Handlers;
use Psr\Http\Message\ResponseInterface;
use Slim\Exception\HttpBadRequestException;
use Slim\Exception\HttpException;
use Slim\Exception\HttpForbiddenException;
use Slim\Exception\HttpMethodNotAllowedException;
use Slim\Exception\HttpNotFoundException;
use Slim\Exception\HttpNotImplementedException;
use Slim\Exception\HttpUnauthorizedException;
use Slim\Handlers\ErrorHandler;
use Exception;
use Throwable;
class HttpErrorHandler extends ErrorHandler
{
public const BAD_REQUEST = 'BAD_REQUEST';
public const INSUFFICIENT_PRIVILEGES = 'INSUFFICIENT_PRIVILEGES';
public const NOT_ALLOWED = 'NOT_ALLOWED';
public const NOT_IMPLEMENTED = 'NOT_IMPLEMENTED';
public const RESOURCE_NOT_FOUND = 'RESOURCE_NOT_FOUND';
public const SERVER_ERROR = 'SERVER_ERROR';
public const UNAUTHENTICATED = 'UNAUTHENTICATED';
protected function respond(): ResponseInterface
{
$exception = $this->exception;
$statusCode = 500;
$type = self::SERVER_ERROR;
$description = 'An internal error has occurred while processing your request.';
if ($exception instanceof HttpException) {
$statusCode = $exception->getCode();
$description = $exception->getMessage();
if ($exception instanceof HttpNotFoundException) {
$type = self::RESOURCE_NOT_FOUND;
} elseif ($exception instanceof HttpMethodNotAllowedException) {
$type = self::NOT_ALLOWED;
} elseif ($exception instanceof HttpUnauthorizedException) {
$type = self::UNAUTHENTICATED;
} elseif ($exception instanceof HttpForbiddenException) {
$type = self::UNAUTHENTICATED;
} elseif ($exception instanceof HttpBadRequestException) {
$type = self::BAD_REQUEST;
} elseif ($exception instanceof HttpNotImplementedException) {
$type = self::NOT_IMPLEMENTED;
}
}
if (
!($exception instanceof HttpException)
&& ($exception instanceof Exception || $exception instanceof Throwable)
&& $this->displayErrorDetails
) {
$description = $exception->getMessage();
}
$error = [
'statusCode' => $statusCode,
'error' => [
'type' => $type,
'description' => $description,
],
];
$payload = json_encode($error, JSON_PRETTY_PRINT);
$response = $this->responseFactory->createResponse($statusCode);
$response->getBody()->write($payload);
return $response;
}
}
Advanced Shutdown Handler
(Advanced Shutdown Handlerってなんだ)
code
<?php
namespace MyApp\Handlers;
use MyApp\Handlers\HttpErrorHandler;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Exception\HttpInternalServerErrorException;
use Slim\ResponseEmitter;
class ShutdownHandler
{
/**
* @var Request
*/
private $request;
/**
* @var HttpErrorHandler
*/
private $errorHandler;
/**
* @var bool
*/
private $displayErrorDetails;
/**
* ShutdownHandler constructor.
*
* @param Request $request
* @param HttpErrorHandler $errorHandler
* @param bool $displayErrorDetails
*/
public function __construct(Request $request, HttpErrorHandler $errorHandler, bool $displayErrorDetails) {
$this->request = $request;
$this->errorHandler = $errorHandler;
$this->displayErrorDetails = $displayErrorDetails;
}
public function __invoke()
{
$error = error_get_last();
if ($error) {
$errorFile = $error['file'];
$errorLine = $error['line'];
$errorMessage = $error['message'];
$errorType = $error['type'];
$message = 'An error while processing your request. Please try again later.';
if ($this->displayErrorDetails) {
switch ($errorType) {
case E_USER_ERROR:
$message = "FATAL ERROR: {$errorMessage}. ";
$message .= " on line {$errorLine} in file {$errorFile}.";
break;
case E_USER_WARNING:
$message = "WARNING: {$errorMessage}";
break;
case E_USER_NOTICE:
$message = "NOTICE: {$errorMessage}";
break;
default:
$message = "ERROR: {$errorMessage}";
$message .= " on line {$errorLine} in file {$errorFile}.";
break;
}
}
$exception = new HttpInternalServerErrorException($this->request, $message);
$response = $this->errorHandler->__invoke($this->request, $exception, $this->displayErrorDetails, false, false);
if (ob_get_length()) {
ob_clean();
}
$responseEmitter = new ResponseEmitter();
$responseEmitter->emit($response);
}
}
Request
Slim アプリのルートとミドルウェアには、Web サーバーが受信した現在の HTTP リクエストを表す PSR-7 リクエスト オブジェクトが渡されます。リクエスト オブジェクトは PSR-7 ServerRequestInterface を実装しており、HTTP リクエスト メソッド、ヘッダー、ボディを検査および操作することができます。
How to get the Request object/Requestオブジェクトの取得方法
PSR-7 リクエスト オブジェクトは、次のようにルート コールバックの最初の引数として、Slim アプリケーション ルートに注入されます。
code
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
require __DIR__ . '/../vendor/autoload.php';
$app = AppFactory::create();
$app->get('/hello', function (Request $request, Response $response) {
$response->getBody()->write('Hello World');
return $response;
});
$app->run();
図1:アプリケーションルートのコールバックにPSR-7リクエストをインジェクトする。
PSR-7リクエストオブジェクトは、このようにミドルウェアの呼び出し可能な第一引数としてSlimアプリケーションミドルウェアに注入されます。
code
<?php
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();
$app->add(function (Request $request, RequestHandler $handler) {
return $handler->handle($request);
});
// ...define app routes...
$app->run();
The Request Method
すべてのHTTPリクエストは、典型的には以下のいずれかのメソッドを持っています。
- GET
- POST
- PUT
- DELETE
- HEAD
- PATCH
- OPTIONS
HTTPリクエストのメソッドを調べるには、RequestオブジェクトのメソッドにgetMethod()という適切な名前のメソッドがあります。
$method = $request->getMethod();
HTTPリクエストメソッドを偽ったり上書きしたりすることができます。これは、例えば、GETまたはPOSTリクエストのみをサポートする従来のWebブラウザを使用してPUTリクエストを模倣する必要がある場合に便利です。
注意事項
リクエストメソッドのオーバーライドを有効にするには、Method Overriding Middlewareをアプリケーションにインジェクトする必要があります。
HTTPリクエストメソッドをオーバーライドするには、2つの方法があります。POSTリクエストのボディにMETHODパラメータを含めることができます。HTTPリクエストは、application/x-www-form-urlencodedコンテンツタイプを使用する必要があります。
POST /path HTTP/1.1
Host: example.com
Content-type: application/x-www-form-urlencoded
Content-length: 22
data=value&_METHOD=PUT
また、カスタムのX-Http-Method-Override HTTPリクエストヘッダを使用して、HTTPリクエストメソッドをオーバーライドすることができます。これは、あらゆるHTTPリクエストのコンテンツタイプで機能します。
POST /path HTTP/1.1
Host: example.com
Content-type: application/json
Content-length: 16
X-Http-Method-Override: PUT
{"data":"value"}
The Request URI
すべてのHTTPリクエストには、要求されたアプリケーションリソースを識別するURIがあります。HTTPリクエストのURIは、いくつかの部分から構成されています。
- Scheme (e.g. http or https)
- Host (e.g. example.com)
- Port (e.g. 80 or 443)
- Path (e.g. /users/1)
- Query string (e.g. sort=created&dir=asc)
PSR-7 Request オブジェクトの URI オブジェクトは、getUri() メソッドで取得することができます。
$uri = $request->getUri();
PSR-7 Request オブジェクトの URI は、それ自体がオブジェクトであり、HTTP リクエストの URL 部分を検査するための以下のメソッドを提供します。
- getScheme()
- getAuthority()
- getUserInfo()
- getHost()
- getPort()
- getPath()
- getQuery() (returns the full query string, e.g. a=1&b=2)
- getFragment()
クエリパラメータは、getQueryParams()を使ってRequestオブジェクトの連想配列として取得することができます。
The Request Headers
すべてのHTTPリクエストにはヘッダーがあります。これらは HTTP リクエストを説明するメタデータですが、リクエストのボディには表示されません。Slim の PSR-7 リクエスト オブジェクトには、そのヘッダーを検査するためのメソッドがいくつか用意されています。
Get All Headers
PSR-7 Request オブジェクトの getHeaders() メソッドを使用すると、すべての HTTP リクエストヘッダーを連想配列として取得することができます。連想配列のキーはヘッダー名で、値はヘッダー名を表す文字列の数値配列となります。
$headerValueArray = $request->getHeader('Accept');
PSR-7 リクエストオブジェクトの getHeaderLine(
$headerValueString = $request->getHeaderLine('Accept');
Detect Header
ヘッダーの有無を調べるには、PSR-7 Request オブジェクトの hasHeader($name) メソッドを使用します。
if ($request->hasHeader('Accept')) {
// Do something
}
The Request Body
すべての HTTP リクエストにはボディがあります。JSON や XML データを消費する Slim アプリケーションを作成する場合は、 PSR-7 リクエストオブジェクトの getParsedBody() メソッドを使用して HTTP リクエストボディを解析し、 PHP のネイティブフォーマットに変換することができます。ボディのパース方法は、PSR-7 の実装によって異なることに注意しましょう。
インストールされている PSR-7 の実装によっては、 受信した入力をパースするためのミドルウェアを実装する必要があるかもしれません。以下は、入力された JSON をパースする例です。
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
class JsonBodyParserMiddleware implements MiddlewareInterface
{
public function process(Request $request, RequestHandler $handler): Response
{
$contentType = $request->getHeaderLine('Content-Type');
if (strstr($contentType, 'application/json')) {
$contents = json_decode(file_get_contents('php://input'), true);
if (json_last_error() === JSON_ERROR_NONE) {
$request = $request->withParsedBody($contents);
}
}
return $handler->handle($request);
}
}
$parsedBody = $request->getParsedBody();
技術的には、PSR-7 Requestオブジェクトは、HTTPリクエストボディをPsrHttpMessageStreamInterfaceのインスタンスとして表現する。
PSR-7 RequestオブジェクトのgetBody()メソッドでHTTPリクエストボディのStreamInterfaceインスタンスを取得することができます。
受信したHTTPリクエストのサイズが不明な場合や、利用可能なメモリに対して大きすぎる場合は、getBody()メソッドを使用することが望ましいです。
$body = $request->getBody();
その結果、PsrHttpのメッセージStreamInterfaceインスタンスは、その基礎となるPHPリソースを読み、反復するための以下のメソッドを提供します。
- getSize()
- tell()
- eof()
- isSeekable()
- seek()
- rewind()
- isWritable()
- write($string)
- isReadable()
- read($length)
- getContents()
- getMetadata($key = null)
Uploaded Files
FILESのファイルアップロードは、RequestオブジェクトのgetUploadedFiles()メソッドから利用できます。これは、入力要素の名前をキーにした配列を返します。
$files = $request->getUploadedFiles();
files配列の各オブジェクトはPsrHttpMessageのインスタンスであり、以下のメソッドをサポートします。
- getStream()
- moveTo($targetPath)
- getSize()
- getError()
- getClientFilename()
- getClientMediaType()
POSTフォームを使用してファイルをアップロードする方法については、クックブックを参照してください。
クックブック:https://www.slimframework.com/docs/v4/cookbook/uploading-files.html
Request Helpers
SlimのPSR-7 Requestの実装は、HTTPリクエストをさらに検査するのに役立つ、これらの追加の独自メソッドを提供します。
Detect XHR requests
XHRリクエストは、RequestのgetHeaderLine()メソッドでXMLHttpRequestのヘッダーX-Requested-Withがあるかどうかをチェックすることで検出できます。
POST /path HTTP/1.1
Host: example.com
Content-type: application/x-www-form-urlencoded
Content-length: 7
X-Requested-With: XMLHttpRequest
foo=bar
if ($request->getHeaderLine('X-Requested-With') === 'XMLHttpRequest') {
// Do something
}
Content Type
HTTPリクエストのコンテンツタイプは、RequestオブジェクトのgetHeaderLine()メソッドで取得できます。
$contentType = $request->getHeaderLine('Content-Type');
Content Length
RequestオブジェクトのgetHeaderLine()メソッドでHTTPリクエストのコンテンツ長を取得することができます。
$length = $request->getHeaderLine('Content-Length');
Server Parameter
受信したリクエスト環境に関連するデータを取得するには、getServerParams()を使用する必要があります。
例えば、一つのServer Parameterを取得する場合。
$params = $request->getServerParams();
$authorization = $params['HTTP_AUTHORIZATION'] ?? null;
POST Parameters
リクエストメソッドがPOSTで、Content-Typeがapplication/x-www-form-urlencodedまたはmultipart/form-dataの場合、次のようにすべてのPOSTパラメータを取得することができます。
// Get all POST parameters
$params = (array)$request->getParsedBody();
// Get a single POST parameter
$foo = $params['foo'];
Route Object
ミドルウェアでは、ルートのパラメータを要求されることがあります。
この例では、まずユーザーがログインしていることを確認し、次に、ユーザーが視聴しようとしている特定の動画を視聴する権限を持っていることを確認しています。
$app
->get('/course/{id}', Video::class . ':watch')
->add(PermissionMiddleware::class);
<?php
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Slim\Routing\RouteContext;
class PermissionMiddleware
{
public function __invoke(Request $request, RequestHandler $handler)
{
$routeContext = RouteContext::fromRequest($request);
$route = $routeContext->getRoute();
$courseId = $route->getArgument('id');
// do permission logic...
return $handler->handle($request);
}
}
Obtain Base Path From Within Route
ルート内のベースパスを取得するには、次のようにします。
?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
use Slim\Routing\RouteContext;
require __DIR__ . '/../vendor/autoload.php';
$app = AppFactory::create();
$app->get('/', function(Request $request, Response $response) {
$routeContext = RouteContext::fromRequest($request);
$basePath = $routeContext->getBasePath();
// ...
return $response;
});
Attributes
PSR-7では、オブジェクトや値をリクエストオブジェクトに注入して、さらに処理することが可能です。アプリケーションでは、ミドルウェアがルートクロージャーに情報を渡す必要がありますが、その方法は、属性を通じてリクエストオブジェクトに情報を追加することです。
例)リクエストオブジェクトに値を設定する。
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
$app->add(function (Request $request, RequestHandler $handler) {
// Add the session storage to your request as [READ-ONLY]
$request = $request->withAttribute('session', $_SESSION);
return $handler->handle($request);
});
例、値の取得方法。
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
$app->get('/test', function (Request $request, Response $response) {
// Get the session from the request
$session = $request->getAttribute('session');
$response->getBody()->write('Yay, ' . $session['name']);
return $response;
});
リクエストオブジェクトは、同様にバルク関数も持っています。request->getAttributes()と$request->withAttributes()です。
Response
Slim アプリのルートとミドルウェアには、クライアントに返される現在の HTTP レスポンスを表す PSR-7 レスポンス オブジェクトが渡されます。レスポンス オブジェクトは PSR-7 ResponseInterface を実装しており、HTTP レスポンスのステータス、ヘッダー、ボディを検査および操作することができます。
How to get the Response object / Responseオブジェクトの取得方法
PSR-7 レスポンス オブジェクトは、次のようにルート コールバックの第 2 引数として、Slim アプリケーション ルートに注入されます。
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
require __DIR__ . '/../vendor/autoload.php';
$app = AppFactory::create();
$app->get('/hello', function (Request $request, Response $response) {
$response->getBody()->write('Hello World');
return $response;
});
$app->run();
The Response Status
すべてのHTTPレスポンスには、数字のステータスコードがあります。ステータスコードは、クライアントに返されるHTTPレスポンスの種類を特定する。PSR-7 Responseオブジェクトのデフォルトのステータスコードは200(OK)です。PSR-7 Responseオブジェクトのステータスコードは、getStatusCode()メソッドで次のように取得できます。
$status = $response->getStatusCode();
PSR-7 Responseオブジェクトをコピーして、次のように新しいステータスコードを割り当てることができます。
$newResponse = $response->withStatus(302);
The Response Headers
すべてのHTTPレスポンスにはヘッダーがあります。これらは HTTP レスポンスを記述するメタデータですが、レスポンスのボディには表示されません。PSR-7 Responseオブジェクトは、ヘッダーを検査し、操作するためのいくつかのメソッドを提供します。
$headers = $response->getHeaders();
foreach ($headers as $name => $values) {
echo $name . ": " . implode(", ", $values);
}
Get One Header
PSR-7 Response オブジェクトの getHeader($name) メソッドを使用すると、 ヘッダーの値をひとつだけ取得することができます。このメソッドは、指定したヘッダ名の値を配列で返します。ひとつの HTTP ヘッダが複数の値を持つことがあることに注意しましょう。
$headerValueArray = $response->getHeader('Vary');
PSR-7 レスポンスオブジェクトの getHeaderLine(
$headerValueString = $response->getHeaderLine('Vary');
Detect Header
ヘッダーの有無を調べるには、PSR-7 Response オブジェクトの hasHeader($name) メソッドを使用します。
if ($response->hasHeader('Vary')) {
// Do something
}
Set Header
ヘッダーの値を設定するには、PSR-7 Response オブジェクトの withHeader($name, $value) メソッドを使用します。
$newResponse = $oldResponse->withHeader('Content-type', 'application/json');
リマインダー
Response オブジェクトは不変である。このメソッドは、新しいヘッダー値を持つ Response オブジェクトのコピーを返します。このメソッドは破壊的であり、同じヘッダー名にすでに関連付けられた既存のヘッダー値を置き換えます。
Append Header
PSR-7 Response オブジェクトの withAddedHeader($name, $value) メソッドでヘッダー値を付加することができます。
$newResponse = $oldResponse->withAddedHeader('Allow', 'PUT');
リマインダー
withHeader() メソッドとは異なり、このメソッドは新しい値を、同じヘッダー名に対して既に存在する値のセットに追加します。Response オブジェクトは不変です。このメソッドは、追加されたヘッダー値を持つ Response オブジェクトのコピーを返します。
Remove Header
ResponseオブジェクトのwithoutHeader($name)メソッドで、ヘッダーを削除することができます。
$newResponse = $oldResponse->withoutHeader('Allow');
リマインダー
Response オブジェクトは不変である。このメソッドは、指定されたヘッダーを除いた Response オブジェクトのコピーを返します。
The Response Body
HTTPレスポンスは、通常、ボディを持ちます。
PSR-7 Request オブジェクトと同様に、PSR-7 Response オブジェクトも PsrHttpMessage の StreamInterface インスタンスとしてボディを実装しています。HTTP レスポンスボディの StreamInterface インスタンスは、PSR-7 Response オブジェクトの getBody() メソッドで取得することができます。送信する HTTP レスポンスの長さが不明な場合、または使用可能なメモリに対して大きすぎる場合は、getBody() メソッドを使用することが望ましい。
$body = $response->getBody();
その結果、PsrHottpMessageStreamInterfaceインスタンスは、その基礎となるPHPリソースからの読み取り、反復、および書き込みのための以下のメソッドを提供します。
- getSize()
- tell()
- eof()
- isSeekable()
- seek()
- rewind()
- isWritable()
- write($string)
- isReadable()
- read($length)
- getContents()
- getMetadata($key = null)
ほとんどの場合、PSR-7レスポンス・オブジェクトに書き込む必要があります。StreamInterfaceのインスタンスのwrite()メソッドで、次のようにコンテンツを書き込むことができます。
$body = $response->getBody();
$body->write('Hello');
PSR-7 Response オブジェクトのボディを、全く新しい StreamInterface インスタンスに置き換えることもできます。これは、リモートの宛先 (ファイルシステムやリモート API など) の内容を HTTP レスポンスにパイプしたい場合に特に有用です。PSR-7 レスポンスオブジェクトのボディを置き換えるには、 withBody(StreamInterface $body) メソッドを使用します。引数は PsrHttpMessage Interface のインスタンスでなければなりません。
use GuzzleHttp\Psr7\LazyOpenStream;
$newStream = new LazyOpenStream('/path/to/file', 'r');
$newResponse = $oldResponse->withBody($newStream);
リマインダー
Response オブジェクトは不変です。
このメソッドは、新しいボディを含む Response オブジェクトのコピーを返します。
Returning JSON
最も単純な形として、JSONデータはデフォルトの200 HTTPステータスコードで返すことができます。
$data = array('name' => 'Bob', 'age' => 40);
$payload = json_encode($data);
$response->getBody()->write($payload);
return $response
->withHeader('Content-Type', 'application/json');
リマインダー
Response オブジェクトは不変である。このメソッドは、新しい Content-Type ヘッダーを持つ Response オブジェクトのコピーを返します。このメソッドは破壊的であり、既存の Content-Type ヘッダーを置き換えます。
Returning a Redirect
Locationヘッダーを使用することで、HTTPクライアントをリダイレクトすることができます。
return $response
->withHeader('Location', 'https://www.example.com')
->withStatus(302);