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 */
29 protected $appid = 'ETHNA';
31 /** @var string アプリケーションベースディレクトリ */
34 /** @protected string アプリケーションベースURL */
37 /** @protected string アプリケーションDSN(Data Source Name) */
40 /** @protected array アプリケーションディレクトリ */
41 protected $directory = array();
43 /** @protected array アプリケーションディレクトリ(デフォルト) */
44 protected $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 /** @protected array DBアクセス定義 */
65 protected $db = array(
69 /** @protected array 拡張子設定 */
70 protected $ext = array(
75 /** @protected array クラス設定 */
76 protected $class = array();
78 /** @protected array クラス設定(デフォルト) */
79 protected $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 /** @protected array フィルタ設定 */
97 protected $filter = array(
100 /** @protected string 使用ロケール設定 */
103 /** @protected string システム側エンコーディング */
104 protected $system_encoding;
106 /** @protected string クライアント側エンコーディング */
107 /** ブラウザからのエンコーディングを指す */
108 protected $client_encoding;
110 /** @protected string 現在実行中のアクション名 */
111 protected $action_name;
113 /** @protected string 現在実行中のXMLRPCメソッド名 */
114 protected $xmlrpc_method_name;
116 /** @protected array forward定義 */
117 protected $forward = array();
119 /** @protected array デフォルトのforward定義 */
120 protected $forward_default = array(
121 '403' => array( 'view_name' => 'Ethna_View_403',),
122 '404' => array( 'view_name' => 'Ethna_View_404',),
123 '500' => array( 'view_name' => 'Ethna_View_500',),
124 'json' => array( 'view_name' => 'Ethna_View_Json',),
125 'redirect' => array( 'view_name' => 'Ethna_View_Redirect',),
128 /** @protected array action定義 */
129 protected $action = array();
131 /** @protected array action(CLI)定義 */
132 protected $action_cli = array();
134 /** @protected array action(XMLRPC)定義 */
135 protected $action_xmlrpc = array();
137 /** @protected array アプリケーションマネージャ定義 */
138 protected $manager = array();
140 /** @protected object レンダラー */
141 protected $renderer = null;
143 /** @protected array フィルターチェイン(Ethna_Filterオブジェクトの配列) */
144 protected $filter_chain = array();
146 /** @protected object Ethna_ClassFactory クラスファクトリオブジェクト */
147 protected $class_factory = null;
149 /** @protected object Ethna_ActionForm フォームオブジェクト */
150 protected $action_form = null;
152 /** @protected object Ethna_View ビューオブジェクト */
153 protected $view = null;
155 /** @protected object Ethna_Config 設定オブジェクト */
156 protected $config = null;
158 /** @protected object Ethna_Logger ログオブジェクト */
159 protected $logger = null;
161 /** @protected object Ethna_Plugin プラグインオブジェクト */
162 protected $plugin = null;
164 /** @protected string リクエストのゲートウェイ(www/cli/rest/xmlrpc/soap...) */
165 protected $gateway = GATEWAY_WWW;
171 * Ethna_Controllerクラスのコンストラクタ
175 public function __construct($gateway = GATEWAY_WWW)
177 $GLOBALS['_Ethna_controller'] = $this;
178 if ($this->base === "") {
179 // EthnaコマンドなどでBASEが定義されていない場合がある
180 if (defined('BASE')) {
185 $this->gateway = $gateway;
188 foreach ($this->class_default as $key => $val) {
189 if (isset($this->class[$key]) == false) {
190 $this->class[$key] = $val;
195 foreach ($this->directory_default as $key => $val) {
196 if (isset($this->directory[$key]) == false) {
197 $this->directory[$key] = $val;
202 $class_factory = $this->class['class'];
203 $this->class_factory = new $class_factory($this, $this->class);
206 Ethna::setErrorCallback(array(&$this, 'handleError'));
208 // ディレクトリ名の設定(相対パス->絶対パス)
209 foreach ($this->directory as $key => $value) {
210 if ($key == 'plugins') {
211 // Smartyプラグインディレクトリは配列で指定する
213 foreach (to_array($value) as $elt) {
214 if (Ethna_Util::isAbsolute($elt) == false) {
215 $tmp[] = $this->base . (empty($this->base) ? '' : '/') . $elt;
218 $this->directory[$key] = $tmp;
220 if (Ethna_Util::isAbsolute($value) == false) {
221 $this->directory[$key] = $this->base . (empty($this->base) ? '' : '/') . $value;
228 $this->forward = $this->forward + $this->forward_default;
231 // フレームワークとしての内部エンコーディングはクライアント
232 // エンコーディング(=ブラウザからのエンコーディング)
234 // @see Ethna_Controller#_getDefaultLanguage
235 list($this->locale, $this->system_encoding, $this->client_encoding) = $this->_getDefaultLanguage();
237 mb_internal_encoding($this->client_encoding);
238 mb_regex_encoding($this->client_encoding);
240 $this->config = $this->getConfig();
241 $this->dsn = $this->_prepareDSN();
242 $this->url = $this->config->get('url');
245 $this->plugin = $this->getPlugin();
247 // include Ethna_Plugin_Abstract for all plugins
248 $this->plugin->includePlugin('Abstract');
250 //// assert (experimental)
251 //if ($this->config->get('debug') === false) {
252 // ini_set('assert.active', 0);
256 $this->logger = $this->getLogger();
257 $this->plugin->setLogger($this->logger);
258 $this->logger->begin();
261 $this->_activateEthnaManager();
265 * アプリケーション実行後の後始末を行います。
271 // 必要に応じてオーバライドして下さい。
272 $this->logger->end();
276 * (現在アクティブな)コントローラのインスタンスを返す
279 * @return object Ethna_Controller コントローラのインスタンス
282 public static function getInstance()
284 if (isset($GLOBALS['_Ethna_controller'])) {
285 return $GLOBALS['_Ethna_controller'];
296 * @return string アプリケーションID
300 return ucfirst(strtolower($this->appid));
307 * @param string $id アプリケーションID
308 * @return mixed true:OK Ethna_Error:NG
311 public static function checkAppId($id)
314 if (strcasecmp($id, 'ethna') === 0
315 || strcasecmp($id, 'app') === 0) {
316 return Ethna::raiseError("Application Id [$id] is reserved\n");
319 // アプリケーションIDはクラス名のprefixともなるため、
321 // @see http://www.php.net/manual/en/language.variables.php
322 if (preg_match('/^[a-zA-Z][a-zA-Z0-9]*$/', $id) === 0) {
323 $msg = (preg_match('/^[0-9]$/', $id[0]))
324 ? "Application ID must NOT start with Number.\n"
325 : "Only Numeric(0-9) and Alphabetical(A-Z) is allowed for Application Id\n";
326 return Ethna::raiseError($msg);
335 * @param string $action_name アクション名
336 * @return mixed true:OK Ethna_Error:NG
339 public static function checkActionName($action_name)
342 if (preg_match('/^[a-zA-Z\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/',
343 $action_name) === 0) {
344 return Ethna::raiseError("invalid action name [$action_name]");
353 * @param string $view_name ビュー名
354 * @return mixed true:OK Ethna_Error:NG
357 public static function checkViewName($view_name)
360 if (preg_match('/^[a-zA-Z\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/',
362 return Ethna::raiseError("invalid view name [$view_name]");
371 * @param string $db_key DBキー
374 function getDSN($db_key = "")
376 if (isset($this->dsn[$db_key]) == false) {
379 return $this->dsn[$db_key];
386 * @param string $db_key DBキー
387 * @return bool true:persistent false:non-persistent(あるいは設定無し)
389 function getDSN_persistent($db_key = "")
391 $key = sprintf("dsn%s_persistent", $db_key == "" ? "" : "_$db_key");
393 $dsn_persistent = $this->config->get($key);
394 if (is_null($dsn_persistent)) {
397 return $dsn_persistent;
404 * @param string $db_key DBキー("", "r", "rw", "default", "blog_r"...)
405 * @return string $db_keyに対応するDB種別定義(設定が無い場合はnull)
407 function getDBType($db_key = null)
409 if (is_null($db_key)) {
414 if (isset($this->db[$db_key]) == false) {
417 return $this->db[$db_key];
424 * @return string アプリケーションベースURL
432 * アプリケーションベースディレクトリを返す
435 * @return string アプリケーションベースディレクトリ
437 function getBasedir()
443 * クライアントタイプ/言語からテンプレートディレクトリ名を決定する
444 * デフォルトでは [appid]/template/ja_JP/ (ja_JPはロケール名)
445 * ロケール名は _getDefaultLanguage で決定される。
448 * @return string テンプレートディレクトリ
449 * @see Ethna_Controller#_getDefaultLanguage
451 function getTemplatedir()
453 $template = $this->getDirectory('template');
456 // _getDerfaultLanguageメソッドでロケールが指定されていた場合は、
457 // テンプレートディレクトリにも自動的にそれを付加する。
458 if (!empty($this->locale)) {
459 $template .= '/' . $this->locale;
469 * @return string アクションディレクトリ
471 function getActiondir($gateway = null)
474 $gateway = is_null($gateway) ? $this->getGateway() : $gateway;
483 $key = 'action_xmlrpc';
487 return (empty($this->directory[$key]) ? ($this->base . (empty($this->base) ? '' : '/')) : ($this->directory[$key] . "/"));
494 * @return string ビューディレクトリ
496 function getViewdir()
498 return (empty($this->directory['view']) ? ($this->base . (empty($this->base) ? '' : '/')) : ($this->directory['view'] . "/"));
502 * (action,view以外の)テストケースを置くディレクトリ名を決定する
505 * @return string テストケースを置くディレクトリ
507 function getTestdir()
509 return (empty($this->directory['test']) ? ($this->base . (empty($this->base) ? '' : '/')) : ($this->directory['test'] . "/"));
513 * アプリケーションディレクトリ設定を返す
516 * @param string $key ディレクトリタイプ("tmp", "template"...)
517 * @return string $keyに対応したアプリケーションディレクトリ(設定が無い場合はnull)
519 function getDirectory($key)
521 if (isset($this->directory[$key]) == false) {
524 return $this->directory[$key];
531 * @param string $key 拡張子タイプ("php", "tpl"...)
532 * @return string $keyに対応した拡張子(設定が無い場合はnull)
534 function getExt($key)
536 if (isset($this->ext[$key]) == false) {
539 return $this->ext[$key];
543 * クラスファクトリオブジェクトのアクセサ(R)
546 * @return object Ethna_ClassFactory クラスファクトリオブジェクト
548 function getClassFactory()
550 return $this->class_factory;
554 * アクションエラーオブジェクトのアクセサ
557 * @return object Ethna_ActionError アクションエラーオブジェクト
559 function getActionError()
561 return $this->class_factory->getObject('error');
565 * アクションフォームオブジェクトのアクセサ
568 * @return object Ethna_ActionForm アクションフォームオブジェクト
570 function getActionForm()
572 // 明示的にクラスファクトリを利用していない
573 return $this->action_form;
580 * @return object Ethna_View ビューオブジェクト
584 // 明示的にクラスファクトリを利用していない
592 * @return object Ethna_Backend backendオブジェクト
594 function getBackend()
596 return $this->class_factory->getObject('backend');
603 * @return object Ethna_Config 設定オブジェクト
607 return $this->class_factory->getObject('config');
614 * @return object Ethna_I18N i18nオブジェクト
618 return $this->class_factory->getObject('i18n');
625 * @return object Ethna_Logger ログオブジェクト
629 return $this->class_factory->getObject('logger');
636 * @return object Ethna_Session セッションオブジェクト
638 function getSession()
640 return $this->class_factory->getObject('session');
647 * @return object Ethna_AppSQL SQLオブジェクト
651 return $this->class_factory->getObject('sql');
658 * @return object Ethna_Plugin プラグインオブジェクト
662 return $this->class_factory->getObject('plugin');
669 * @return object Ethna_UrlHandler URLハンドラオブジェクト
671 function getUrlHandler()
673 return $this->class_factory->getObject('url_handler');
680 * @return array マネージャ一覧
683 function getManagerList()
685 return $this->manager;
692 * @return string 実行中のアクション名
694 function getCurrentActionName()
696 return $this->action_name;
703 * @return string 実行中のXMLRPCメソッド名
705 function getXmlrpcMethodName()
707 return $this->xmlrpc_method_name;
714 * @return array ロケール名(e.x ja_JP, en_US 等),
716 * クライアントエンコーディング名 の配列
717 * (ロケール名は、ll_cc の形式。ll = 言語コード cc = 国コード)
718 * @see http://www.gnu.org/software/gettext/manual/html_node/Locale-Names.html
720 function getLanguage()
722 return array($this->locale, $this->system_encoding, $this->client_encoding);
729 * @return string ロケール名(e.x ja_JP, en_US 等),
730 * (ロケール名は、ll_cc の形式。ll = 言語コード cc = 国コード)
734 return $this->locale;
741 * @param $locale ロケール名(e.x ja_JP, en_US 等),
742 * (ロケール名は、ll_cc の形式。ll = 言語コード cc = 国コード)
744 function setLocale($locale)
746 $this->locale = $locale;
747 $i18n = $this->getI18N();
748 $i18n->setLanguage($this->locale, $this->system_encoding, $this->client_encoding);
752 * クライアントエンコーディング名へのアクセサ(R)
755 * @return string $client_encoding クライアントエンコーディング名
757 function getClientEncoding()
759 return $this->client_encoding;
763 * クライアントエンコーディング名へのアクセサ(W)
766 * @param string $client_encoding クライアントエンコーディング名
768 function setClientEncoding($client_encoding)
770 $this->client_encoding = $client_encoding;
771 $i18n = $this->getI18N();
772 $i18n->setLanguage($this->locale, $this->system_encoding, $this->client_encoding);
780 function getGateway()
782 return $this->gateway;
790 function setGateway($gateway)
792 $this->gateway = $gateway;
799 * @param string $class_name アプリケーションコントローラのクラス名
800 * @param mixed $action_name 指定のアクション名(省略可)
801 * @param mixed $fallback_action_name アクションが決定できなかった場合に実行されるアクション名(省略可)
804 public static function main($class_name, $action_name = "", $fallback_action_name = "")
806 $c = new $class_name;
807 $c->trigger($action_name, $fallback_action_name);
812 * CLIアプリケーションのエントリポイント
815 * @param string $class_name アプリケーションコントローラのクラス名
816 * @param string $action_name 実行するアクション名
817 * @param bool $enable_filter フィルタチェインを有効にするかどうか
820 public static function main_CLI($class_name, $action_name, $enable_filter = true)
822 $c = new $class_name(GATEWAY_CLI);
823 $c->action_cli[$action_name] = array();
824 $c->trigger($action_name, "", $enable_filter);
829 * XMLRPCアプリケーションのエントリポイント
834 public static function main_XMLRPC($class_name)
836 if (extension_loaded('xmlrpc') == false) {
837 die("xmlrpc extension is required to enable this gateway");
840 $c = new $class_name(GATEWAY_XMLRPC);
841 $c->trigger("", "", false);
846 * SOAPアプリケーションのエントリポイント
849 * @param string $class_name アプリケーションコントローラのクラス名
850 * @param mixed $action_name 指定のアクション名(省略可)
851 * @param mixed $fallback_action_name アクションが決定できなかった場合に実行されるアクション名(省略可)
854 public static function main_SOAP($class_name, $action_name = "", $fallback_action_name = "")
856 $c = new $class_name(GATEWAY_SOAP);
857 $c->trigger($action_name, $fallback_action_name);
865 * @param mixed $default_action_name 指定のアクション名
866 * @param mixed $fallback_action_name アクション名が決定できなかった場合に実行されるアクション名
867 * @param bool $enable_filter フィルタチェインを有効にするかどうか
868 * @return mixed 0:正常終了 Ethna_Error:エラー
870 function trigger($default_action_name = "", $fallback_action_name = "", $enable_filter = true)
873 if ($enable_filter) {
874 $this->_createFilterChain();
878 for ($i = 0; $i < count($this->filter_chain); $i++) {
879 $r = $this->filter_chain[$i]->preFilter();
880 if (Ethna::isError($r)) {
886 switch ($this->getGateway()) {
888 $this->_trigger_WWW($default_action_name, $fallback_action_name);
891 $this->_trigger_CLI($default_action_name);
894 $this->_trigger_XMLRPC();
897 $this->_trigger_SOAP();
902 for ($i = count($this->filter_chain) - 1; $i >= 0; $i--) {
903 $r = $this->filter_chain[$i]->postFilter();
904 if (Ethna::isError($r)) {
911 * フレームワークの処理を実行する(WWW)
913 * 引数$default_action_nameに配列が指定された場合、その配列で指定された
914 * アクション以外は受け付けない(指定されていないアクションが指定された
915 * 場合、配列の先頭で指定されたアクションが実行される)
918 * @param mixed $default_action_name 指定のアクション名
919 * @param mixed $fallback_action_name アクション名が決定できなかった場合に実行されるアクション名
920 * @return mixed 0:正常終了 Ethna_Error:エラー
922 function _trigger_WWW($default_action_name = "", $fallback_action_name = "")
925 $action_name = $this->_getActionName($default_action_name, $fallback_action_name);
928 $this->_ethnaManagerEnabledCheck($action_name);
931 $action_obj = $this->_getAction($action_name);
932 if (is_null($action_obj)) {
933 if ($fallback_action_name != "") {
934 $this->logger->log(LOG_DEBUG, 'undefined action [%s] -> try fallback action [%s]', $action_name, $fallback_action_name);
935 $action_obj = $this->_getAction($fallback_action_name);
937 if (is_null($action_obj)) {
938 return Ethna::raiseError("undefined action [%s]", E_APP_UNDEFINED_ACTION, $action_name);
940 $action_name = $fallback_action_name;
945 for ($i = 0; $i < count($this->filter_chain); $i++) {
946 $r = $this->filter_chain[$i]->preActionFilter($action_name);
948 $this->logger->log(LOG_DEBUG, 'action [%s] -> [%s] by %s', $action_name, $r, get_class($this->filter_chain[$i]));
952 $this->action_name = $action_name;
955 $backend = $this->getBackend();
956 $session = $this->getSession();
960 $this->_setLanguage($this->locale, $this->system_encoding, $this->client_encoding);
964 $form_name = $this->getActionFormName($action_name);
965 $this->action_form = new $form_name($this);
966 $this->action_form->setFormDef_PreHelper();
967 $this->action_form->setFormVars();
968 $backend->setActionForm($this->action_form);
971 $forward_name = $backend->perform($action_name);
974 for ($i = count($this->filter_chain) - 1; $i >= 0; $i--) {
975 $r = $this->filter_chain[$i]->postActionFilter($action_name, $forward_name);
977 $this->logger->log(LOG_DEBUG, 'forward [%s] -> [%s] by %s', $forward_name, $r, get_class($this->filter_chain[$i]));
982 // コントローラで遷移先を決定する(オプション)
983 $forward_name_params = $this->_sortForward($action_name, $forward_name);
986 $preforward_params = array();
987 if (is_array($forward_name_params)) {
988 $forward_name = array_shift($forward_name_params);
989 $preforward_params = $forward_name_params;
992 $forward_name = $forward_name_params;
995 if ($forward_name != null) {
996 $view_class_name = $this->getViewClassName($forward_name);
997 $this->view = new $view_class_name($backend, $forward_name, $this->_getForwardPath($forward_name));
998 call_user_func_array(array($this->view, 'preforward'), $preforward_params);
999 $this->view->forward();
1006 * フレームワークの処理を実行する(CLI)
1009 * @param mixed $default_action_name 指定のアクション名
1010 * @return mixed 0:正常終了 Ethna_Error:エラー
1012 function _trigger_CLI($default_action_name = "")
1014 return $this->_trigger_WWW($default_action_name);
1018 * フレームワークの処理を実行する(XMLRPC)
1021 * @param mixed $action_name 指定のアクション名
1022 * @return mixed 0:正常終了 Ethna_Error:エラー
1024 function _trigger_XMLRPC($action_name = "")
1026 // prepare xmlrpc server
1027 $xmlrpc_gateway_method_name = "_Ethna_XmlrpcGateway";
1028 $xmlrpc_server = xmlrpc_server_create();
1031 $param = xmlrpc_decode_request(file_get_contents('php://input'), $method);
1032 $this->xmlrpc_method_name = $method;
1034 $request = xmlrpc_encode_request(
1035 $xmlrpc_gateway_method_name,
1038 'output_type' => 'xml',
1039 'verbosity' => 'pretty',
1040 'escaping' => array('markup'),
1041 'version' => 'xmlrpc',
1042 'encoding' => 'utf-8'
1046 xmlrpc_server_register_method(
1048 $xmlrpc_gateway_method_name,
1049 $xmlrpc_gateway_method_name
1053 $r = xmlrpc_server_call_method(
1058 'output_type' => 'xml',
1059 'verbosity' => 'pretty',
1060 'escaping' => array('markup'),
1061 'version' => 'xmlrpc',
1062 'encoding' => 'utf-8'
1066 header('Content-Length: ' . strlen($r));
1067 header('Content-Type: text/xml; charset=UTF-8');
1072 * _trigger_XMLRPCのコールバックメソッド
1076 function trigger_XMLRPC($method, $param)
1079 $action_obj = $this->_getAction($method);
1080 if (is_null($action_obj)) {
1081 return Ethna::raiseError("undefined xmlrpc method [%s]", E_APP_UNDEFINED_ACTION, $method);
1085 $backend = $this->getBackend();
1087 $form_name = $this->getActionFormName($method);
1088 $this->action_form = new $form_name($this);
1089 $def = $this->action_form->getDef();
1091 foreach ($def as $key => $value) {
1092 if (isset($param[$n]) == false) {
1093 $this->action_form->set($key, null);
1095 $this->action_form->set($key, $param[$n]);
1101 $backend->setActionForm($this->action_form);
1103 $session = $this->getSession();
1104 $session->restore();
1105 $r = $backend->perform($method);
1111 * SOAPフレームワークの処理を実行する
1115 function _trigger_SOAP()
1118 $gg = new Ethna_SOAP_GatewayGenerator();
1119 $script = $gg->generate();
1123 $server = new SoapServer(null, array('uri' => $this->config->get('url')));
1124 $server->setClass($gg->getClassName());
1131 * エラー発生時の追加処理を行いたい場合はこのメソッドをオーバーライドする
1132 * (アラートメール送信等−デフォルトではログ出力時にアラートメール
1133 * が送信されるが、エラー発生時に別にアラートメールをここで送信
1137 * @param object Ethna_Error エラーオブジェクト
1139 function handleError(&$error)
1142 list ($log_level, $dummy) = $this->logger->errorLevelToLogLevel($error->getLevel());
1143 $message = $error->getMessage();
1144 $this->logger->log($log_level, sprintf("%s [ERROR CODE(%d)]", $message, $error->getCode()));
1151 * @param int $code エラーコード
1152 * @return string エラーメッセージ
1154 function getErrorMessage($code)
1156 $message_list = $GLOBALS['_Ethna_error_message_list'];
1157 for ($i = count($message_list)-1; $i >= 0; $i--) {
1158 if (array_key_exists($code, $message_list[$i])) {
1159 return $message_list[$i][$code];
1169 * @param mixed $default_action_name 指定のアクション名
1170 * @return string 実行するアクション名
1172 function _getActionName($default_action_name, $fallback_action_name)
1174 // フォームから要求されたアクション名を取得する
1175 $form_action_name = $this->_getActionName_Form();
1176 $form_action_name = preg_replace('/[^a-z0-9\-_]+/i', '', $form_action_name);
1177 $this->logger->log(LOG_DEBUG, 'form_action_name[%s]', $form_action_name);
1179 // Ethnaマネージャへのフォームからのリクエストは拒否
1180 if ($form_action_name == "__ethna_info__" ||
1181 $form_action_name == "__ethna_unittest__") {
1182 $form_action_name = "";
1185 // フォームからの指定が無い場合はエントリポイントに指定されたデフォルト値を利用する
1186 if ($form_action_name == "" && count($default_action_name) > 0) {
1187 $tmp = is_array($default_action_name) ? $default_action_name[0] : $default_action_name;
1188 if ($tmp{strlen($tmp)-1} == '*') {
1189 $tmp = substr($tmp, 0, -1);
1191 $this->logger->log(LOG_DEBUG, '-> default_action_name[%s]', $tmp);
1192 $action_name = $tmp;
1194 $action_name = $form_action_name;
1197 // エントリポイントに配列が指定されている場合は指定以外のアクション名は拒否する
1198 if (is_array($default_action_name)) {
1199 if ($this->_isAcceptableActionName($action_name, $default_action_name) == false) {
1200 // 指定以外のアクション名で合った場合は$fallback_action_name(or デフォルト)
1201 $tmp = $fallback_action_name != "" ? $fallback_action_name : $default_action_name[0];
1202 if ($tmp{strlen($tmp)-1} == '*') {
1203 $tmp = substr($tmp, 0, -1);
1205 $this->logger->log(LOG_DEBUG, '-> fallback_action_name[%s]', $tmp);
1206 $action_name = $tmp;
1210 $this->logger->log(LOG_DEBUG, '<<< action_name[%s] >>>', $action_name);
1212 return $action_name;
1216 * フォームにより要求されたアクション名を返す
1218 * アプリケーションの性質に応じてこのメソッドをオーバーライドして下さい。
1219 * デフォルトでは"action_"で始まるフォーム値の"action_"の部分を除いたもの
1220 * ("action_sample"なら"sample")がアクション名として扱われます
1223 * @return string フォームにより要求されたアクション名
1225 function _getActionName_Form()
1227 if (isset($_SERVER['REQUEST_METHOD']) == false) {
1231 $url_handler = $this->getUrlHandler();
1232 if ($_SERVER['REQUEST_METHOD'] == "GET") {
1234 } else if ($_SERVER['REQUEST_METHOD'] == "POST") {
1238 if (empty($_SERVER['URL_HANDLER']) == false) {
1239 $tmp_vars['__url_handler__'] = $_SERVER['URL_HANDLER'];
1240 $tmp_vars['__url_info__'] = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : null;
1241 $tmp_vars = $url_handler->requestToAction($tmp_vars);
1243 if ($_SERVER['REQUEST_METHOD'] == "GET") {
1244 $_GET = array_merge($_GET, $tmp_vars);
1245 } else if ($_SERVER['REQUEST_METHOD'] == "POST") {
1246 $_POST = array_merge($_POST, $tmp_vars);
1248 $_REQUEST = array_merge($_REQUEST, $tmp_vars);
1251 if (strcasecmp($_SERVER['REQUEST_METHOD'], 'post') == 0) {
1252 $http_vars = $_POST;
1257 // フォーム値からリクエストされたアクション名を取得する
1258 $action_name = $sub_action_name = null;
1259 foreach ($http_vars as $name => $value) {
1260 if ($value == "" || strncmp($name, 'action_', 7) != 0) {
1264 $tmp = substr($name, 7);
1267 if (preg_match('/_x$/', $name) || preg_match('/_y$/', $name)) {
1268 $tmp = substr($tmp, 0, strlen($tmp)-2);
1271 // value="dummy"となっているものは優先度を下げる
1272 if ($value == "dummy") {
1273 $sub_action_name = $tmp;
1275 $action_name = $tmp;
1278 if ($action_name == null) {
1279 $action_name = $sub_action_name;
1282 return $action_name;
1286 * アクション名を指定するクエリ/HTMLを生成する
1289 * @param string $action action to request
1290 * @param string $type hidden, url...
1291 * @todo consider gateway
1293 function getActionRequest($action, $type = "hidden")
1296 if ($type == "hidden") {
1297 $s = sprintf('<input type="hidden" name="action_%s" value="true" />', htmlspecialchars($action, ENT_QUOTES));
1298 } else if ($type == "url") {
1299 $s = sprintf('action_%s=true', urlencode($action));
1305 * フォームにより要求されたアクション名に対応する定義を返す
1308 * @param string $action_name アクション名
1309 * @return array アクション定義
1311 function _getAction($action_name, $gateway = null)
1314 $gateway = is_null($gateway) ? $this->getGateway() : $gateway;
1317 $action = $this->action;
1320 $action = $this->action_cli;
1322 case GATEWAY_XMLRPC:
1323 $action = $this->action_xmlrpc;
1327 $action_obj = array();
1328 if (isset($action[$action_name])) {
1329 $action_obj = $action[$action_name];
1330 if (isset($action_obj['inspect']) && $action_obj['inspect']) {
1334 $this->logger->log(LOG_DEBUG, "action [%s] is not defined -> try default", $action_name);
1337 // アクションスクリプトのインクルード
1338 $this->_includeActionScript($action_obj, $action_name);
1341 if (isset($action_obj['class_name']) == false) {
1342 $action_obj['class_name'] = $this->getDefaultActionClass($action_name);
1345 if (isset($action_obj['form_name']) == false) {
1346 $action_obj['form_name'] = $this->getDefaultFormClass($action_name);
1347 } else if (class_exists($action_obj['form_name']) == false) {
1348 // 明示指定されたフォームクラスが定義されていない場合は警告
1349 $this->logger->log(LOG_WARNING, 'stated form class is not defined [%s]', $action_obj['form_name']);
1353 if (class_exists($action_obj['class_name']) == false) {
1354 $this->logger->log(LOG_NOTICE, 'action class is not defined [%s]', $action_obj['class_name']);
1355 $_ret_object = null;
1356 return $_ret_object;
1358 if (class_exists($action_obj['form_name']) == false) {
1360 $class_name = $this->class_factory->getObjectName('form');
1361 $this->logger->log(LOG_DEBUG, 'form class is not defined [%s] -> falling back to default [%s]', $action_obj['form_name'], $class_name);
1362 $action_obj['form_name'] = $class_name;
1365 $action_obj['inspect'] = true;
1366 $action[$action_name] = $action_obj;
1367 return $action[$action_name];
1371 * アクション名とアクションクラスからの戻り値に基づいて遷移先を決定する
1374 * @param string $action_name アクション名
1375 * @param string $retval アクションクラスからの戻り値
1376 * @return string 遷移先
1378 function _sortForward($action_name, $retval)
1388 function _createFilterChain()
1390 $this->filter_chain = array();
1391 foreach ($this->filter as $filter) {
1392 $filter_plugin = $this->plugin->getPlugin('Filter', $filter);
1393 if (Ethna::isError($filter_plugin)) {
1397 $this->filter_chain[] = $filter_plugin;
1402 * アクション名が実行許可されているものかどうかを返す
1405 * @param string $action_name リクエストされたアクション名
1406 * @param array $default_action_name 許可されているアクション名
1407 * @return bool true:許可 false:不許可
1409 function _isAcceptableActionName($action_name, $default_action_name)
1411 foreach (to_array($default_action_name) as $name) {
1412 if ($action_name == $name) {
1414 } else if ($name{strlen($name)-1} == '*') {
1415 if (strncmp($action_name, substr($name, 0, -1), strlen($name)-1) == 0) {
1424 * 指定されたアクションのフォームクラス名を返す(オブジェクトの生成は行わない)
1427 * @param string $action_name アクション名
1428 * @return string アクションのフォームクラス名
1430 function getActionFormName($action_name)
1432 $action_obj = $this->_getAction($action_name);
1433 if (is_null($action_obj)) {
1437 return $action_obj['form_name'];
1441 * アクションに対応するフォームクラス名が省略された場合のデフォルトクラス名を返す
1443 * デフォルトでは[プロジェクトID]_Form_[アクション名]となるので好み応じてオーバライドする
1446 * @param string $action_name アクション名
1447 * @return string アクションフォーム名
1449 function getDefaultFormClass($action_name, $gateway = null)
1451 $gateway_prefix = $this->_getGatewayPrefix($gateway);
1453 $postfix = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($action_name));
1454 $r = sprintf("%s_%sForm_%s", $this->getAppId(), $gateway_prefix ? $gateway_prefix . "_" : "", $postfix);
1455 $this->logger->log(LOG_DEBUG, "default action class [%s]", $r);
1461 * getDefaultFormClass()で取得したクラス名からアクション名を取得する
1463 * getDefaultFormClass()をオーバーライドした場合、こちらも合わせてオーバーライド
1467 * @param string $class_name フォームクラス名
1468 * @return string アクション名
1470 function actionFormToName($class_name)
1472 $prefix = sprintf("%s_Form_", $this->getAppId());
1473 if (preg_match("/$prefix(.*)/", $class_name, $match) == 0) {
1477 $target = $match[1];
1479 $action_name = substr(preg_replace('/([A-Z])/e', "'_' . strtolower('\$1')", $target), 1);
1481 return $action_name;
1485 * アクションに対応するフォームパス名が省略された場合のデフォルトパス名を返す
1487 * デフォルトでは_getDefaultActionPath()と同じ結果を返す(1ファイルに
1488 * アクションクラスとフォームクラスが記述される)ので、好みに応じて
1492 * @param string $action_name アクション名
1493 * @return string form classが定義されるスクリプトのパス名
1495 function getDefaultFormPath($action_name)
1497 return $this->getDefaultActionPath($action_name);
1501 * 指定されたアクションのクラス名を返す(オブジェクトの生成は行わない)
1504 * @param string $action_name アクションの名称
1505 * @return string アクションのクラス名
1507 function getActionClassName($action_name)
1509 $action_obj = $this->_getAction($action_name);
1510 if ($action_obj == null) {
1514 return $action_obj['class_name'];
1518 * アクションに対応するアクションクラス名が省略された場合のデフォルトクラス名を返す
1520 * デフォルトでは[プロジェクトID]_Action_[アクション名]となるので好み応じてオーバライドする
1523 * @param string $action_name アクション名
1524 * @return string アクションクラス名
1526 function getDefaultActionClass($action_name, $gateway = null)
1528 $gateway_prefix = $this->_getGatewayPrefix($gateway);
1530 $postfix = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($action_name));
1531 $r = sprintf("%s_%sAction_%s", $this->getAppId(), $gateway_prefix ? $gateway_prefix . "_" : "", $postfix);
1532 $this->logger->log(LOG_DEBUG, "default action class [%s]", $r);
1538 * getDefaultActionClass()で取得したクラス名からアクション名を取得する
1540 * getDefaultActionClass()をオーバーライドした場合、こちらも合わせてオーバーライド
1544 * @param string $class_name アクションクラス名
1545 * @return string アクション名
1547 function actionClassToName($class_name)
1549 $prefix = sprintf("%s_Action_", $this->getAppId());
1550 if (preg_match("/$prefix(.*)/", $class_name, $match) == 0) {
1554 $target = $match[1];
1556 $action_name = substr(preg_replace('/([A-Z])/e', "'_' . strtolower('\$1')", $target), 1);
1558 return $action_name;
1562 * アクションに対応するアクションパス名が省略された場合のデフォルトパス名を返す
1564 * デフォルトでは"foo_bar" -> "/Foo/Bar.php"となるので好み応じてオーバーライドする
1567 * @param string $action_name アクション名
1568 * @return string アクションクラスが定義されるスクリプトのパス名
1570 function getDefaultActionPath($action_name)
1572 $r = preg_replace('/_(.)/e', "'/' . strtoupper('\$1')", ucfirst($action_name)) . '.' . $this->getExt('php');
1573 $this->logger->log(LOG_DEBUG, "default action path [%s]", $r);
1579 * 指定された遷移名に対応するビュークラス名を返す(オブジェクトの生成は行わない)
1582 * @param string $forward_name 遷移先の名称
1583 * @return string view classのクラス名
1585 function getViewClassName($forward_name)
1587 if ($forward_name == null) {
1591 if (isset($this->forward[$forward_name])) {
1592 $forward_obj = $this->forward[$forward_name];
1594 $forward_obj = array();
1597 if (isset($forward_obj['view_name'])) {
1598 $class_name = $forward_obj['view_name'];
1599 if (class_exists($class_name)) {
1607 $this->_includeViewScript($forward_obj, $forward_name);
1609 if (is_null($class_name) == false && class_exists($class_name)) {
1611 } else if (is_null($class_name) == false) {
1612 $this->logger->log(LOG_WARNING, 'stated view class is not defined [%s] -> try default', $class_name);
1615 $class_name = $this->getDefaultViewClass($forward_name);
1616 if (class_exists($class_name)) {
1619 $class_name = $this->class_factory->getObjectName('view');
1620 $this->logger->log(LOG_DEBUG, 'view class is not defined for [%s] -> use default [%s]', $forward_name, $class_name);
1626 * 遷移名に対応するビュークラス名が省略された場合のデフォルトクラス名を返す
1628 * デフォルトでは[プロジェクトID]_View_[遷移名]となるので好み応じてオーバライドする
1631 * @param string $forward_name forward名
1632 * @return string view classクラス名
1634 function getDefaultViewClass($forward_name, $gateway = null)
1636 $gateway_prefix = $this->_getGatewayPrefix($gateway);
1638 $postfix = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($forward_name));
1639 $r = sprintf("%s_%sView_%s", $this->getAppId(), $gateway_prefix ? $gateway_prefix . "_" : "", $postfix);
1640 $this->logger->log(LOG_DEBUG, "default view class [%s]", $r);
1646 * 遷移名に対応するビューパス名が省略された場合のデフォルトパス名を返す
1648 * デフォルトでは"foo_bar" -> "/Foo/Bar.php"となるので好み応じてオーバーライドする
1651 * @param string $forward_name forward名
1652 * @return string view classが定義されるスクリプトのパス名
1654 function getDefaultViewPath($forward_name)
1656 $r = preg_replace('/_(.)/e', "'/' . strtoupper('\$1')", ucfirst($forward_name)) . '.' . $this->getExt('php');
1657 $this->logger->log(LOG_DEBUG, "default view path [%s]", $r);
1663 * 遷移名に対応するテンプレートパス名が省略された場合のデフォルトパス名を返す
1665 * デフォルトでは"foo_bar"というforward名が"foo/bar" + テンプレート拡張子となる
1669 * @param string $forward_name forward名
1670 * @return string forwardパス名
1672 function getDefaultForwardPath($forward_name)
1674 return str_replace('_', '/', $forward_name) . '.' . $this->ext['tpl'];
1678 * テンプレートパス名から遷移名を取得する
1680 * getDefaultForwardPath()をオーバーライドした場合、こちらも合わせてオーバーライド
1684 * @param string $forward_path テンプレートパス名
1685 * @return string 遷移名
1687 function forwardPathToName($forward_path)
1689 $forward_path = preg_replace('/^\/+/', '', $forward_path);
1690 $forward_path = preg_replace(sprintf('/\.%s$/', $this->getExt('tpl')), '', $forward_path);
1692 return str_replace('/', '_', $forward_path);
1696 * 遷移名からテンプレートファイルのパス名を取得する
1699 * @param string $forward_name forward名
1700 * @return string テンプレートファイルのパス名
1702 function _getForwardPath($forward_name)
1704 $forward_obj = null;
1706 if (isset($this->forward[$forward_name]) == false) {
1708 $this->forward[$forward_name] = array();
1710 $forward_obj = $this->forward[$forward_name];
1711 if (isset($forward_obj['forward_path']) == false) {
1713 $forward_obj['forward_path'] = $this->getDefaultForwardPath($forward_name);
1716 return $forward_obj['forward_path'];
1720 * レンダラを取得する(getTemplateEngine()はそのうち廃止されgetRenderer()に統合される予定)
1723 * @return object Ethna_Renderer レンダラオブジェクト
1725 public function getRenderer()
1727 $_ret_object = $this->getTemplateEngine();
1728 return $_ret_object;
1735 * @return object Ethna_Renderer レンダラオブジェクト
1738 public function getTemplateEngine()
1740 if (is_object($this->renderer)) {
1741 return $this->renderer;
1744 $this->renderer = $this->class_factory->getObject('renderer');
1746 //テンプレートエンジンのデフォルトの設定
1747 $this->_setDefaultTemplateEngine($this->renderer);
1750 return $this->renderer;
1754 * テンプレートエンジンのデフォルト状態を設定する
1757 * @param object Ethna_Renderer レンダラオブジェクト
1760 protected function _setDefaultTemplateEngine($renderer)
1766 * 条件によって使用言語、ロケールを切り替えたい場合は、
1770 * @param string $locale ロケール名(ja_JP, en_US等)
1771 * (ll_cc の形式。ll = 言語コード cc = 国コード)
1772 * @param string $system_encoding システムエンコーディング名
1773 * @param string $client_encoding クライアントエンコーディング(テンプレートのエンコーディングと考えれば良い)
1774 * @see http://www.gnu.org/software/gettext/manual/html_node/Locale-Names.html
1775 * @see Ethna_Controller#_getDefaultLanguage
1777 protected function _setLanguage($locale, $system_encoding = null, $client_encoding = null)
1779 $this->locale = $locale;
1780 $this->system_encoding = $system_encoding;
1781 $this->client_encoding = $client_encoding;
1783 // $this->locale, $this->client_encoding を書き換えた場合は
1784 // 必ず Ethna_I18N クラスの setLanguageメソッドも呼ぶこと!
1785 // さもないとカタログその他が再ロードされない!
1786 $i18n = $this->getI18N();
1787 $i18n->setLanguage($locale, $system_encoding, $client_encoding);
1791 * デフォルト状態での使用言語を取得する
1792 * 外部に出力されるEthnaのエラーメッセージ等のエンコーディングを
1793 * 切り替えたい場合は、このメソッドをオーバーライドする。
1796 * @return array ロケール名(e.x ja_JP, en_US 等),
1799 * (= テンプレートのエンコーディングと考えてよい) の配列
1800 * (ロケール名は ll_cc の形式。ll = 言語コード cc = 国コード)
1802 * WARNING!! : クライアントエンコーディング名が、フレームワークの内部エンコーデ
1803 * ィングとして設定されます。つまり、クライアントエンコーディングで
1804 * ブラウザからの入力は入ってくるものと想定しています!
1806 protected function _getDefaultLanguage()
1808 return array('ja_JP', 'UTF-8', 'UTF-8');
1812 * デフォルト状態でのゲートウェイを取得する
1815 * @return int ゲートウェイ定義(GATEWAY_WWW, GATEWAY_CLI...)
1817 protected function _getDefaultGateway($gateway)
1819 if (is_null($GLOBALS['_Ethna_gateway']) == false) {
1820 return $GLOBALS['_Ethna_gateway'];
1826 * ゲートウェイに対応したクラス名のプレフィクスを取得する
1829 * @param string $gateway ゲートウェイ
1830 * @return string ゲートウェイクラスプレフィクス
1832 protected function _getGatewayPrefix($gateway = null)
1834 $gateway = is_null($gateway) ? $this->getGateway() : $gateway;
1842 case GATEWAY_XMLRPC:
1857 * @param string $name マネージャキー
1858 * @return string マネージャクラス名
1860 public function getManagerClassName($name)
1862 // アプリケーションIDと、渡された名前のはじめを大文字にして、
1864 $manager_id = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($name));
1865 return sprintf('%s_%sManager', $this->getAppId(), ucfirst($manager_id));
1869 * アプリケーションオブジェクトクラス名を取得する
1872 * @param string $name アプリケーションオブジェクトキー
1873 * @return string マネージャクラス名
1875 public function getObjectClassName($name)
1877 // 引数のはじめの一文字目と、アンダーバー直後の
1878 // 1文字を必ず大文字にする。アンダーバーは削除される。
1879 $name = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($name));
1881 // $name に foo_bar を渡し、AppID が Hogeの場合
1882 // [Appid]_FooBar が返される
1883 return sprintf('%s_%s', $this->getAppId(), $name);
1887 * アクションスクリプトをインクルードする
1889 * ただし、インクルードしたファイルにクラスが正しく定義されているかどうかは保証しない
1892 * @param array $action_obj アクション定義
1893 * @param string $action_name アクション名
1895 protected function _includeActionScript($action_obj, $action_name)
1897 $class_path = $form_path = null;
1899 $action_dir = $this->getActiondir();
1902 if (isset($action_obj['class_path'])) {
1904 $tmp_path = $action_obj['class_path'];
1905 if (Ethna_Util::isAbsolute($tmp_path) == false) {
1906 $tmp_path = $action_dir . $tmp_path;
1909 if (file_exists($tmp_path) == false) {
1910 $this->logger->log(LOG_WARNING, 'class_path file not found [%s] -> try default', $tmp_path);
1912 include_once $tmp_path;
1913 $class_path = $tmp_path;
1918 if (is_null($class_path)) {
1919 $class_path = $this->getDefaultActionPath($action_name);
1920 if (file_exists($action_dir . $class_path)) {
1921 include_once $action_dir . $class_path;
1923 $this->logger->log(LOG_DEBUG, 'default action file not found [%s] -> try all files', $class_path);
1929 if (isset($action_obj['form_path'])) {
1931 $tmp_path = $action_obj['form_path'];
1932 if (Ethna_Util::isAbsolute($tmp_path) == false) {
1933 $tmp_path = $action_dir . $tmp_path;
1936 if ($tmp_path == $class_path) {
1939 if (file_exists($tmp_path) == false) {
1940 $this->logger->log(LOG_WARNING, 'form_path file not found [%s] -> try default', $tmp_path);
1942 include_once $tmp_path;
1943 $form_path = $tmp_path;
1948 if (is_null($form_path)) {
1949 $form_path = $this->getDefaultFormPath($action_name);
1950 if ($form_path == $class_path) {
1953 if (file_exists($action_dir . $form_path)) {
1954 include_once $action_dir . $form_path;
1956 $this->logger->log(LOG_DEBUG, 'default form file not found [%s] -> maybe falling back to default form class', $form_path);
1964 * ただし、インクルードしたファイルにクラスが正しく定義されているかどうかは保証しない
1967 * @param array $forward_obj 遷移定義
1968 * @param string $forward_name 遷移名
1970 protected function _includeViewScript($forward_obj, $forward_name)
1972 $view_dir = $this->getViewdir();
1975 if (isset($forward_obj['view_path'])) {
1977 $tmp_path = $forward_obj['view_path'];
1978 if (Ethna_Util::isAbsolute($tmp_path) == false) {
1979 $tmp_path = $view_dir . $tmp_path;
1982 if (file_exists($tmp_path) == false) {
1983 $this->logger->log(LOG_WARNING, 'view_path file not found [%s] -> try default', $tmp_path);
1985 include_once $tmp_path;
1991 $view_path = $this->getDefaultViewPath($forward_name);
1992 if (file_exists($view_dir . $view_path)) {
1993 include_once $view_dir . $view_path;
1996 $this->logger->log(LOG_DEBUG, 'default view file not found [%s]', $view_path);
2002 * ディレクトリ以下の全てのスクリプトをインクルードする
2006 protected function _includeDirectory($dir)
2008 $ext = "." . $this->ext['php'];
2009 $ext_len = strlen($ext);
2011 if (is_dir($dir) == false) {
2015 $dh = opendir($dir);
2017 while (($file = readdir($dh)) !== false) {
2018 if ($file != '.' && $file != '..' && is_dir("$dir/$file")) {
2019 $this->_includeDirectory("$dir/$file");
2021 if (substr($file, -$ext_len, $ext_len) != $ext) {
2024 include_once $dir . '/' . $file;
2031 * 設定ファイルのDSN定義から使用するデータを再構築する(スレーブアクセス分岐等)
2033 * DSNの定義方法(デフォルト:設定ファイル)を変えたい場合はここをオーバーライドする
2036 * @return array DSN定義(array('DBキー1' => 'dsn1', 'DBキー2' => 'dsn2', ...))
2038 protected function _prepareDSN()
2042 foreach ($this->db as $key => $value) {
2043 $config_key = "dsn";
2045 $config_key .= "_$key";
2047 $dsn = $this->config->get($config_key);
2048 if (is_array($dsn)) {
2049 // 種別1つにつき複数DSNが定義されている場合はアクセス分岐
2050 $dsn = $this->_selectDSN($key, $dsn);
2060 * スレーブサーバへの振分け処理(デフォルト:ランダム)を変更したい場合はこのメソッドをオーバーライドする
2063 * @param string $type DB種別
2064 * @param array $dsn_list DSN一覧
2065 * @return string 選択されたDSN
2067 protected function _selectDSN($type, $dsn_list)
2069 if (is_array($dsn_list) == false) {
2074 list($usec, $sec) = explode(' ', microtime());
2075 mt_srand($sec + ((float) $usec * 100000));
2076 $n = mt_rand(0, count($dsn_list)-1);
2078 return $dsn_list[$n];
2084 * 不要な場合は空のメソッドとしてオーバーライドしてもよい
2088 protected function _activateEthnaManager()
2090 if ($this->config->get('debug') == false) {
2094 require_once ETHNA_BASE . '/class/InfoManager.php';
2096 // see if we have simpletest
2097 if (file_exists_ex('simpletest/unit_tester.php', true)) {
2098 require_once ETHNA_BASE . '/class/UnitTestManager.php';
2102 $this->action['__ethna_info__'] = array(
2103 'form_name' => 'Ethna_Form_Info',
2104 'form_path' => sprintf('%s/class/Action/Info.php', ETHNA_BASE),
2105 'class_name' => 'Ethna_Action_Info',
2106 'class_path' => sprintf('%s/class/Action/Info.php', ETHNA_BASE),
2110 $this->forward['__ethna_info__'] = array(
2111 'forward_path' => sprintf('%s/tpl/info.tpl', ETHNA_BASE),
2112 'view_name' => 'Ethna_View_Info',
2113 'view_path' => sprintf('%s/class/View/Info.php', ETHNA_BASE),
2118 $this->action['__ethna_unittest__'] = array(
2119 'form_name' => 'Ethna_Form_UnitTest',
2120 'form_path' => sprintf('%s/class/Action/UnitTest.php', ETHNA_BASE),
2121 'class_name' => 'Ethna_Action_UnitTest',
2122 'class_path' => sprintf('%s/class/Action/UnitTest.php', ETHNA_BASE),
2126 $this->forward['__ethna_unittest__'] = array(
2127 'forward_path' => sprintf('%s/tpl/unittest.tpl', ETHNA_BASE),
2128 'view_name' => 'Ethna_View_UnitTest',
2129 'view_path' => sprintf('%s/class/View/UnitTest.php', ETHNA_BASE),
2135 * Ethnaマネージャが実行可能かをチェックする
2137 * Ethnaマネージャを実行するよう指示されているにも関わらず、
2138 * debug が trueでない場合は実行を停止する。
2142 protected function _ethnaManagerEnabledCheck($action_name)
2144 if ($this->config->get('debug') == false
2145 && ($action_name == '__ethna_info__' || $action_name == '__ethna_unittest__')) {
2146 $this->ethnaManagerCheckErrorMsg($action_name);
2152 * Ethnaマネージャが実行不能な場合のエラーメッセージを
2153 * 表示する。運用上の都合でこのメッセージを出力したくない
2154 * 場合は、このメソッドをオーバーライドせよ
2158 protected function ethnaManagerCheckErrorMsg($action_name)
2160 $appid = strtolower($this->getAppId());
2161 $run_action = ($action_name == '__ethna_info__')
2162 ? ' show Application Info List '
2163 : ' run Unit Test ';
2164 echo "Ethna cannot {$run_action} under your application setting.<br>";
2165 echo "HINT: You must set {$appid}/etc/{$appid}-ini.php debug setting 'true'.<br>";
2167 echo "In {$appid}-ini.php, please set as follows :<br><br>";
2168 echo "\$config = array ( 'debug' => true, );";
2175 * @return bool CLI実行中フラグ
2178 public function getCLI()
2180 return $this->gateway == GATEWAY_CLI ? true : false;
2187 * @param bool CLI実行中フラグ
2190 public function setCLI($cli)
2192 $this->gateway = $cli ? GATEWAY_CLI : $this->_getDefaultGateway();
2198 * XMLRPCゲートウェイのスタブクラス
2202 function _Ethna_XmlrpcGateway($method_stub, $param)
2204 $ctl = Ethna_Controller::getInstance();
2205 $method = $ctl->getXmlrpcMethodName();
2206 $r = $ctl->trigger_XMLRPC($method, $param);
2207 if (Ethna::isError($r)) {
2209 'faultCode' => $r->getCode(),
2210 'faultString' => $r->getMessage(),