Net_URL_Dispatcher というライブラリを作った

あ…ありのまま 今 起こった事を話すぜ!
年末年始の休みで Python の勉強をするはずだったんだが、気づいたら openpear にライブラリをコミットしていた。
な… 何を言ってるのか わからねーと思うが(ry


というわけで、 Net_URL_Dispatcher というライブラリを作ったので openpear で公開しました。
http://openpear.org/package/Net_URL_Dispatcher
何をするライブラリかというと、URL の PATH_INFO からパースしてクラスにディスパッチをするもの。
仕事で必要になりそうなので、単体のライブラリがどっかに無いかなーと思って探したけど、見つからなかったので作りました。
# 最近のフレームワークにはもれなく付いてるけど。


ルーティングには Net_URL_Mapper を使用してます。
# Net_URL_Mapper についてはウノウラボさんの PEAR::Net_URL_MapperでURLルーティングを制御するを参照。

使いどころ

フレームワークなんて使用していないレガシーなシステムの保守で、新規機能を追加しなければいけない、でもフレームワークを入れるには学習コストが大きくておおげさすぎるというような場合に使えるかと思います。
どちらかというとエントリーポイントが各ページごとにあるような場合を想定しています。
# フロントコントローラパターンでも使えるけど・・・。

使い方

コントローラクラスを使う場合、/index.php/controller/action/key1/value1/key2/value2 というようなパスでディスパッチします。

<?php
require_once 'Net/URL/Dispatcher.php';
$dispatcher = new Net_URL_Dispatcher();
$dispatcher->connect(':controller/:action/*params')->dispatch('/path/to/directory');

パスが /index.php/hoge/fuga だと、/path/to/directory/controllers ディレクトリの HogeController.php の fugaAction() にディスパッチします。
# ファイル名とクラス名は同じである必要があります。


必ず特定のコントローラにディスパッチしたい場合は、 :controller にコントローラ名を設定する事で、そのコントローラにディスパッチします。

<?php
require_once 'Net/URL/Dispatcher.php';
$dispatcher = new Net_URL_Dispatcher();
$dispatcher->connect('sample/:action/*params')->dispatch('/path/to/directory');

上記の場合、 /index.php/sample/hoge で SampleController.php の hogeAction() にディスパッチします。


単純にコントローラとアクションを呼びたいだけって場合は、dispatchController() を呼べばディスパッチします。

<?php
require_once 'Net/URL/Dispatcher.php';
$dispatcher = new Net_URL_Dispatcher();
$dispatcher->dispatchController('Hoge', 'fuga', null, '/path/to/directory');

上記の場合、HogeController の fugaAction にディスパッチします。
# あんまり使う意味がなさそうだけど、呼び出し先のファイルをインクルードしなくて済みます。


setPathInfo() なんてメソッドもあります。引数にパスを設定すると、ディスパッチ時に $_SERVER['PATH_INFO'] の代りに設定したパスを使用します。


/index.php/sample/ のようにパスにアクションが指定されていない場合、SampleController.php の indexAction(); にディスパッチしようとします。
# indexAction(); がデフォルトのアクションです。


コントローラクラスなんて要らない!アクションクラスで十分ってな場合は、以下のように :action というルールにすると、アクションクラスを探しに行きます。

<?php
require_once 'Net/URL/Dispatcher.php';
$dispatcher = new Net_URL_Dispatcher();
$dispatcher->connect(':action/*params')->dispatch('/path/to/directory');

パスが /index.php/hoge/foo/bar だと、/path/to/directory/actions ディレクトリの HogeAction.php にディスパッチします。
コントローラと違って execute() メソッドが実行されます。


単純にアクションクラスを呼びたい場合は、コントローラの場合と同じように dispatchAction(); を呼べば設定した引数のアクションクラスを実行します。

規約っぽいもの

コントローラクラスは Zend Framework っぽく書けます。
Net_URL_Dispatcher_Controller を継承すれば、 preDispatch, postDispatch を使用できます。
それぞれアクションメソッドが呼ばれる前と呼ばれた後に実行されます。


アクションクラスの場合、Net_URL_Dispatcher_Action を継承すれば、execute() の前後にそれぞれ preExecute(), postExecute() が呼ばれます。
メソッド名は moony からパクっインスパイアされました。


呼び元からディスパッチ先に値を渡したい場合は、以下のようにすると渡せます。

<?php
require_once 'Net/URL/Dispatcher.php';
$dispatcher = new Net_URL_Dispatcher();
$dispatcher->connect(':controller/:action/*params')->setParams(array('hoge' => 'fuga'))->dispatch('/path/to/directory');
<?php
class SampleController extends Net_URL_Dispatcher_Controller
{
    public function indexAction()
    {
        echo $this->getParam('hoge');  // fuga と表示
    }
}
パラメータの取得

コントローラクラスやアクションクラスで、パラメータを取得するには getParam('key);とすると $_GET, $_POST, PATH_INFO からよろしく値を取得します。
# 全ての値を取得したい場合は、getParams(); で取得できます。
PATH_INFO に設定されているパラメータは /key/value の順番で取得します。
/key1/value1/key2/value2 の場合、getParams() すると、
array(
key1 => value1,
key2 => value2
)
となります。


要素名がかぶったら、array_merge してマージするので注意してください。
また getParam('key', 'default'); というように 第二引数に値を設定すると、取得しようとした key に該当するものが無い場合、第二引数で設定した値を応答します(この場合 default が応答)。
# Zend Framework のパクリ。

actionStack

Net_URL_Dispatcher_Controller|Action を継承した場合、actionStack というメソッドを使用できます。
Zend FrameworkActionStack 機能を劣化させたようなものです。

<?php
class SampleController extends Net_URL_Dispatcher_Controller
{
    public function hogeAction()
    {
        $this->actionStack('fuga', null, array('key' => 'value'));
    }
    
    public function fugaAction()
    {
        echo $this->getParam('key');  // value と表示
    }
}

hogeAction() の処理が終わった後に、 fugaAction() を呼び出します。
呼び出す順番は SampleController#preDispatch() -> hogeAction() -> postDispatch() -> preDispatch() -> fugaAction() -> postDispatch() となります。
actionStack の第二引数に コントローラ名を設定すると、別のコントローラのメソッドを呼び出せます。


アクションクラスでも使用できます。
アクションクラスを使用する場合、コントローラを指定する第二引数に値を設定しても無視します。

autoload

コントローラクラス、アクションクラスともに autoload を使用しているので、Net_URL_Dispatcher_Controller|Action を継承する場合 require を書く必要はありません。
Net_URL_Dispatcher_Controller|Action ではない独自のクラスを親クラスとしたい場合でも autoload が走りますが、クラス名とパスは PEARZend Framework と同じ規約で、include_path されている必要があります。

その他もろもろ

  • ライセンスは?
    • BSD ライセンスです。
  • モデルとかビューは?
    • 単純にディスパッチするだけのものです。お好きな物を使って下さい。
  • error_reporting に E_ALL|E_STRICT 使いたいんだけど?
    • Net_URL_Mapper が Net_URL に依存している関係で、 E_STRICT にするとワーニングが出るので、デフォルト E_ALL です。それでも変更したい場合は、 setErrorReporting() に値を渡せば変更できます。
  • テストコードは?
    • テスト関係は PHPSpec で書いてます。動かすには Stagehand_TestRunner が必要です。
  • 細かい仕様は?
    • 仕様を確認したい場合は、 tests 以下の spec ファイルに記述しています。ただ全てカバーしてるわけではありません。。。

まとめ

こういうオレオレライブラリを簡単に提供できる openpear は素晴らしい。
みんなもっと openpear で作ったライブラリを公開するといいと思うよ。


ということで本年もよろしくお願いします <(_ _)>