1処理1クラスのコントローラクラス
前回までのサンプルでは、アプリにアクセスしてきたときの処理(これをリクエスト処理と言います)をルーティングコールバック関数内に記述していました。その問題点の確認から行いましょう。
ルーティングコールバック関数の問題点
各リクエスト処理をルーティングコールバック関数に記述していくと、ソースコードの見通しが悪くなるという問題が生じます。本連載中に紹介したソースコードは、あくまでサンプルですので、大したコード量ではありません。
それでも、ルーティング登録ファイル内のソースコードの見通しがいいとは言えません。ましてや、本運用で使われるアプリとなると、各リクエスト処理のコード量はサンプルの比ではなく、ルーティング登録ファイル内はさらにコードの見通しが悪くなり、メンテナンス性が極端に下がります。
これを解決するには、ルーティング登録のコードとリクエスト処理のコードを分離することです。
コントローラクラス
そこで、Slimでは、リクエスト処理をクラスとして記述し、それをルーティング登録する方法が用意されています。そういったリクエスト処理が記述されたクラスのことを、「コントローラクラス」と言います。そのうちで、1つのリクエスト処理を1つのクラスとして記述する方法をまず紹介します。
では、実際に作成していきましょう。まず、コントローラクラスファイルを格納するフォルダを作ります。こういった自作クラスファイル類を格納するフォルダについて、Slimでの取り決め事項は特にありません。
そこで、srcフォルダ直下にそういうクラス類をまとめて入れておくフォルダとしてclassesフォルダを作成します。このフォルダ以下のサブフォルダはそれぞれクラスの役割ごとに作ります。コントローラクラス類は、controllersフォルダに格納することにします。さらに、その中に階層構造を作成して整理します。今回は第6回にあたるので、サブフォルダとしてno6を作成し、その中にリスト1のHelloControllerクラスを作成してください。
<?php namespace CodeZineSlim\FirstSlim\controllers\no6; // (1) use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ResponseInterface as Response; use Psr\Container\ContainerInterface; class HelloController { //Slimのコンテナインスタンスを格納するプロパティ。 private $container; // (2) //コンストラクタ。 public function __construct(ContainerInterface $container) // (3) { $this->container = $container; } //実際に実行されるメソッド。 public function __invoke(Request $request, Response $response, array $args): Response // (4) { $view = $this->container->get("view"); // (5) return $view->render($response, "hello.html"); // (6) } }
リスト1では、(5)と(6)が実際のリクエスト処理であり、ここでは前回のリスト2と同じ処理を行うように記述しています((5)が前回のリスト2と違いますが、こちらは後述します)。そのようなリクエスト処理1つ分を1つのクラスとして記述する場合は、リスト1の(4)のようにリクエスト処理をマジックメソッド__invoke()に記述したクラスを作成します(※)。
__invoke()メソッドの引数は、コールバック関数の引数と同じものを記述し、順番に、ServerRequestInterfaceインスタンス($request)、ResponseInterfaceインスタンス($response)、ルーティングプレースホルダが格納された連想配列($args)です。戻り値についても、コールバック関数と同じで、ResponseInterfaceインスタンスをリターンします。
なお、クラス名については特に指定はないので自由につけてもらってもかまいませんが、どういった処理を行うコントローラクラスなのかわかるようにしておいた方がいいでしょう。おすすめは、「〇〇Controller」といったネーミングにすることです。
また、このクラスの名前空間も、classesフォルダ以降のフォルダ階層と同じ階層構造にしておけば、ベンダプレフィックスは何でもいいです。リスト1では(1)のように、実際のフォルダ構成であるcontrollers\no6の前に、プレフィックスとしてCodeZineSlim\FirstSlimとしています。これについては、もう一度後で触れます。
※マジックメソッドとは何か、__invoke()メソッドがどのようなメソッドかについては、拙記事「PHPの「マジックメソッド」とは――「__set()」「__get()」「__invoke()」の使い方」を参照してください。
コントローラクラスのコンストラクタ
ここで、リスト1の(5)のコードに注目します。前回のリスト2ではこの行は以下のコードでした。
$view = $this->get("view");
その際、解説したように、ルーティングコールバック関数内では、$thisという変数はSlimのコンテナそのものを表します。一方、コントローラクラスでは$thisはコントローラクラスのインスタンスを表すので、当然コンテナとは違い、上の記述はできません。
では、コントローラクラスでコンテナを扱いたい場合はどうすればいいのでしょうか。そこで登場するのがコンストラクタです。コントロールクラスにコンストラクタを記述し、その引数として、コンテナを表すContainerInterface型引数($container)を定義しておきます。
すると、Slimがこのコントローラクラスを呼び出して実行する際にコンストラクタの引数に自動的にコンテナが渡されるようになります。つまり、リスト1の(3)の引数$containerはコンテナインスタンスを表します。これを(2)のプロパティに格納しておくことで、このコントローラクラス中ではいつでもコンテナが利用できるような仕組みとなるのです。
リスト1の(5)ではこのプロパティのコンテナからget()メソッドを使ってTwigインスタンスを取得しています。