2 // vim: foldmethod=marker
6 * @author Masaki Fujimoto <fujimoto@php.net>
7 * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
12 // {{{ Ethna_Controller
16 * @todo gatewayでswitchしてるところがダサダサ
18 * @author Masaki Fujimoto <fujimoto@php.net>
22 class Ethna_Controller
28 /** @var string アプリケーションID */
31 /** @var string アプリケーションベースディレクトリ */
34 /** @var string アプリケーションベースURL */
37 /** @var string アプリケーションDSN(Data Source Name) */
40 /** @var array アプリケーションディレクトリ */
41 var $directory = array();
43 /** @var array アプリケーションディレクトリ(デフォルト) */
44 var $directory_default = array(
45 'action' => 'app/action',
46 'action_cli' => 'app/action_cli',
47 'action_xmlrpc' => 'app/action_xmlrpc',
49 'plugin' => 'app/plugin',
52 'filter' => 'app/filter',
56 'template' => 'template',
57 'template_c' => 'tmp',
64 /** @var array DBアクセス定義 */
69 /** @var array 拡張子設定 */
75 /** @var array クラス設定 */
78 /** @var array クラス設定(デフォルト) */
79 var $class_default = array(
80 'class' => 'Ethna_ClassFactory',
81 'backend' => 'Ethna_Backend',
82 'config' => 'Ethna_Config',
84 'error' => 'Ethna_ActionError',
85 'form' => 'Ethna_ActionForm',
86 'i18n' => 'Ethna_I18N',
87 'logger' => 'Ethna_Logger',
88 'plugin' => 'Ethna_Plugin',
89 'renderer' => 'Ethna_Renderer_Smarty',
90 'session' => 'Ethna_Session',
91 'sql' => 'Ethna_AppSQL',
92 'view' => 'Ethna_ViewClass',
93 'url_handler' => 'Ethna_UrlHandler',
96 /** @var array 検索対象となるプラグインのアプリケーションIDのリスト */
97 var $plugin_search_appids;
99 /** @var array フィルタ設定 */
103 /** @var string 使用言語設定 */
106 /** @var string システム側エンコーディング */
107 var $system_encoding;
109 /** @var string クライアント側エンコーディング */
110 var $client_encoding;
112 /** @var string 現在実行中のアクション名 */
115 /** @var string 現在実行中のXMLRPCメソッド名 */
116 var $xmlrpc_method_name;
118 /** @var array forward定義 */
119 var $forward = array();
121 /** @var array action定義 */
122 var $action = array();
124 /** @var array action(CLI)定義 */
125 var $action_cli = array();
127 /** @var array action(XMLRPC)定義 */
128 var $action_xmlrpc = array();
130 /** @var array アプリケーションマネージャ定義 */
131 var $manager = array();
133 /** @var object レンダラー */
134 var $renderer = null;
136 /** @var array smarty modifier定義 */
137 var $smarty_modifier_plugin = array();
139 /** @var array smarty function定義 */
140 var $smarty_function_plugin = array();
142 /** @var array smarty block定義 */
143 var $smarty_block_plugin = array();
145 /** @var array smarty prefilter定義 */
146 var $smarty_prefilter_plugin = array();
148 /** @var array smarty postfilter定義 */
149 var $smarty_postfilter_plugin = array();
151 /** @var array smarty outputfilter定義 */
152 var $smarty_outputfilter_plugin = array();
155 /** @var array フィルターチェイン(Ethna_Filterオブジェクトの配列) */
156 var $filter_chain = array();
158 /** @var object Ethna_ClassFactory クラスファクトリオブジェクト */
159 var $class_factory = null;
161 /** @var object Ethna_ActionForm フォームオブジェクト */
162 var $action_form = null;
164 /** @var object Ethna_View ビューオブジェクト */
167 /** @var object Ethna_Config 設定オブジェクト */
170 /** @var object Ethna_Logger ログオブジェクト */
173 /** @var object Ethna_Plugin プラグインオブジェクト */
176 /** @var string リクエストのゲートウェイ(www/cli/rest/xmlrpc/soap...) */
177 var $gateway = GATEWAY_WWW;
183 * Ethna_Controllerクラスのコンストラクタ
187 function Ethna_Controller($gateway = GATEWAY_WWW)
189 $GLOBALS['_Ethna_controller'] =& $this;
190 if ($this->base === "") {
191 // EthnaコマンドなどでBASEが定義されていない場合がある
192 if (defined('BASE')) {
197 $this->gateway = $gateway;
200 foreach ($this->class_default as $key => $val) {
201 if (isset($this->class[$key]) == false) {
202 $this->class[$key] = $val;
207 foreach ($this->directory_default as $key => $val) {
208 if (isset($this->directory[$key]) == false) {
209 $this->directory[$key] = $val;
214 $class_factory = $this->class['class'];
215 $this->class_factory =& new $class_factory($this, $this->class);
218 Ethna::setErrorCallback(array(&$this, 'handleError'));
220 // ディレクトリ名の設定(相対パス->絶対パス)
221 foreach ($this->directory as $key => $value) {
222 if ($key == 'plugins') {
223 // Smartyプラグインディレクトリは配列で指定する
225 foreach (to_array($value) as $elt) {
226 if (Ethna_Util::isAbsolute($elt) == false) {
227 $tmp[] = $this->base . (empty($this->base) ? '' : '/') . $elt;
230 $this->directory[$key] = $tmp;
232 if (Ethna_Util::isAbsolute($value) == false) {
233 $this->directory[$key] = $this->base . (empty($this->base) ? '' : '/') . $value;
239 list($this->language, $this->system_encoding, $this->client_encoding) = $this->_getDefaultLanguage();
241 $this->config =& $this->getConfig();
242 $this->dsn = $this->_prepareDSN();
243 $this->url = $this->config->get('url');
246 $this->plugin =& $this->getPlugin();
248 //// assert (experimental)
249 //if ($this->config->get('debug') === false) {
250 // ini_set('assert.active', 0);
254 $this->logger =& $this->getLogger();
255 $this->plugin->setLogger($this->logger);
256 $this->logger->begin();
259 $this->_activateEthnaManager();
263 * (現在アクティブな)コントローラのインスタンスを返す
266 * @return object Ethna_Controller コントローラのインスタンス
269 function &getInstance()
271 if (isset($GLOBALS['_Ethna_controller'])) {
272 return $GLOBALS['_Ethna_controller'];
283 * @return string アプリケーションID
287 return ucfirst(strtolower($this->appid));
294 * @param string $id アプリケーションID
295 * @return mixed true:OK Ethna_Error:NG
298 function &checkAppId($id)
301 if (strcasecmp($id, 'ethna') === 0
302 || strcasecmp($id, 'app') === 0) {
303 return Ethna::raiseError("Application Id [$id] is reserved\n");
305 if (preg_match('/^[0-9a-zA-Z]+$/', $id) === 0) {
306 return Ethna::raiseError(
307 "Only Numeric(0-9) and Alphabetical(A-Z) is allowed for Application Id\n"
317 * @param string $action_name アクション名
318 * @return mixed true:OK Ethna_Error:NG
321 function &checkActionName($action_name)
324 if (preg_match('/^[a-zA-Z\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/',
325 $action_name) === 0) {
326 return Ethna::raiseError("invalid action name [$action_name]");
335 * @param string $view_name ビュー名
336 * @return mixed true:OK Ethna_Error:NG
339 function &checkViewName($view_name)
342 if (preg_match('/^[a-zA-Z\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/',
344 return Ethna::raiseError("invalid view name [$view_name]");
353 * @param string $db_key DBキー
356 function getDSN($db_key = "")
358 if (isset($this->dsn[$db_key]) == false) {
361 return $this->dsn[$db_key];
368 * @param string $db_key DBキー
369 * @return bool true:persistent false:non-persistent(あるいは設定無し)
371 function getDSN_persistent($db_key = "")
373 $key = sprintf("dsn%s_persistent", $db_key == "" ? "" : "_$db_key");
375 $dsn_persistent = $this->config->get($key);
376 if (is_null($dsn_persistent)) {
379 return $dsn_persistent;
386 * @param string $db_key DBキー("", "r", "rw", "default", "blog_r"...)
387 * @return string $db_keyに対応するDB種別定義(設定が無い場合はnull)
389 function getDBType($db_key = null)
391 if (is_null($db_key)) {
396 if (isset($this->db[$db_key]) == false) {
399 return $this->db[$db_key];
406 * @return string アプリケーションベースURL
414 * アプリケーションベースディレクトリを返す
417 * @return string アプリケーションベースディレクトリ
419 function getBasedir()
425 * クライアントタイプ/言語からテンプレートディレクトリ名を決定する
428 * @return string テンプレートディレクトリ
430 function getTemplatedir()
432 $template = $this->getDirectory('template');
435 if (file_exists($template . '/' . $this->language)) {
436 $template .= '/' . $this->language;
446 * @return string アクションディレクトリ
448 function getActiondir($gateway = null)
451 $gateway = is_null($gateway) ? $this->getGateway() : $gateway;
460 $key = 'action_xmlrpc';
464 return (empty($this->directory[$key]) ? ($this->base . (empty($this->base) ? '' : '/')) : ($this->directory[$key] . "/"));
471 * @return string アクションディレクトリ
473 function getViewdir()
475 return (empty($this->directory['view']) ? ($this->base . (empty($this->base) ? '' : '/')) : ($this->directory['view'] . "/"));
479 * アプリケーションディレクトリ設定を返す
482 * @param string $key ディレクトリタイプ("tmp", "template"...)
483 * @return string $keyに対応したアプリケーションディレクトリ(設定が無い場合はnull)
485 function getDirectory($key)
488 if ($key == 'app' && isset($this->directory[$key]) == false) {
489 return BASE . '/app';
492 if (isset($this->directory[$key]) == false) {
495 return $this->directory[$key];
502 * @param string $key 拡張子タイプ("php", "tpl"...)
503 * @return string $keyに対応した拡張子(設定が無い場合はnull)
505 function getExt($key)
507 if (isset($this->ext[$key]) == false) {
510 return $this->ext[$key];
514 * クラスファクトリオブジェクトのアクセサ(R)
517 * @return object Ethna_ClassFactory クラスファクトリオブジェクト
519 function &getClassFactory()
521 return $this->class_factory;
525 * アクションエラーオブジェクトのアクセサ
528 * @return object Ethna_ActionError アクションエラーオブジェクト
530 function &getActionError()
532 return $this->class_factory->getObject('error');
536 * アクションフォームオブジェクトのアクセサ
539 * @return object Ethna_ActionForm アクションフォームオブジェクト
541 function &getActionForm()
543 // 明示的にクラスファクトリを利用していない
544 return $this->action_form;
551 * @return object Ethna_View ビューオブジェクト
555 // 明示的にクラスファクトリを利用していない
563 * @return object Ethna_Backend backendオブジェクト
565 function &getBackend()
567 return $this->class_factory->getObject('backend');
574 * @return object Ethna_Config 設定オブジェクト
576 function &getConfig()
578 return $this->class_factory->getObject('config');
585 * @return object Ethna_I18N i18nオブジェクト
589 return $this->class_factory->getObject('i18n');
596 * @return object Ethna_Logger ログオブジェクト
598 function &getLogger()
600 return $this->class_factory->getObject('logger');
607 * @return object Ethna_Session セッションオブジェクト
609 function &getSession()
611 return $this->class_factory->getObject('session');
618 * @return object Ethna_AppSQL SQLオブジェクト
622 return $this->class_factory->getObject('sql');
629 * @return object Ethna_Plugin プラグインオブジェクト
631 function &getPlugin()
633 return $this->class_factory->getObject('plugin');
640 * @return object Ethna_UrlHandler URLハンドラオブジェクト
642 function &getUrlHandler()
644 return $this->class_factory->getObject('url_handler');
651 * @return array マネージャ一覧
654 function getManagerList()
656 return $this->manager;
663 * @return string 実行中のアクション名
665 function getCurrentActionName()
667 return $this->action_name;
674 * @return string 実行中のXMLRPCメソッド名
676 function getXmlrpcMethodName()
678 return $this->xmlrpc_method_name;
685 * @return array 使用言語,システムエンコーディング名,クライアントエンコーディング名
687 function getLanguage()
689 return array($this->language, $this->system_encoding, $this->client_encoding);
697 function getGateway()
699 return $this->gateway;
707 function setGateway($gateway)
709 $this->gateway = $gateway;
716 * @param string $class_name アプリケーションコントローラのクラス名
717 * @param mixed $action_name 指定のアクション名(省略可)
718 * @param mixed $fallback_action_name アクションが決定できなかった場合に実行されるアクション名(省略可)
721 function main($class_name, $action_name = "", $fallback_action_name = "")
723 $c =& new $class_name;
724 $c->trigger($action_name, $fallback_action_name);
728 * CLIアプリケーションのエントリポイント
731 * @param string $class_name アプリケーションコントローラのクラス名
732 * @param string $action_name 実行するアクション名
733 * @param bool $enable_filter フィルタチェインを有効にするかどうか
736 function main_CLI($class_name, $action_name, $enable_filter = true)
738 $c =& new $class_name(GATEWAY_CLI);
739 $c->action_cli[$action_name] = array();
740 $c->trigger($action_name, "", $enable_filter);
744 * XMLRPCアプリケーションのエントリポイント
749 function main_XMLRPC($class_name)
751 if (extension_loaded('xmlrpc') == false) {
752 die("xmlrpc extension is required to enable this gateway");
755 $c =& new $class_name(GATEWAY_XMLRPC);
756 $c->trigger("", "", false);
760 * SOAPアプリケーションのエントリポイント
763 * @param string $class_name アプリケーションコントローラのクラス名
764 * @param mixed $action_name 指定のアクション名(省略可)
765 * @param mixed $fallback_action_name アクションが決定できなかった場合に実行されるアクション名(省略可)
768 function main_SOAP($class_name, $action_name = "", $fallback_action_name = "")
770 $c =& new $class_name(GATEWAY_SOAP);
771 $c->trigger($action_name, $fallback_action_name);
778 * @param mixed $default_action_name 指定のアクション名
779 * @param mixed $fallback_action_name アクション名が決定できなかった場合に実行されるアクション名
780 * @param bool $enable_filter フィルタチェインを有効にするかどうか
781 * @return mixed 0:正常終了 Ethna_Error:エラー
783 function trigger($default_action_name = "", $fallback_action_name = "", $enable_filter = true)
786 if ($enable_filter) {
787 $this->_createFilterChain();
791 for ($i = 0; $i < count($this->filter_chain); $i++) {
792 $r = $this->filter_chain[$i]->preFilter();
793 if (Ethna::isError($r)) {
799 switch ($this->getGateway()) {
801 $this->_trigger_WWW($default_action_name, $fallback_action_name);
804 $this->_trigger_CLI($default_action_name);
807 $this->_trigger_XMLRPC();
810 $this->_trigger_SOAP();
815 for ($i = count($this->filter_chain) - 1; $i >= 0; $i--) {
816 $r = $this->filter_chain[$i]->postFilter();
817 if (Ethna::isError($r)) {
824 * フレームワークの処理を実行する(WWW)
826 * 引数$default_action_nameに配列が指定された場合、その配列で指定された
827 * アクション以外は受け付けない(指定されていないアクションが指定された
828 * 場合、配列の先頭で指定されたアクションが実行される)
831 * @param mixed $default_action_name 指定のアクション名
832 * @param mixed $fallback_action_name アクション名が決定できなかった場合に実行されるアクション名
833 * @return mixed 0:正常終了 Ethna_Error:エラー
835 function _trigger_WWW($default_action_name = "", $fallback_action_name = "")
838 $action_name = $this->_getActionName($default_action_name, $fallback_action_name);
841 $this->_ethnaManagerEnabledCheck($action_name);
844 $action_obj =& $this->_getAction($action_name);
845 if (is_null($action_obj)) {
846 if ($fallback_action_name != "") {
847 $this->logger->log(LOG_DEBUG, 'undefined action [%s] -> try fallback action [%s]', $action_name, $fallback_action_name);
848 $action_obj =& $this->_getAction($fallback_action_name);
850 if (is_null($action_obj)) {
851 return Ethna::raiseError("undefined action [%s]", E_APP_UNDEFINED_ACTION, $action_name);
853 $action_name = $fallback_action_name;
858 for ($i = 0; $i < count($this->filter_chain); $i++) {
859 $r = $this->filter_chain[$i]->preActionFilter($action_name);
861 $this->logger->log(LOG_DEBUG, 'action [%s] -> [%s] by %s', $action_name, $r, get_class($this->filter_chain[$i]));
865 $this->action_name = $action_name;
868 $this->_setLanguage($this->language, $this->system_encoding, $this->client_encoding);
871 $backend =& $this->getBackend();
873 $form_name = $this->getActionFormName($action_name);
874 $this->action_form =& new $form_name($this);
875 $this->action_form->setFormVars();
878 $backend->setActionForm($this->action_form);
880 $session =& $this->getSession();
882 $forward_name = $backend->perform($action_name);
885 for ($i = count($this->filter_chain) - 1; $i >= 0; $i--) {
886 $r = $this->filter_chain[$i]->postActionFilter($action_name, $forward_name);
888 $this->logger->log(LOG_DEBUG, 'forward [%s] -> [%s] by %s', $forward_name, $r, get_class($this->filter_chain[$i]));
893 // コントローラで遷移先を決定する(オプション)
894 $forward_name = $this->_sortForward($action_name, $forward_name);
896 if ($forward_name != null) {
897 $view_class_name = $this->getViewClassName($forward_name);
898 $this->view =& new $view_class_name($backend, $forward_name, $this->_getForwardPath($forward_name));
899 $this->view->preforward();
900 $this->view->forward();
907 * フレームワークの処理を実行する(CLI)
910 * @param mixed $default_action_name 指定のアクション名
911 * @return mixed 0:正常終了 Ethna_Error:エラー
913 function _trigger_CLI($default_action_name = "")
915 return $this->_trigger_WWW($default_action_name);
919 * フレームワークの処理を実行する(XMLRPC)
922 * @param mixed $action_name 指定のアクション名
923 * @return mixed 0:正常終了 Ethna_Error:エラー
925 function _trigger_XMLRPC($action_name = "")
927 // prepare xmlrpc server
928 $xmlrpc_gateway_method_name = "_Ethna_XmlrpcGateway";
929 $xmlrpc_server = xmlrpc_server_create();
932 $param = xmlrpc_decode_request(file_get_contents('php://input'), $method);
933 $this->xmlrpc_method_name = $method;
935 $request = xmlrpc_encode_request(
936 $xmlrpc_gateway_method_name,
939 'output_type' => 'xml',
940 'verbosity' => 'pretty',
941 'escaping' => array('markup'),
942 'version' => 'xmlrpc',
943 'encoding' => 'utf-8'
947 xmlrpc_server_register_method(
949 $xmlrpc_gateway_method_name,
950 $xmlrpc_gateway_method_name
954 $r = xmlrpc_server_call_method(
959 'output_type' => 'xml',
960 'verbosity' => 'pretty',
961 'escaping' => array('markup'),
962 'version' => 'xmlrpc',
963 'encoding' => 'utf-8'
967 header('Content-Length: ' . strlen($r));
968 header('Content-Type: text/xml; charset=UTF-8');
973 * _trigger_XMLRPCのコールバックメソッド
977 function trigger_XMLRPC($method, $param)
980 $action_obj =& $this->_getAction($method);
981 if (is_null($action_obj)) {
982 return Ethna::raiseError("undefined xmlrpc method [%s]", E_APP_UNDEFINED_ACTION, $method);
986 $backend =& $this->getBackend();
988 $form_name = $this->getActionFormName($method);
989 $this->action_form =& new $form_name($this);
990 $def = $this->action_form->getDef();
992 foreach ($def as $key => $value) {
993 if (isset($param[$n]) == false) {
994 $this->action_form->set($key, null);
996 $this->action_form->set($key, $param[$n]);
1002 $backend->setActionForm($this->action_form);
1004 $session =& $this->getSession();
1005 $session->restore();
1006 $r = $backend->perform($method);
1012 * SOAPフレームワークの処理を実行する
1016 function _trigger_SOAP()
1019 $gg =& new Ethna_SOAP_GatewayGenerator();
1020 $script = $gg->generate();
1024 $server =& new SoapServer(null, array('uri' => $this->config->get('url')));
1025 $server->setClass($gg->getClassName());
1032 * エラー発生時の追加処理を行いたい場合はこのメソッドをオーバーライドする
1033 * (アラートメール送信等−デフォルトではログ出力時にアラートメール
1034 * が送信されるが、エラー発生時に別にアラートメールをここで送信
1038 * @param object Ethna_Error エラーオブジェクト
1040 function handleError(&$error)
1043 list ($log_level, $dummy) = $this->logger->errorLevelToLogLevel($error->getLevel());
1044 $message = $error->getMessage();
1045 $this->logger->log($log_level, sprintf("%s [ERROR CODE(%d)]", $message, $error->getCode()));
1052 * @param int $code エラーコード
1053 * @return string エラーメッセージ
1055 function getErrorMessage($code)
1057 $message_list =& $GLOBALS['_Ethna_error_message_list'];
1058 for ($i = count($message_list)-1; $i >= 0; $i--) {
1059 if (array_key_exists($code, $message_list[$i])) {
1060 return $message_list[$i][$code];
1070 * @param mixed $default_action_name 指定のアクション名
1071 * @return string 実行するアクション名
1073 function _getActionName($default_action_name, $fallback_action_name)
1075 // フォームから要求されたアクション名を取得する
1076 $form_action_name = $this->_getActionName_Form();
1077 $form_action_name = preg_replace('/[^a-z0-9\-_]+/i', '', $form_action_name);
1078 $this->logger->log(LOG_DEBUG, 'form_action_name[%s]', $form_action_name);
1080 // Ethnaマネージャへのフォームからのリクエストは拒否
1081 if ($form_action_name == "__ethna_info__" ||
1082 $form_action_name == "__ethna_unittest__") {
1083 $form_action_name = "";
1086 // フォームからの指定が無い場合はエントリポイントに指定されたデフォルト値を利用する
1087 if ($form_action_name == "" && count($default_action_name) > 0) {
1088 $tmp = is_array($default_action_name) ? $default_action_name[0] : $default_action_name;
1089 if ($tmp{strlen($tmp)-1} == '*') {
1090 $tmp = substr($tmp, 0, -1);
1092 $this->logger->log(LOG_DEBUG, '-> default_action_name[%s]', $tmp);
1093 $action_name = $tmp;
1095 $action_name = $form_action_name;
1098 // エントリポイントに配列が指定されている場合は指定以外のアクション名は拒否する
1099 if (is_array($default_action_name)) {
1100 if ($this->_isAcceptableActionName($action_name, $default_action_name) == false) {
1101 // 指定以外のアクション名で合った場合は$fallback_action_name(or デフォルト)
1102 $tmp = $fallback_action_name != "" ? $fallback_action_name : $default_action_name[0];
1103 if ($tmp{strlen($tmp)-1} == '*') {
1104 $tmp = substr($tmp, 0, -1);
1106 $this->logger->log(LOG_DEBUG, '-> fallback_action_name[%s]', $tmp);
1107 $action_name = $tmp;
1111 $this->logger->log(LOG_DEBUG, '<<< action_name[%s] >>>', $action_name);
1113 return $action_name;
1117 * フォームにより要求されたアクション名を返す
1119 * アプリケーションの性質に応じてこのメソッドをオーバーライドして下さい。
1120 * デフォルトでは"action_"で始まるフォーム値の"action_"の部分を除いたもの
1121 * ("action_sample"なら"sample")がアクション名として扱われます
1124 * @return string フォームにより要求されたアクション名
1126 function _getActionName_Form()
1128 if (isset($_SERVER['REQUEST_METHOD']) == false) {
1132 $url_handler =& $this->getUrlHandler();
1133 if ($_SERVER['REQUEST_METHOD'] == "GET") {
1135 } else if ($_SERVER['REQUEST_METHOD'] == "POST") {
1139 if (empty($_SERVER['URL_HANDLER']) == false) {
1140 $tmp_vars['__url_handler__'] = $_SERVER['URL_HANDLER'];
1141 $tmp_vars['__url_info__'] = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : null;
1142 $tmp_vars = $url_handler->requestToAction($tmp_vars);
1144 if ($_SERVER['REQUEST_METHOD'] == "GET") {
1145 $_GET = array_merge($_GET, $tmp_vars);
1146 } else if ($_SERVER['REQUEST_METHOD'] == "POST") {
1147 $_POST = array_merge($_POST, $tmp_vars);
1149 $_REQUEST = array_merge($_REQUEST, $tmp_vars);
1152 if (strcasecmp($_SERVER['REQUEST_METHOD'], 'post') == 0) {
1153 $http_vars =& $_POST;
1155 $http_vars =& $_GET;
1158 // フォーム値からリクエストされたアクション名を取得する
1159 $action_name = $sub_action_name = null;
1160 foreach ($http_vars as $name => $value) {
1161 if ($value == "" || strncmp($name, 'action_', 7) != 0) {
1165 $tmp = substr($name, 7);
1168 if (preg_match('/_x$/', $name) || preg_match('/_y$/', $name)) {
1169 $tmp = substr($tmp, 0, strlen($tmp)-2);
1172 // value="dummy"となっているものは優先度を下げる
1173 if ($value == "dummy") {
1174 $sub_action_name = $tmp;
1176 $action_name = $tmp;
1179 if ($action_name == null) {
1180 $action_name = $sub_action_name;
1183 return $action_name;
1187 * アクション名を指定するクエリ/HTMLを生成する
1190 * @param string $action action to request
1191 * @param string $type hidden, url...
1192 * @todo consider gateway
1194 function getActionRequest($action, $type = "hidden")
1197 if ($type == "hidden") {
1198 $s = sprintf('<input type="hidden" name="action_%s" value="true">', htmlspecialchars($action, ENT_QUOTES));
1199 } else if ($type == "url") {
1200 $s = sprintf('action_%s=true', urlencode($action));
1206 * フォームにより要求されたアクション名に対応する定義を返す
1209 * @param string $action_name アクション名
1210 * @return array アクション定義
1212 function &_getAction($action_name, $gateway = null)
1215 $gateway = is_null($gateway) ? $this->getGateway() : $gateway;
1218 $action =& $this->action;
1221 $action =& $this->action_cli;
1223 case GATEWAY_XMLRPC:
1224 $action =& $this->action_xmlrpc;
1228 $action_obj = array();
1229 if (isset($action[$action_name])) {
1230 $action_obj = $action[$action_name];
1231 if (isset($action_obj['inspect']) && $action_obj['inspect']) {
1235 $this->logger->log(LOG_DEBUG, "action [%s] is not defined -> try default", $action_name);
1238 // アクションスクリプトのインクルード
1239 $this->_includeActionScript($action_obj, $action_name);
1242 if (isset($action_obj['class_name']) == false) {
1243 $action_obj['class_name'] = $this->getDefaultActionClass($action_name);
1246 if (isset($action_obj['form_name']) == false) {
1247 $action_obj['form_name'] = $this->getDefaultFormClass($action_name);
1248 } else if (class_exists($action_obj['form_name']) == false) {
1249 // 明示指定されたフォームクラスが定義されていない場合は警告
1250 $this->logger->log(LOG_WARNING, 'stated form class is not defined [%s]', $action_obj['form_name']);
1254 if (class_exists($action_obj['class_name']) == false) {
1255 $this->logger->log(LOG_NOTICE, 'action class is not defined [%s]', $action_obj['class_name']);
1256 $_ret_object = null;
1257 return $_ret_object;
1259 if (class_exists($action_obj['form_name']) == false) {
1261 $class_name = $this->class_factory->getObjectName('form');
1262 $this->logger->log(LOG_DEBUG, 'form class is not defined [%s] -> falling back to default [%s]', $action_obj['form_name'], $class_name);
1263 $action_obj['form_name'] = $class_name;
1266 $action_obj['inspect'] = true;
1267 $action[$action_name] = $action_obj;
1268 return $action[$action_name];
1272 * アクション名とアクションクラスからの戻り値に基づいて遷移先を決定する
1275 * @param string $action_name アクション名
1276 * @param string $retval アクションクラスからの戻り値
1277 * @return string 遷移先
1279 function _sortForward($action_name, $retval)
1289 function _createFilterChain()
1291 $this->filter_chain = array();
1292 foreach ($this->filter as $filter) {
1293 //バージョン0.2.0以前のフィルタ群から探す
1294 $file = sprintf("%s/%s.%s", $this->getDirectory('filter'), $filter,$this->getExt('php'));
1295 if (file_exists($file)) {
1297 if (class_exists($filter)) {
1298 $this->filter_chain[] =& new $filter($this);
1300 } else { //プラグインから探す.
1301 $filter_plugin =& $this->plugin->getPlugin('Filter', $filter);
1302 if (Ethna::isError($filter_plugin)) {
1306 $this->filter_chain[] =& $filter_plugin;
1312 * アクション名が実行許可されているものかどうかを返す
1315 * @param string $action_name リクエストされたアクション名
1316 * @param array $default_action_name 許可されているアクション名
1317 * @return bool true:許可 false:不許可
1319 function _isAcceptableActionName($action_name, $default_action_name)
1321 foreach (to_array($default_action_name) as $name) {
1322 if ($action_name == $name) {
1324 } else if ($name{strlen($name)-1} == '*') {
1325 if (strncmp($action_name, substr($name, 0, -1), strlen($name)-1) == 0) {
1334 * 指定されたアクションのフォームクラス名を返す(オブジェクトの生成は行わない)
1337 * @param string $action_name アクション名
1338 * @return string アクションのフォームクラス名
1340 function getActionFormName($action_name)
1342 $action_obj =& $this->_getAction($action_name);
1343 if (is_null($action_obj)) {
1347 return $action_obj['form_name'];
1351 * アクションに対応するフォームクラス名が省略された場合のデフォルトクラス名を返す
1353 * デフォルトでは[プロジェクトID]_Form_[アクション名]となるので好み応じてオーバライドする
1356 * @param string $action_name アクション名
1357 * @return string アクションフォーム名
1359 function getDefaultFormClass($action_name, $gateway = null)
1361 $gateway_prefix = $this->_getGatewayPrefix($gateway);
1363 $postfix = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($action_name));
1364 $r = sprintf("%s_%sForm_%s", $this->getAppId(), $gateway_prefix ? $gateway_prefix . "_" : "", $postfix);
1365 $this->logger->log(LOG_DEBUG, "default action class [%s]", $r);
1371 * getDefaultFormClass()で取得したクラス名からアクション名を取得する
1373 * getDefaultFormClass()をオーバーライドした場合、こちらも合わせてオーバーライド
1377 * @param string $class_name フォームクラス名
1378 * @return string アクション名
1380 function actionFormToName($class_name)
1382 $prefix = sprintf("%s_Form_", $this->getAppId());
1383 if (preg_match("/$prefix(.*)/", $class_name, $match) == 0) {
1387 $target = $match[1];
1389 $action_name = substr(preg_replace('/([A-Z])/e', "'_' . strtolower('\$1')", $target), 1);
1391 return $action_name;
1395 * アクションに対応するフォームパス名が省略された場合のデフォルトパス名を返す
1397 * デフォルトでは_getDefaultActionPath()と同じ結果を返す(1ファイルに
1398 * アクションクラスとフォームクラスが記述される)ので、好みに応じて
1402 * @param string $action_name アクション名
1403 * @return string form classが定義されるスクリプトのパス名
1405 function getDefaultFormPath($action_name)
1407 return $this->getDefaultActionPath($action_name);
1411 * 指定されたアクションのクラス名を返す(オブジェクトの生成は行わない)
1414 * @param string $action_name アクションの名称
1415 * @return string アクションのクラス名
1417 function getActionClassName($action_name)
1419 $action_obj =& $this->_getAction($action_name);
1420 if ($action_obj == null) {
1424 return $action_obj['class_name'];
1428 * アクションに対応するアクションクラス名が省略された場合のデフォルトクラス名を返す
1430 * デフォルトでは[プロジェクトID]_Action_[アクション名]となるので好み応じてオーバライドする
1433 * @param string $action_name アクション名
1434 * @return string アクションクラス名
1436 function getDefaultActionClass($action_name, $gateway = null)
1438 $gateway_prefix = $this->_getGatewayPrefix($gateway);
1440 $postfix = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($action_name));
1441 $r = sprintf("%s_%sAction_%s", $this->getAppId(), $gateway_prefix ? $gateway_prefix . "_" : "", $postfix);
1442 $this->logger->log(LOG_DEBUG, "default action class [%s]", $r);
1448 * getDefaultActionClass()で取得したクラス名からアクション名を取得する
1450 * getDefaultActionClass()をオーバーライドした場合、こちらも合わせてオーバーライド
1454 * @param string $class_name アクションクラス名
1455 * @return string アクション名
1457 function actionClassToName($class_name)
1459 $prefix = sprintf("%s_Action_", $this->getAppId());
1460 if (preg_match("/$prefix(.*)/", $class_name, $match) == 0) {
1464 $target = $match[1];
1466 $action_name = substr(preg_replace('/([A-Z])/e', "'_' . strtolower('\$1')", $target), 1);
1468 return $action_name;
1472 * アクションに対応するアクションパス名が省略された場合のデフォルトパス名を返す
1474 * デフォルトでは"foo_bar" -> "/Foo/Bar.php"となるので好み応じてオーバーライドする
1477 * @param string $action_name アクション名
1478 * @return string アクションクラスが定義されるスクリプトのパス名
1480 function getDefaultActionPath($action_name)
1482 $r = preg_replace('/_(.)/e', "'/' . strtoupper('\$1')", ucfirst($action_name)) . '.' . $this->getExt('php');
1483 $this->logger->log(LOG_DEBUG, "default action path [%s]", $r);
1489 * 指定された遷移名に対応するビュークラス名を返す(オブジェクトの生成は行わない)
1492 * @param string $forward_name 遷移先の名称
1493 * @return string view classのクラス名
1495 function getViewClassName($forward_name)
1497 if ($forward_name == null) {
1501 if (isset($this->forward[$forward_name])) {
1502 $forward_obj = $this->forward[$forward_name];
1504 $forward_obj = array();
1507 if (isset($forward_obj['view_name'])) {
1508 $class_name = $forward_obj['view_name'];
1509 if (class_exists($class_name)) {
1517 $this->_includeViewScript($forward_obj, $forward_name);
1519 if (is_null($class_name) == false && class_exists($class_name)) {
1521 } else if (is_null($class_name) == false) {
1522 $this->logger->log(LOG_WARNING, 'stated view class is not defined [%s] -> try default', $class_name);
1525 $class_name = $this->getDefaultViewClass($forward_name);
1526 if (class_exists($class_name)) {
1529 $class_name = $this->class_factory->getObjectName('view');
1530 $this->logger->log(LOG_DEBUG, 'view class is not defined for [%s] -> use default [%s]', $forward_name, $class_name);
1536 * 遷移名に対応するビュークラス名が省略された場合のデフォルトクラス名を返す
1538 * デフォルトでは[プロジェクトID]_View_[遷移名]となるので好み応じてオーバライドする
1541 * @param string $forward_name forward名
1542 * @return string view classクラス名
1544 function getDefaultViewClass($forward_name, $gateway = null)
1546 $gateway_prefix = $this->_getGatewayPrefix($gateway);
1548 $postfix = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($forward_name));
1549 $r = sprintf("%s_%sView_%s", $this->getAppId(), $gateway_prefix ? $gateway_prefix . "_" : "", $postfix);
1550 $this->logger->log(LOG_DEBUG, "default view class [%s]", $r);
1556 * 遷移名に対応するビューパス名が省略された場合のデフォルトパス名を返す
1558 * デフォルトでは"foo_bar" -> "/Foo/Bar.php"となるので好み応じてオーバーライドする
1561 * @param string $forward_name forward名
1562 * @return string view classが定義されるスクリプトのパス名
1564 function getDefaultViewPath($forward_name)
1566 $r = preg_replace('/_(.)/e', "'/' . strtoupper('\$1')", ucfirst($forward_name)) . '.' . $this->getExt('php');
1567 $this->logger->log(LOG_DEBUG, "default view path [%s]", $r);
1573 * 遷移名に対応するテンプレートパス名が省略された場合のデフォルトパス名を返す
1575 * デフォルトでは"foo_bar"というforward名が"foo/bar" + テンプレート拡張子となる
1579 * @param string $forward_name forward名
1580 * @return string forwardパス名
1582 function getDefaultForwardPath($forward_name)
1584 return str_replace('_', '/', $forward_name) . '.' . $this->ext['tpl'];
1588 * テンプレートパス名から遷移名を取得する
1590 * getDefaultForwardPath()をオーバーライドした場合、こちらも合わせてオーバーライド
1594 * @param string $forward_path テンプレートパス名
1595 * @return string 遷移名
1597 function forwardPathToName($forward_path)
1599 $forward_path = preg_replace('/^\/+/', '', $forward_path);
1600 $forward_path = preg_replace(sprintf('/\.%s$/', $this->getExt('tpl')), '', $forward_path);
1602 return str_replace('/', '_', $forward_path);
1606 * 遷移名からテンプレートファイルのパス名を取得する
1609 * @param string $forward_name forward名
1610 * @return string テンプレートファイルのパス名
1612 function _getForwardPath($forward_name)
1614 $forward_obj = null;
1616 if (isset($this->forward[$forward_name]) == false) {
1618 $this->forward[$forward_name] = array();
1620 $forward_obj =& $this->forward[$forward_name];
1621 if (isset($forward_obj['forward_path']) == false) {
1623 $forward_obj['forward_path'] = $this->getDefaultForwardPath($forward_name);
1626 return $forward_obj['forward_path'];
1630 * レンダラを取得する(getTemplateEngine()はそのうち廃止されgetRenderer()に統合される予定)
1633 * @return object Ethna_Renderer レンダラオブジェクト
1635 function &getRenderer()
1637 $_ret_object =& $this->getTemplateEngine();
1638 return $_ret_object;
1645 * @return object Ethna_Renderer レンダラオブジェクト
1648 function &getTemplateEngine()
1650 if (is_object($this->renderer)) {
1651 return $this->renderer;
1654 $this->renderer =& $this->class_factory->getObject('renderer');
1657 if (strtolower(get_class($this->renderer)) == "ethna_renderer_smarty") {
1658 // user defined modifiers
1659 foreach ($this->smarty_modifier_plugin as $modifier) {
1660 $name = str_replace('smarty_modifier_', '', $modifier);
1661 $this->renderer->setPlugin($name,'modifier', $modifier);
1664 // user defined functions
1665 foreach ($this->smarty_function_plugin as $function) {
1666 if (!is_array($function)) {
1667 $name = str_replace('smarty_function_', '', $function);
1668 $this->renderer->setPlugin($name, 'function', $function);
1670 $this->renderer->setPlugin($function[1], 'function', $function);
1674 // user defined blocks
1675 foreach ($this->smarty_block_plugin as $block) {
1676 if (!is_array($block)) {
1677 $name = str_replace('smarty_block_', '', $block);
1678 $this->renderer->setPlugin($name,'block', $block);
1680 $this->renderer->setPlugin($block[1],'block', $block);
1684 // user defined prefilters
1685 foreach ($this->smarty_prefilter_plugin as $prefilter) {
1686 if (!is_array($prefilter)) {
1687 $name = str_replace('smarty_prefilter_', '', $prefilter);
1688 $this->renderer->setPlugin($name,'prefilter', $prefilter);
1690 $this->renderer->setPlugin($prefilter[1],'prefilter', $prefilter);
1694 // user defined postfilters
1695 foreach ($this->smarty_postfilter_plugin as $postfilter) {
1696 if (!is_array($postfilter)) {
1697 $name = str_replace('smarty_postfilter_', '', $postfilter);
1698 $this->renderer->setPlugin($name,'postfilter', $postfilter);
1700 $this->renderer->setPlugin($postfilter[1],'postfilter', $postfilter);
1704 // user defined outputfilters
1705 foreach ($this->smarty_outputfilter_plugin as $outputfilter) {
1706 if (!is_array($outputfilter)) {
1707 $name = str_replace('smarty_outputfilter_', '', $outputfilter);
1708 $this->renderer->setPlugin($name,'outputfilter', $outputfilter);
1710 $this->renderer->setPlugin($outputfilter[1],'outputfilter', $outputfilter);
1715 //テンプレートエンジンのデフォルトの設定
1716 $this->_setDefaultTemplateEngine($this->renderer);
1719 return $this->renderer;
1723 * テンプレートエンジンのデフォルト状態を設定する
1726 * @param object Ethna_Renderer レンダラオブジェクト
1729 function _setDefaultTemplateEngine(&$renderer)
1736 * 将来への拡張のためのみに存在しています。現在は特にオーバーライドの必要はありません。
1739 * @param string $language 言語定義(LANG_JA, LANG_EN...)
1740 * @param string $system_encoding システムエンコーディング名
1741 * @param string $client_encoding クライアントエンコーディング
1743 function _setLanguage($language, $system_encoding = null, $client_encoding = null)
1745 $this->language = $language;
1746 $this->system_encoding = $system_encoding;
1747 $this->client_encoding = $client_encoding;
1749 $i18n =& $this->getI18N();
1750 $i18n->setLanguage($language, $system_encoding, $client_encoding);
1754 * デフォルト状態での使用言語を取得する
1757 * @return array 使用言語,システムエンコーディング名,クライアントエンコーディング名
1759 function _getDefaultLanguage()
1761 return array(LANG_JA, null, null);
1765 * デフォルト状態でのゲートウェイを取得する
1768 * @return int ゲートウェイ定義(GATEWAY_WWW, GATEWAY_CLI...)
1770 function _getDefaultGateway($gateway)
1772 if (is_null($GLOBALS['_Ethna_gateway']) == false) {
1773 return $GLOBALS['_Ethna_gateway'];
1779 * ゲートウェイに対応したクラス名のプレフィクスを取得する
1782 * @param string $gateway ゲートウェイ
1783 * @return string ゲートウェイクラスプレフィクス
1785 function _getGatewayPrefix($gateway = null)
1787 $gateway = is_null($gateway) ? $this->getGateway() : $gateway;
1795 case GATEWAY_XMLRPC:
1810 * @param string $name マネージャキー
1811 * @return string マネージャクラス名
1813 function getManagerClassName($name)
1815 return sprintf('%s_%sManager', $this->getAppId(), ucfirst($name));
1819 * アプリケーションオブジェクトクラス名を取得する
1822 * @param string $name アプリケーションオブジェクトキー
1823 * @return string マネージャクラス名
1825 function getObjectClassName($name)
1827 $name = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($name));
1828 return sprintf('%s_%s', $this->getAppId(), $name);
1832 * アクションスクリプトをインクルードする
1834 * ただし、インクルードしたファイルにクラスが正しく定義されているかどうかは保証しない
1837 * @param array $action_obj アクション定義
1838 * @param string $action_name アクション名
1840 function _includeActionScript($action_obj, $action_name)
1842 $class_path = $form_path = null;
1844 $action_dir = $this->getActiondir();
1847 if (isset($action_obj['class_path'])) {
1849 $tmp_path = $action_obj['class_path'];
1850 if (Ethna_Util::isAbsolute($tmp_path) == false) {
1851 $tmp_path = $action_dir . $tmp_path;
1854 if (file_exists($tmp_path) == false) {
1855 $this->logger->log(LOG_WARNING, 'class_path file not found [%s] -> try default', $tmp_path);
1857 include_once $tmp_path;
1858 $class_path = $tmp_path;
1863 if (is_null($class_path)) {
1864 $class_path = $this->getDefaultActionPath($action_name);
1865 if (file_exists($action_dir . $class_path)) {
1866 include_once $action_dir . $class_path;
1868 $this->logger->log(LOG_DEBUG, 'default action file not found [%s] -> try all files', $class_path);
1874 if (is_null($class_path)) {
1875 $this->_includeDirectory($this->getActiondir());
1880 if (isset($action_obj['form_path'])) {
1882 $tmp_path = $action_obj['form_path'];
1883 if (Ethna_Util::isAbsolute($tmp_path) == false) {
1884 $tmp_path = $action_dir . $tmp_path;
1887 if ($tmp_path == $class_path) {
1890 if (file_exists($tmp_path) == false) {
1891 $this->logger->log(LOG_WARNING, 'form_path file not found [%s] -> try default', $tmp_path);
1893 include_once $tmp_path;
1894 $form_path = $tmp_path;
1899 if (is_null($form_path)) {
1900 $form_path = $this->getDefaultFormPath($action_name);
1901 if ($form_path == $class_path) {
1904 if (file_exists($action_dir . $form_path)) {
1905 include_once $action_dir . $form_path;
1907 $this->logger->log(LOG_DEBUG, 'default form file not found [%s] -> maybe falling back to default form class', $form_path);
1915 * ただし、インクルードしたファイルにクラスが正しく定義されているかどうかは保証しない
1918 * @param array $forward_obj 遷移定義
1919 * @param string $forward_name 遷移名
1921 function _includeViewScript($forward_obj, $forward_name)
1923 $view_dir = $this->getViewdir();
1926 if (isset($forward_obj['view_path'])) {
1928 $tmp_path = $forward_obj['view_path'];
1929 if (Ethna_Util::isAbsolute($tmp_path) == false) {
1930 $tmp_path = $view_dir . $tmp_path;
1933 if (file_exists($tmp_path) == false) {
1934 $this->logger->log(LOG_WARNING, 'view_path file not found [%s] -> try default', $tmp_path);
1936 include_once $tmp_path;
1942 $view_path = $this->getDefaultViewPath($forward_name);
1943 if (file_exists($view_dir . $view_path)) {
1944 include_once $view_dir . $view_path;
1947 $this->logger->log(LOG_DEBUG, 'default view file not found [%s]', $view_path);
1953 * ディレクトリ以下の全てのスクリプトをインクルードする
1957 function _includeDirectory($dir)
1959 $ext = "." . $this->ext['php'];
1960 $ext_len = strlen($ext);
1962 if (is_dir($dir) == false) {
1966 $dh = opendir($dir);
1968 while (($file = readdir($dh)) !== false) {
1969 if ($file != '.' && $file != '..' && is_dir("$dir/$file")) {
1970 $this->_includeDirectory("$dir/$file");
1972 if (substr($file, -$ext_len, $ext_len) != $ext) {
1975 include_once $dir . '/' . $file;
1982 * 設定ファイルのDSN定義から使用するデータを再構築する(スレーブアクセス分岐等)
1984 * DSNの定義方法(デフォルト:設定ファイル)を変えたい場合はここをオーバーライドする
1987 * @return array DSN定義(array('DBキー1' => 'dsn1', 'DBキー2' => 'dsn2', ...))
1989 function _prepareDSN()
1993 foreach ($this->db as $key => $value) {
1994 $config_key = "dsn";
1996 $config_key .= "_$key";
1998 $dsn = $this->config->get($config_key);
1999 if (is_array($dsn)) {
2000 // 種別1つにつき複数DSNが定義されている場合はアクセス分岐
2001 $dsn = $this->_selectDSN($key, $dsn);
2011 * スレーブサーバへの振分け処理(デフォルト:ランダム)を変更したい場合はこのメソッドをオーバーライドする
2014 * @param string $type DB種別
2015 * @param array $dsn_list DSN一覧
2016 * @return string 選択されたDSN
2018 function _selectDSN($type, $dsn_list)
2020 if (is_array($dsn_list) == false) {
2025 list($usec, $sec) = explode(' ', microtime());
2026 mt_srand($sec + ((float) $usec * 100000));
2027 $n = mt_rand(0, count($dsn_list)-1);
2029 return $dsn_list[$n];
2035 * 不要な場合は空のメソッドとしてオーバーライドしてもよい
2039 function _activateEthnaManager()
2041 if ($this->config->get('debug') == false) {
2045 require_once ETHNA_BASE . '/class/Ethna_InfoManager.php';
2047 // see if we have simpletest
2048 if (file_exists_ex('simpletest/unit_tester.php', true)) {
2049 require_once ETHNA_BASE . '/class/Ethna_UnitTestManager.php';
2053 $this->action['__ethna_info__'] = array(
2054 'form_name' => 'Ethna_Form_Info',
2055 'form_path' => sprintf('%s/class/Action/Ethna_Action_Info.php', ETHNA_BASE),
2056 'class_name' => 'Ethna_Action_Info',
2057 'class_path' => sprintf('%s/class/Action/Ethna_Action_Info.php', ETHNA_BASE),
2061 $this->forward['__ethna_info__'] = array(
2062 'forward_path' => sprintf('%s/tpl/info.tpl', ETHNA_BASE),
2063 'view_name' => 'Ethna_View_Info',
2064 'view_path' => sprintf('%s/class/View/Ethna_View_Info.php', ETHNA_BASE),
2069 $this->action['__ethna_unittest__'] = array(
2070 'form_name' => 'Ethna_Form_UnitTest',
2071 'form_path' => sprintf('%s/class/Action/Ethna_Action_UnitTest.php', ETHNA_BASE),
2072 'class_name' => 'Ethna_Action_UnitTest',
2073 'class_path' => sprintf('%s/class/Action/Ethna_Action_UnitTest.php', ETHNA_BASE),
2077 $this->forward['__ethna_unittest__'] = array(
2078 'forward_path' => sprintf('%s/tpl/unittest.tpl', ETHNA_BASE),
2079 'view_name' => 'Ethna_View_UnitTest',
2080 'view_path' => sprintf('%s/class/View/Ethna_View_UnitTest.php', ETHNA_BASE),
2086 * Ethnaマネージャが実行可能かをチェックする
2088 * Ethnaマネージャを実行するよう指示されているにも関わらず、
2089 * debug が trueでない場合は実行を停止する。
2093 function _ethnaManagerEnabledCheck($action_name)
2095 if ($this->config->get('debug') == false
2096 && ($action_name == '__ethna_info__' || $action_name == '__ethna_unittest__')) {
2097 $this->ethnaManagerCheckErrorMsg($action_name);
2103 * Ethnaマネージャが実行不能な場合のエラーメッセージを
2104 * 表示する。運用上の都合でこのメッセージを出力したくない
2105 * 場合は、このメソッドをオーバーライドせよ
2109 function ethnaManagerCheckErrorMsg($action_name)
2111 $appid = $this->getAppId();
2112 $run_action = ($action_name == '__ethna_info__')
2113 ? ' show Application Info List '
2114 : ' run Unit Test ';
2115 echo "Ethna cannot {$run_action} under your application setting.<br>";
2116 echo "HINT: You must set {$appid}/etc/{$appid}.ini debug setting 'true'.<br>";
2118 echo "In {$appid}.ini, please set as follows :<br><br>";
2119 echo "\$config = array ( 'debug' => true, );";
2126 * @return bool CLI実行中フラグ
2131 return $this->gateway == GATEWAY_CLI ? true : false;
2138 * @param bool CLI実行中フラグ
2141 function setCLI($cli)
2143 $this->gateway = $cli ? GATEWAY_CLI : $this->_getDefaultGateway();
2149 * XMLRPCゲートウェイのスタブクラス
2153 function _Ethna_XmlrpcGateway($method_stub, $param)
2155 $ctl =& Ethna_Controller::getInstance();
2156 $method = $ctl->getXmlrpcMethodName();
2157 $r = $ctl->trigger_XMLRPC($method, $param);
2158 if (Ethna::isError($r)) {
2160 'faultCode' => $r->getCode(),
2161 'faultString' => $r->getMessage(),