チャット作るよ。6日目
アクションを作ったので、制御するコントローラを作る。
まずはテストケース。
<?php class ControllerTest extends PHPUnit_Extensions_OutputTestCase { /** * テストアプリディレクトリパス */ const APP_DIR_PATH = '/project/chat/_test'; /** * テストアクションディレクトリパス */ const ACT_DIR_PATH = '/project/chat/_test/action'; /** * Indexアクションファイルパス */ const INDEX_ACT_FILE_PATH = '/project/chat/_test/action/IndexAction.php'; /** * Index2アクションファイルパス */ const INDEX2_ACT_FILE_PATH = '/project/chat/_test/action/Index2Action.php'; /** * Emptyアクションファイルパス */ const EMPTY_ACT_FILE_PATH = '/project/chat/_test/action/EmptyAction.php'; public static function setUpBeforeClass() { // テスト用ディレクトリ、及びファイルの生成 mkdir(self::ACT_DIR_PATH, 0777, true); $index = array(); $index[] = '<?php'; $index[] = 'class IndexAction extends Action {'; $index[] = 'public function run() {'; $index[] = 'print("success");'; $index[] = '}'; $index[] = '}'; file_put_contents(self::INDEX_ACT_FILE_PATH, implode("\n", $index)); $index2 = array(); $index2[] = '<?php'; $index2[] = 'class Index2Action extends Action {'; $index2[] = 'public function run() {'; $index2[] = 'print("test");'; $index2[] = '}'; $index2[] = '}'; file_put_contents(self::INDEX2_ACT_FILE_PATH, implode("\n", $index2)); touch(self::EMPTY_ACT_FILE_PATH); } public function setUp() { $this->option = array( 'appDirPath' => self::APP_DIR_PATH ); $this->ctrl = Controller::getInstance($this->option); } public function testGetInstance() { $expect = Controller::getInstance($this->option); // 生成したインスタンスが同じであること $this->assertEquals($this->ctrl, $expect); } public function testRun() { // 指定したアクションが実行されること $this->expectOutputString('test'); $this->ctrl->run('index2'); } public function testRunDefault() { // アクションを指定しない場合に、デフォルトが実行されること $this->expectOutputString('success'); $this->ctrl->run(); } /** * @expectedException PHPUnit_Framework_Error */ public function testBadParamError() { // 半角英数字でない文字を含むアクション名はエラーになること $this->expectOutputString('404 Not Found.'); $this->ctrl->run('../../../../../../../../../etc/passwd%00'); } /** * @expectedException PHPUnit_Framework_Error */ public function testFileNotFoundError() { // アクションクラスファイルが見つからない場合エラーになること $this->expectOutputString('404 Not Found.'); $this->ctrl->run('none'); } /** * @expectedException PHPUnit_Framework_Error */ public function testClassNotFoundError() { // クラスが見つからない場合エラーになること $this->expectOutputString('404 Not Found.'); $this->ctrl->run('empty'); } public static function tearDownAfterClass() { // テスト用ファイル及びディレクトリを削除 unlink(self::INDEX_ACT_FILE_PATH); unlink(self::INDEX2_ACT_FILE_PATH); unlink(self::EMPTY_ACT_FILE_PATH); rmdir(self::ACT_DIR_PATH); rmdir(self::APP_DIR_PATH); } }
続いてソース。
<?php /** * コントローラ * */ class Controller { /** * デフォルトアクション */ const DEFAULT_ACTION = 'index'; /** * インスタンス */ private static $_instance = null; /** * アプリケーションディレクトリパス */ private $_appDirPath; /** * コンストラクタ * * @param array $option 初期化パラメータ */ private function Controller($option) { // アプリケーションディレクトリパス $this->_appDirPath = $option['appDirPath']; } /** * コントローラのインスタンスを取得します。 * * @param array $option 初期化パラメータ * @return Controller コントローラインスタンス */ public static function getInstance($option) { // Singleton if(self::$_instance === null) { self::$_instance = new Controller($option); } return self::$_instance; } /** * 指定アクションを実行します。 * * @param string $actionName アクション名 * @return void */ public function run($actionName = null) { if($actionName === null) { // アクション名指定なしの場合、デフォルトにする $actionName = self::DEFAULT_ACTION; } // アクションインスタンスを生成 $action = $this->_loadAction($actionName); // アクション初期化設定 $config = array( 'appDirPath' => $this->_appDirPath ); // アクションを初期化 $action->initialize($config); // アクションを実行 $action->run(); } /** * 指定アクションのインスタンスを生成します。 * * @param string $actionName アクション名 * @return Action アクションインスタンス */ private function _loadAction($actionName) { try { if(preg_match("/\W/", $actionName)) { // 半角英数字以外が含まれた場合、エラーにする throw new Exception("Bad Parameter. [$actionName]"); } // アクションクラス名を作成 $clazz = ucfirst($actionName) . 'Action'; if(!class_exists($clazz)) { // クラスが存在しない場合、ファイルパスを作成 $path = $this->_appDirPath . "/action/$clazz.php"; if(!file_exists($path)) { // ファイルが存在しない場合、エラーにする throw new Exception("File Not Found. [$path]"); } // ファイル読み込み require_once($path); if(!class_exists($clazz)) { // クラスが存在しない場合、エラーにする throw new Exception("Action Not Found. [$clazz]"); } } // インスタンスを生成して返却 $action = new $clazz; return $action; } catch(Exception $e) { // エラー処理 header('HTTP/1.1 404 Not Found', true); print('404 Not Found.'); trigger_error($e->getMessage(), E_USER_ERROR); exit(); } } }
エラーハンドリングがちょっと適当。とりあえず暫定対応。
HudsonとPhing使ってビルド環境作ってみてたら、今までのテストケース結構手を入れてしまった。
テスト内容は変わってないからまあいいかと。ビルドも通ったし。
そろそろアプリの実装に入ろう。