Open27

PHP-Slim Framework-log

ピン留めされたアイテム
m0n0rem0n0re

Slim framework

https://www.slimframework.com/


<?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();

m0n0rem0n0re

https://www.slimframework.com/docs/v4/start/installation.html

Step1 Composerのインストール

https://getcomposer.org/doc/00-intro.md#installation-windows

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

public/index.php

<?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:
https://qiita.com/ryu022304/items/10518cb1e306e213c2ac
https://qiita.com/taro-hida/items/a4f47d6bca2ed4063efb

m0n0rem0n0re

Composer?

https://getcomposer.org/

https://weblabo.oscasierra.net/php-composer-1/

Composer は、PHP のプロジェクトが必要とするライブラリやパッケージを管理する「ライブラリ依存管理ツール」です。 その PHP プロジェクトで必要なパッケージ(ライブラリ)は何かを列挙すると、それらを自動的にインストールしてくれる機能を持ちます。

ははーん。npmとかnodeとかpipとかなんかそんな感じね????

Composerのインストール(Win)

https://weblabo.oscasierra.net/php-composer-windows-install/

m0n0rem0n0re

Get Started

https://www.slimframework.com/docs/v4/

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 アプリをインスタンス化し、実行します。

m0n0rem0n0re

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();

🤔?

m0n0rem0n0re

リクエストとレスポンス
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 の概念とアーキテクチャの説明から始まり、リクエストとレスポンスの処理、ルーティング、エラー処理などの特定のトピックに踏み込みます。

🤔🤔?

m0n0rem0n0re
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,名前が出るって感じか。
匿名関数のところがよくわからんけどここで深堀するのはハマりそうだからいったんこのまま。

m0n0rem0n0re

https://www.slimframework.com/docs/v4/start/web-servers.html

PHP built-in server

ターミナルで以下のコマンドを実行し、localhostのWebサーバーを起動します。./public/が公開可能なディレクトリで、index.phpファイルがあると仮定します。

警告内蔵のウェブサーバーは、アプリケーションの開発を支援するために設計されています。また、テスト目的や制御された環境で実行されるアプリケーションのデモにも有用です。これは、全機能を備えたウェブサーバーとして意図されているわけではありません。公共のネットワークで使用するべきではありません。

PHPにビルドインされてるWebサーバを使うけど、本番環境とかでは使うなよ!って話。

// ここは各WEBサーバにインストールするところの手順っぽいから後回し。

m0n0rem0n0re

https://www.slimframework.com/docs/v4/deployment/deployment.html

Deployment

おめでとうございます!ここまで来られたということは、Slimを使って何か素晴らしいものを作ることに成功されたのだと思います。しかし、パーティーをする時間はまだ来ていません。まだ、アプリケーションを本番サーバーにプッシュしなければならないのです。

これを行うには多くの方法がありますが、このドキュメントの範囲を超えています。このセクションでは、さまざまなセットアップのためのいくつかのメモを提供します。

// ここも本番サーバにDeployするところ関連のようなので後回し

m0n0rem0n0re

Slim-Skeleton

Github URL

https://github.com/slimphp/Slim-Skeleton

このスケルトン・アプリケーションを使用して、新しい 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/ がウェブ書き込み可能であることを確認します。

m0n0rem0n0re

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展開用のなにかが足りなくて怒られてるらしい。
上記のログ以降もモリモリ足りないと怒られた。

ぐぐる。
https://stackoverflow.com/questions/41274829/php-error-the-zip-extension-and-unzip-command-are-both-missing-skipping

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を削除してもう一度コマンドを叩く。

できたっぽい!

m0n0rem0n0re

apache のdocument rootを作成したmyapp/publicに変更しろって書いてあるのでXAMPPのapache設定変えた.

xampp/apache/conf/httpd.conf
-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が表示された。

m0n0rem0n0re

skeletonだけど解説がすくなくてよくわからん!!UserGuideに戻る

m0n0rem0n0re

https://www.slimframework.com/docs/v4/concepts/life-cycle.html

アプリケーションのライフサイクル
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 レスポンスボディは現在の出力バッファに出力されます。

m0n0rem0n0re

https://www.slimframework.com/docs/v4/concepts/value-objects.html

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 のドキュメントを参照ください。

m0n0rem0n0re

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 (英語)

m0n0rem0n0re

requestとresponseの間に色々挟めるよ~って機能だと理解。
実装方法とかは一旦置いておく。こういう機能があるよってだけ頭の隅に置く。

m0n0rem0n0re

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;
});

🤔

m0n0rem0n0re

https://www.slimframework.com/docs/v4/objects/application.html

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);
        }
    }
m0n0rem0n0re

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(name) メソッドを使用すると、指定したヘッダーのすべての値をカンマ区切りで文字列として取得することもできます。getHeader(name) メソッドとは異なり、このメソッドはカンマで区切られた文字列を返します。

$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()です。

m0n0rem0n0re

Response

Slim アプリのルートとミドルウェアには、クライアントに返される現在の HTTP レスポンスを表す PSR-7 レスポンス オブジェクトが渡されます。レスポンス オブジェクトは PSR-7 ResponseInterface を実装しており、HTTP レスポンスのステータス、ヘッダー、ボディを検査および操作することができます。

m0n0rem0n0re

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();
m0n0rem0n0re

The Response Status

すべてのHTTPレスポンスには、数字のステータスコードがあります。ステータスコードは、クライアントに返されるHTTPレスポンスの種類を特定する。PSR-7 Responseオブジェクトのデフォルトのステータスコードは200(OK)です。PSR-7 Responseオブジェクトのステータスコードは、getStatusCode()メソッドで次のように取得できます。

$status = $response->getStatusCode();

PSR-7 Responseオブジェクトをコピーして、次のように新しいステータスコードを割り当てることができます。

$newResponse = $response->withStatus(302);
m0n0rem0n0re

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(name) メソッドを使用すると、 指定したヘッダーのすべての値をカンマ区切りで文字列として取得することもできます。getHeader(name) メソッドとは異なり、このメソッドはカンマで区切られた文字列を返します。

$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 オブジェクトのコピーを返します。

m0n0rem0n0re

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 オブジェクトのコピーを返します。

m0n0rem0n0re

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 ヘッダーを置き換えます。

m0n0rem0n0re

Returning a Redirect

Locationヘッダーを使用することで、HTTPクライアントをリダイレクトすることができます。

return $response
  ->withHeader('Location', 'https://www.example.com')
  ->withStatus(302);