やみとものプログラミング日記 やみとものプログラミング日記
TOP テスト駆動開発でルーターを作る Part5
テスト駆動開発でルーターを作る Part5

テスト駆動開発でルーターを作る Part5

プログラミング
作成日時: 2020年7月9日
更新日時: 2020年7月11日
こんにちは、やみともです。
今回は前回「テスト駆動開発でルーターを作る Part4」の続きです。

今回はpostメソッドのルーティングができるように実装を進めましょう。
と言ってもまずはテストからです。

テスト

[ RouterTest.php RouterTestクラス ]
    public function test_routing_post()
    {
        Router::post("/contact", "ContactPost");
        list($controller_class_name, $params) = Router::routing("post", "/contact");
        $this->assertEquals("ContactPost", $controller_class_name);
    }

テスト失敗

以下のように失敗します。
$ p
PHPUnit 9.2.5 by Sebastian Bergmann and contributors.

...E                                                                4 / 4 (100%)

Time: 00:00.019, Memory: 4.00 MB

There was 1 error:

1) RouterTest::test_routing_post
Error: Call to undefined method Router::post()

/Users/yuki/testblog/yamitomo_router/tests/RouterTest.php:35

ERRORS!
Tests: 4, Assertions: 4, Errors: 1.

実装

Routerクラスを少し修正しました。
具体的には$routing_tableスタティック変数にgetもしくはpostのメソッド情報も登録するようにし、routingメソッドでそれを参照して処理するようにしました。

[ Router.php ]
<?php

class Router
{
    private static $routing_table = [];

    public static function get(string $url, string $controller)
    {
        // ルーティングテーブルにルートを登録する
        // ★getやpostなどのHTTPメソッドも登録するように変更した
        array_push(self::$routing_table, [
            "method" => "get",
            "url" => $url,
            "controller" => $controller
        ]);
    }

    public static function post(string $url, string $controller)
    {
        // ルーティングテーブルにルートを登録する
        // ★getやpostなどのHTTPメソッドも登録するように変更した
        array_push(self::$routing_table, [
            "method" => "post",
            "url" => $url,
            "controller" => $controller
        ]);
    }

    public static function routing(string $method, string $url)
    {
        // 念のため小文字化しておく
        $method = strtolower($method);

        // ルーティングテーブルのルートを1つずつ見ていきマッチしたコントローラークラス名を返す
        for ($i = 0; $i < count(self::$routing_table); $i++) {
            $route = self::$routing_table[$i];
            $route_method = $route["method"];
            $url_pat = $route["url"];
            $controller = $route["controller"];

            if ($route_method != $method) continue;

            // URLパターンの?を\?に変換する
            $url_pat = str_replace("?", '\?', $url_pat);

            // int型のパラメータ名を抽出列挙する
            preg_match_all("/\[int (?P<ints>[a-zA-Z0-9_]+)\]/", $url_pat, $match);
            $ints = $match["ints"];

            // str型のパラメータ名を抽出列挙する
            preg_match_all("/\[str (?P<strs>[a-zA-Z0-9_]+)\]/", $url_pat, $match);
            $strs = $match["strs"];

            // パターンの作成
            $pat = preg_replace("/\[int ([a-zA-Z0-9_]+)\]/", "(?P<$1>0|[1-9][0-9]*)", $url_pat);
            $pat = preg_replace("/\[str ([a-zA-Z0-9_]+)\]/", "(?P<$1>[a-zA-Z0-9_]+)", $pat);

            if (preg_match("#^{$pat}$#", $url, $match)) {
                $params = [];
                for ($j = 0; $j < count($ints); $j++) {
                    $key = $ints[$j];
                    $params[$key] = intval($match[$key]);
                }
                for ($j = 0; $j < count($strs); $j++) {
                    $key = $strs[$j];
                    $params[$key] = $match[$key];
                }
                $params = $params == [] ? null : $params;

                return [$controller, $params];
            }
        }
    }
}
これでテストも通りました。
今回は短いですがここまでとします。

次回予告 & 本紹介

次回以降もルーターライブラリを作っていきます。
ちなみにこれまでの説明もこれからの説明も下のテスト駆動開発の本を参考にしています。
テスト駆動開発に興味のある方は購入されてはどうでしょうか。