PHPでルーティングを行うパッケージであるnikic/FastRouteパッケージを利用して、controller-actionスタイルのルーティングを行う方法を説明します。
nikic/FastRouteパッケージは、PHP本体の開発者であるNikitaさんが開発していて、Slim3 Frameworkでも採用されているシンプルで高速なルーティングパッケージです。
controller-actionスタイルって何?
controller-actionスタイルというのは、左のようなURLが来た時に、URLからクラス名とメソッド名を特定し、矢印の右側にあるメソッドを読んでくれるようなルーティングを行う方法です。
http://example.com/user/list -> UserController::list()
http://example.com/user/index -> UserController::index()
http://example.com/user/ -> UserController::index()
上に書かれたUserControllerクラスは、以下のような普通のPHPクラスです。今回の例では、App\Controllerネームスペースをつけています。
namespace App\Controller;
class UserController
{
public function index(Request $request, Response $response, $args) {
return "index called";
}
public function list() {
return "list called";
}
}
controller-actionタイプのルーティング処理
今回行いたいルーティングのルールは、ホスト名の後に来る1つ目の要素がコントローラ名(クラス名を特定するもの)で、2つ目がアクション名(メソッド名)とみなします。また、アクション名を省略した場合はindexが指定されたとみなします。
この要件を満たすルーティング処理は以下のようになります。
<?php
include "UserController.php";
$app->get('/{controller}[/{action}]', function (Request $request, Response $response, array $args) {
$prefix = '\\App\\Controller\\';
$suffix = 'Controller';
// アクションを実行するクラス、メソッド名を取得
// action名省略時はindexとみなす
$controllerName = $prefix . $args['controller'] . $suffix;
$methodName = $args['action'] ?? 'index';
// 指定されたアクションを実行
$c = new $controllerName;
$response = $c->$methodName($request, $response, $args);
return $response;
});
$app->get()の第二引数で指定しているクロージャーでこのルーティングを行っています。先ほど提示した例ではURLでhttp://example.com/user/が指定されたときに、App\Controller\UserController
のクラスを使用していました。
Urlで指定された名称"user"の前に、接頭語としてApp\Controller\
、また接尾語としてController
をつける必要があるため、この文字列をprefix/suffixの変数で管理しています。
また、メソッド名は以下のように省略時は、indexが指定されたとみなしています。
$methodName = $args['action'] ?? 'index';
この処理は、PHP 5.Xなど古いバージョンのPHP環境で??
演算子が使えない場合は、以下のように書き換える必要があります。
$methodName = !isset($args['action']) ? $args['action'] : 'index';
クラス名とメソッド名が決定したら、名称を元に動的にクラス生成・メソッド呼び出しを行えばよいです。
// 指定されたアクションを実行
$c = new $controllerName;
$response = $c->$methodName($request, $response, $args);
これで、最初に提示したようなcontroller-actionスタイルのルーティングが行えるようになります。