こんなん考えた
<?php function UriDispatcher() { return UriDispatcher::current(); } class UriDispatcher { private $_uri; private $_current ; private $_path; private $_request; public function index(uri $uri) { $uri->children = $this->_uri->children; $this->_uri = $uri; } public function __call($name, Array $arguments) { $uri = array_shift($arguments); $this->_current->children[$name] = $uri; $this->_current = $uri; return $this; } public function __get($name) { return isset($this->_current->children[$name]) ? $this->_current->children[$name] : null; } public static function current() { $self = self::_instance(); $self->_current = $self->_uri; return $self; } private static function _instance() { static $_instance; isset($_instance) or $_instance = new self; return $_instance; } private function __construct() { $_request = str_replace( dirname($_SERVER['SCRIPT_NAME']) , '' , $_SERVER['REQUEST_URI'] ); $_path = explode('/',$_request); array_shift($_path); $this->_request = $_request; $this->_path = $_path; $uri = uri(); $this->_current = $uri; $this->_uri = $uri; } public function __destruct() { $this->loadFile($this->_uri->module); $uri = $this->_uri; while($path = array_shift($this->_path)) { if(empty($uri->children[$path])) { break; } $uri = $uri->children[$path]; foreach($uri->parameter as $key) { empty($this->_path) and $this->error_404(); $_REQUEST[ $key ] = array_shift($this->_path); } $this->loadFile($uri->module) or $this->error_404(); } $this->loadFile($uri->view) or $this->error_404(); } private function error_404() { header('HTTP/1.1 404 Not Found'); echo '404 not found !!!'; exit; } private function loadfile($filepath) { if(empty($filepath)) { return False; } $filepath = realpath( dirname($_SERVER['SCRIPT_FILENAME']) ) . '/' . $filepath; if(!file_exists($filepath)) { return False; } return require $filepath; } } function uri() { $args = func_get_args(); return new uri($args); } class uri { private $_module = null; private $_view = null; private $_parameter = null; public $children = Array(); public function __construct($args=Array()) { $this->_parameter = $args; } public function module($value) { $this->_module = $value; return $this; } public function view($value) { $this->_view = $value; return $this; } public function __get($name) { $key = "_{$name}"; return isset($this->$key) ? $this->$key : null; } }
Restって言うか、URIとモジュールのディスパッチに悩みまくって
自前で用意した。
まだ、デバッグ中。
URIの階層構造に対してモジュールを適応出来る様にした
こんなURIを
/session/{session}/room/{room_id}/
<?php require 'lib/UriDispatcher.php'; UriDispatcher() ->session(uri('session')->module('src/user.php')) ->room(uri('room_id')->module('src/room.php')->view('src/room.view.php'));
こんなPHPのコードで表現する。
/session/{session}/ 以下のディレクトリにアクセスした際に
src/user.phpモジュールが呼び出される
(実際にはDiconファイルっぽいPHPを記述しておく
んでセッションがらみの認証を行って、認証情報のオブジェクトをコンテナに突っ込んでおいて
下の階層のURIのモジュールを読み込んでいく
/room/{room_id}/
にアクセスした際に src/room.php モジュールを読み込んで、room情報の一覧とか
まぁ何かしらオブジェクトをコンテナにつっこむ
んで、URIが終端に来たら、一番したの階層のモジュールの viewプロパティに指定してある
src/room.view.php モジュールを読み込む、ココで表示用のPHPなり、テンプレートエンジンとの紐付けなり
何なりを行う
テンプレートエンジンのオブジェクトとか、DBアクセスの為のコネクションとか全てのURIで
使用するっぽいオブジェクトは
UriDispatcher() ->index(uri()->module('src/init.php'));
こんな感じに uri のindex階層にてモジュールを読み込ませておけば良い
発想としは、JavaScriptやSqueakとかのスクリプトが実行された時点で
無数のオブジェクトが名前空間に存在して、オブジェクトを使うだけで
色々な事が出来て楽しい世界をPHPに持ってきたくて
どの段階でオブジェクトをコンテナに設定してやるかって
フックのタイミングをURIに対して紐付けてやった感じ
これなら、あぁー、このテンプレートにユーザーの名前を表示させたいけれど
ユーザーの名前はオブジェクトに存在しないなぁって時に
動作するスクリプトなり、テンプレートにデータのアサインを書かなくても
上位層でユーザーオブジェクトを拡張してやるなり、上位層のオブジェクトを
コンテナに設定してやってる所に記述してやれば良い
何て事をアホみたいにSmartyテンプレートの点数が多いサイトや
Velocityテンプレートが多いサイトを運用する上で
ViewとViewの為のモジュールが一対一のサイトでView一寸変更するだけなのに
当初想定されていなかったからモジュールの修正が必要になって
モジュールとテンプレートを結局、システム屋が何とかしなきゃ
いけないとか本末転倒な事を打破するのに多少は役立つんじゃぁ
無いかなぁっと
結局、まったく用意してないオブジェクト要素については対応出来ないけれど
こっちの画面で行った事を簡単に運用レベルの技術で
(結構デザイナさんでSmarty弄れる人とかいたりするし
(ベタなPHPだったら書けるってデザイナさんもいるしね
この前作った機能を横展開させましょうって時のコストが
こう書いてみたら動くんじゃね?
レベルまで落とし込めたらイイナぁ