Struts」とは、Javaの世界で一時期隆盛を極めたフレームワークである。私が関わっていた当時は1.2.9だったが、今はもう「Struts2」の名前でリリースされているらしい。MVCアーキテクチャを日本に広めた功績はあると思うが、コードの見通しの悪さには苦労させられた。

詳細各自で調べてもらうとして、その当時参考にさせてもらった手法をkwappaにも取り入れることにした。

Strutsはリクエストを受けると、URLにマッピングされたアクションクラスを呼び出して作業を行い、結果をJSPで表示する、という仕組みになっている。

このときアクションクラスが実際に処理を行うメソッドはデフォルトでは固定、というのが曲者で、たとえばひとつのフォームに「登録」「確認」「削除」のようなボタンをつけると、各ボタンそれぞれにアクションクラスを用意する必要があるのだ。

さすがにこれでは効率が悪いので、あるバージョンから「DispatchAction」という仕組みが用意された。リクエストパラメータに特定のキーを設定し、その値でアクションクラス内のメソッドを呼び分けてくれる。しかし、この方法でも「設定ファイルに書く」「GET / POSTパラメータに値を設定する」という2つのステップが必要になる。しかも名前をキーにメソッドを呼び出すので、ボタンのvalue要素に日本語が使えないという問題点もあった。それを解決するために「LookupDispatchAction」という拡張が施されたが、これもリソースファイルでマッピングを書く必要があるのでお手軽とは言い難い。

と、こんな仕組みの上でたくさんのDispatchを書いているとたいていのプログラマがめんどくさくなってくるのだが、その中のひとりが「こんな仕組み」を書いてくれた。「おおそうだこれだこれだ!」とばかりに当時活用させてもらったのみならず、今こうしてフレームワークの中でネタとして活用させていただいている。ありがたい話だ。

Kwappaではリクエストパラメータに「__[METHOD_NAME]\__」という名前でなにか(なんでもいいがPHPでtrue判定される)値を送る。するとControllerのBaseClassがMethodを呼び分けてくれる、という仕組み。通常はsubmitボタンのname要素にメソッド名を記述する。DispatchAction / EasyDispatchActionではメソッドが見つからないとデフォルト(unspecified)メソッドを呼ぶようになっているが、KwappaではPHPがFatal Errorを出すに任せている。

【view】(template)

<form action="example.php" method="POST">
    <input type="text" name="hoge">
    <input type="submit" name="__foo__" value="call method foo" />
    <input type="submit" name="__bar__" value="call method bar" />
</form>

【controller】

<?php
class TestController extends KwappaController
{
    // メソッド名が指定されていない場合のデフォルト
    public function do_exec()
    {
        echo "function : default / value : {$_POST['hoge']}" ;
    }
    // [__foo__]ボタンを押した
    public function do_foo()
    {
        echo "function : foo / value : {$_POST['hoge']}" ;
    }
    // [__bar__]ボタンを押した
    public function do_bar()
    {
        echo "function : bar / value : {$_POST['hoge']}" ;
    }
}
?>

【super-class】

<?php
abstruct class KwappaController
{
    /**************** 前略 ****************/
    // デフォルト処理メソッドはオーバーライドさせる
    abstruct function do_exec() ;
    /**************** 中略 ****************/
    // リクエストパラメータによってdispatch
    private function dispatch()
    {
        $func_name = "exec" ;       // デフォルトの関数名
        foreach ($_POST as $key => $value)
        {
            if (preg_match("/__\w+__/", $key) && $value)
            {
                // input type="image" の場合、クリックした座標が入ってくるので対策
                $func_name = preg_replace("/_[xy]$/", "", $key) ;
                $func_name = "do_" . str_replace("__", "", $func_name) ;
                break ;
            }
        }
        // 抽出したメソッド名で実行して終了
        return $this->$func_name() ;
    }
    /**************** 後略 ****************/
}
?>

KwappaではURLルーティングを行わないつもりだった(前代もそうだった)。だが諸事情により方針転換したので、この辺まるっと書き直している最中である。Dispatchの仕組みは同じだが実際の処理はだいぶ違ったものになるので、今回は大まかな仕組みだけ紹介しておく。

余談ながら、input type=”image”の場合。

<form action="" method="POST">
    <input type="text" name="hoge" value="fuga" />
    <input type="image" src="button_img.png" name="__test__" />
</form>
<?php
    echo "<pre>" ;
    var_dump($_POST) ;
    echo "</pre>" ;
?>

【出力結果】

array(3) {
  ["hoge"]=>
  string(4) "fuga"
  ["__test___x"]=>
  string(2) "58"
  ["__test___y"]=>
  string(3) "114"
}

こんな感じで、ボタン画像のクリックされた座標が返ってくる。