OSDN Git Service

bd9929f774e84feffa6ffc4a09a1bf7f9f0ab07c
[ethna/ethna.git] / class / Ethna_Controller.php
1 <?php
2 // vim: foldmethod=marker
3 /**
4  *  Ethna_Controller.php
5  *
6  *  @author     Masaki Fujimoto <fujimoto@php.net>
7  *  @license    http://www.opensource.org/licenses/bsd-license.php The BSD License
8  *  @package    Ethna
9  *  @version    $Id$
10  */
11
12 // {{{ Ethna_Controller
13 /**
14  *  コントローラクラス
15  *
16  *  @todo       gatewayでswitchしてるところがダサダサ
17  *
18  *  @author     Masaki Fujimoto <fujimoto@php.net>
19  *  @access     public
20  *  @package    Ethna
21  */
22 class Ethna_Controller
23 {
24     /**#@+
25      *  @access private
26      */
27
28     /** @var    string      アプリケーションID */
29     var $appid = 'ETHNA';
30
31     /** @var    string      アプリケーションベースディレクトリ */
32     var $base = '';
33
34     /** @var    string      アプリケーションベースURL */
35     var $url = '';
36
37     /** @var    string      アプリケーションDSN(Data Source Name) */
38     var $dsn;
39
40     /** @var    array       アプリケーションディレクトリ */
41     var $directory = array();
42
43     /** @var    array       アプリケーションディレクトリ(デフォルト) */
44     var $directory_default = array(
45         'action'        => 'app/action',
46         'action_cli'    => 'app/action_cli',
47         'action_xmlrpc' => 'app/action_xmlrpc',
48         'app'           => 'app',
49         'plugin'        => 'app/plugin',
50         'bin'           => 'bin',
51         'etc'           => 'etc',
52         'filter'        => 'app/filter',
53         'locale'        => 'locale',
54         'log'           => 'log',
55         'plugins'       => array(),
56         'template'      => 'template',
57         'template_c'    => 'tmp',
58         'tmp'           => 'tmp',
59         'view'          => 'app/view',
60         'www'           => 'www',
61         'test'          => 'app/test',
62     );
63
64     /** @var    array       DBアクセス定義 */
65     var $db = array(
66         ''              => DB_TYPE_RW,
67     );
68
69     /** @var    array       拡張子設定 */
70     var $ext = array(
71         'php'           => 'php',
72         'tpl'           => 'tpl',
73     );
74
75     /** @var    array       クラス設定 */
76     var $class = array();
77
78     /** @var    array       クラス設定(デフォルト) */
79     var $class_default = array(
80         'class'         => 'Ethna_ClassFactory',
81         'backend'       => 'Ethna_Backend',
82         'config'        => 'Ethna_Config',
83         'db'            => 'Ethna_DB',
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',
94     );
95
96     /** @var    array       フィルタ設定 */
97     var $filter = array(
98     );
99
100     /** @var    string      使用ロケール設定 */
101     var $locale;
102
103     /** @var    string      システム側エンコーディング */
104     var $system_encoding;
105
106     /** @var    string      クライアント側エンコーディング */
107     /**                     ブラウザからのエンコーディングを指す  */
108     var $client_encoding;
109
110     /** @var    string  現在実行中のアクション名 */
111     var $action_name;
112
113     /** @var    string  現在実行中のXMLRPCメソッド名 */
114     var $xmlrpc_method_name;
115
116     /** @var    array   forward定義 */
117     var $forward = array();
118
119     /** @var    array   デフォルトのforward定義 */
120     var $forward_default = array(
121         '404' => array( 'view_name' => 'Ethna_View_404',),
122         '500' => array( 'view_name' => 'Ethna_View_500',), 
123         'json' => array( 'view_name' => 'Ethna_View_Json',),
124         'redirect' => array( 'view_name' => 'Ethna_View_Redirect',),
125     );
126
127     /** @var    array   action定義 */
128     var $action = array();
129
130     /** @var    array   action(CLI)定義 */
131     var $action_cli = array();
132
133     /** @var    array   action(XMLRPC)定義 */
134     var $action_xmlrpc = array();
135
136     /** @var    array   アプリケーションマネージャ定義 */
137     var $manager = array();
138
139     /** @var    object  レンダラー */
140     var $renderer = null;
141
142     /** @var    array   フィルターチェイン(Ethna_Filterオブジェクトの配列) */
143     var $filter_chain = array();
144
145     /** @var    object  Ethna_ClassFactory  クラスファクトリオブジェクト */
146     var $class_factory = null;
147
148     /** @var    object  Ethna_ActionForm    フォームオブジェクト */
149     var $action_form = null;
150
151     /** @var    object  Ethna_View          ビューオブジェクト */
152     var $view = null;
153
154     /** @var    object  Ethna_Config        設定オブジェクト */
155     var $config = null;
156
157     /** @var    object  Ethna_Logger        ログオブジェクト */
158     var $logger = null;
159
160     /** @var    object  Ethna_Plugin        プラグインオブジェクト */
161     var $plugin = null;
162
163     /** @var    string  リクエストのゲートウェイ(www/cli/rest/xmlrpc/soap...) */
164     var $gateway = GATEWAY_WWW;
165
166     /**#@-*/
167
168
169     /**
170      *  Ethna_Controllerクラスのコンストラクタ
171      *
172      *  @access     public
173      */
174     function Ethna_Controller($gateway = GATEWAY_WWW)
175     {
176         $GLOBALS['_Ethna_controller'] =& $this;
177         if ($this->base === "") {
178             // EthnaコマンドなどでBASEが定義されていない場合がある
179             if (defined('BASE')) {
180                 $this->base = BASE;
181             }
182         }
183
184         $this->gateway = $gateway;
185
186         // クラス設定の未定義値を補完
187         foreach ($this->class_default as $key => $val) {
188             if (isset($this->class[$key]) == false) {
189                 $this->class[$key] = $val;
190             }
191         }
192
193         // ディレクトリ設定の未定義値を補完
194         foreach ($this->directory_default as $key => $val) {
195             if (isset($this->directory[$key]) == false) {
196                 $this->directory[$key] = $val;
197             }
198         }
199
200         // クラスファクトリオブジェクトの生成
201         $class_factory = $this->class['class'];
202         $this->class_factory =& new $class_factory($this, $this->class);
203
204         // エラーハンドラの設定
205         Ethna::setErrorCallback(array(&$this, 'handleError'));
206
207         // ディレクトリ名の設定(相対パス->絶対パス)
208         foreach ($this->directory as $key => $value) {
209             if ($key == 'plugins') {
210                 // Smartyプラグインディレクトリは配列で指定する
211                 $tmp = array();
212                 foreach (to_array($value) as $elt) {
213                     if (Ethna_Util::isAbsolute($elt) == false) {
214                         $tmp[] = $this->base . (empty($this->base) ? '' : '/') . $elt;
215                     }
216                 }
217                 $this->directory[$key] = $tmp;
218             } else {
219                 if (Ethna_Util::isAbsolute($value) == false) {
220                     $this->directory[$key] = $this->base . (empty($this->base) ? '' : '/') . $value;
221                 }
222             }
223         }
224
225         // 遷移先設定をマージ
226         // 但し、キーは完全に維持する
227         $this->forward = $this->forward + $this->forward_default;
228
229         // 初期設定
230         // フレームワークとしての内部エンコーディングはクライアント
231         // エンコーディング(=ブラウザからのエンコーディング)
232         //
233         // @see Ethna_Controller#_getDefaultLanguage
234         list($this->locale, $this->system_encoding, $this->client_encoding) = $this->_getDefaultLanguage();
235         if (mb_enabled()) {
236             mb_internal_encoding($this->client_encoding);
237             mb_regex_encoding($this->client_encoding);
238         }
239         $this->config =& $this->getConfig();
240         $this->dsn = $this->_prepareDSN();
241         $this->url = $this->config->get('url');
242
243         // プラグインオブジェクトの用意
244         $this->plugin =& $this->getPlugin();
245
246         //// assert (experimental)
247         //if ($this->config->get('debug') === false) {
248         //    ini_set('assert.active', 0);
249         //}
250
251         // ログ出力開始
252         $this->logger =& $this->getLogger();
253         $this->plugin->setLogger($this->logger);
254         $this->logger->begin();
255
256         // Ethnaマネージャ設定
257         $this->_activateEthnaManager();
258     }
259
260     /**
261      *  アプリケーション実行後の後始末を行います。
262      *
263      *  @access protected
264      */
265     function end()
266     {
267         //  必要に応じてオーバライドして下さい。
268         $this->logger->end();
269     }
270
271     /**
272      *  (現在アクティブな)コントローラのインスタンスを返す
273      *
274      *  @access public
275      *  @return object  Ethna_Controller    コントローラのインスタンス
276      *  @static
277      */
278     function &getInstance()
279     {
280         if (isset($GLOBALS['_Ethna_controller'])) {
281             return $GLOBALS['_Ethna_controller'];
282         } else {
283             $_ret_object = null;
284             return $_ret_object;
285         }
286     }
287
288     /**
289      *  アプリケーションIDを返す
290      *
291      *  @access public
292      *  @return string  アプリケーションID
293      */
294     function getAppId()
295     {
296         return ucfirst(strtolower($this->appid));
297     }
298
299     /**
300      *  アプリケーションIDをチェックする
301      *
302      *  @access public
303      *  @param  string  $id     アプリケーションID
304      *  @return mixed   true:OK Ethna_Error:NG
305      *  @static
306      */
307     function &checkAppId($id)
308     {
309         $true = true;
310         if (strcasecmp($id, 'ethna') === 0
311             || strcasecmp($id, 'app') === 0) {
312             return Ethna::raiseError("Application Id [$id] is reserved\n");
313         }
314
315         //    アプリケーションIDはクラス名のprefixともなるため、
316         //    数字で始まっていてはいけない
317         //    @see http://www.php.net/manual/en/language.variables.php
318         if (preg_match('/^[a-zA-Z][a-zA-Z0-9]*$/', $id) === 0) {
319             $msg = (preg_match('/^[0-9]$/', $id[0]))
320                  ? "Application ID must NOT start with Number.\n"
321                  : "Only Numeric(0-9) and Alphabetical(A-Z) is allowed for Application Id\n";
322             return Ethna::raiseError($msg);
323         }
324         return $true;
325     }
326
327     /**
328      *  アクション名をチェックする
329      *
330      *  @access public
331      *  @param  string  $action_name    アクション名
332      *  @return mixed   true:OK Ethna_Error:NG
333      *  @static
334      */
335     function &checkActionName($action_name)
336     {
337         $true = true;
338         if (preg_match('/^[a-zA-Z\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/',
339                        $action_name) === 0) {
340             return Ethna::raiseError("invalid action name [$action_name]");
341         }
342         return $true;
343     }
344
345     /**
346      *  ビュー名をチェックする
347      *
348      *  @access public
349      *  @param  string  $view_name    ビュー名
350      *  @return mixed   true:OK Ethna_Error:NG
351      *  @static
352      */
353     function &checkViewName($view_name)
354     {
355         $true = true;
356         if (preg_match('/^[a-zA-Z\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/',
357                        $view_name) === 0) {
358             return Ethna::raiseError("invalid view name [$view_name]");
359         }
360         return $true;
361     }
362
363     /**
364      *  DSNを返す
365      *
366      *  @access public
367      *  @param  string  $db_key DBキー
368      *  @return string  DSN
369      */
370     function getDSN($db_key = "")
371     {
372         if (isset($this->dsn[$db_key]) == false) {
373             return null;
374         }
375         return $this->dsn[$db_key];
376     }
377
378     /**
379      *  DSNの持続接続設定を返す
380      *
381      *  @access public
382      *  @param  string  $db_key DBキー
383      *  @return bool    true:persistent false:non-persistent(あるいは設定無し)
384      */
385     function getDSN_persistent($db_key = "")
386     {
387         $key = sprintf("dsn%s_persistent", $db_key == "" ? "" : "_$db_key");
388
389         $dsn_persistent = $this->config->get($key);
390         if (is_null($dsn_persistent)) {
391             return false;
392         }
393         return $dsn_persistent;
394     }
395
396     /**
397      *  DB設定を返す
398      *
399      *  @access public
400      *  @param  string  $db_key DBキー("", "r", "rw", "default", "blog_r"...)
401      *  @return string  $db_keyに対応するDB種別定義(設定が無い場合はnull)
402      */
403     function getDBType($db_key = null)
404     {
405         if (is_null($db_key)) {
406             // 一覧を返す
407             return $this->db;
408         }
409
410         if (isset($this->db[$db_key]) == false) {
411             return null;
412         }
413         return $this->db[$db_key];
414     }
415
416     /**
417      *  アプリケーションベースURLを返す
418      *
419      *  @access public
420      *  @return string  アプリケーションベースURL
421      */
422     function getURL()
423     {
424         return $this->url;
425     }
426
427     /**
428      *  アプリケーションベースディレクトリを返す
429      *
430      *  @access public
431      *  @return string  アプリケーションベースディレクトリ
432      */
433     function getBasedir()
434     {
435         return $this->base;
436     }
437
438     /**
439      *  クライアントタイプ/言語からテンプレートディレクトリ名を決定する
440      *  デフォルトでは [appid]/template/ja_JP/ (ja_JPはロケール名)
441      *  ロケール名は _getDefaultLanguage で決定される。
442      *
443      *  @access public
444      *  @return string  テンプレートディレクトリ
445      *  @see    Ethna_Controller#_getDefaultLanguage
446      */
447     function getTemplatedir()
448     {
449         $template = $this->getDirectory('template');
450
451         // 言語別ディレクトリ
452         // _getDerfaultLanguageメソッドでロケールが指定されていた場合は、
453         // テンプレートディレクトリにも自動的にそれを付加する。
454         if (!empty($this->locale)) {
455             $template .= '/' . $this->locale;
456         }
457
458         return $template;
459     }
460
461     /**
462      *  アクションディレクトリ名を決定する
463      *
464      *  @access public
465      *  @return string  アクションディレクトリ
466      */
467     function getActiondir($gateway = null)
468     {
469         $key = 'action';
470         $gateway = is_null($gateway) ? $this->getGateway() : $gateway;
471         switch ($gateway) {
472         case GATEWAY_WWW:
473             $key = 'action';
474             break;
475         case GATEWAY_CLI:
476             $key = 'action_cli';
477             break;
478         case GATEWAY_XMLRPC:
479             $key = 'action_xmlrpc';
480             break;
481         }
482
483         return (empty($this->directory[$key]) ? ($this->base . (empty($this->base) ? '' : '/')) : ($this->directory[$key] . "/"));
484     }
485
486     /**
487      *  ビューディレクトリ名を決定する
488      *
489      *  @access public
490      *  @return string  ビューディレクトリ
491      */
492     function getViewdir()
493     {
494         return (empty($this->directory['view']) ? ($this->base . (empty($this->base) ? '' : '/')) : ($this->directory['view'] . "/"));
495     }
496
497     /**
498      *  (action,view以外の)テストケースを置くディレクトリ名を決定する
499      *
500      *  @access public
501      *  @return string  テストケースを置くディレクトリ
502      */
503     function getTestdir()
504     {
505         return (empty($this->directory['test']) ? ($this->base . (empty($this->base) ? '' : '/')) : ($this->directory['test'] . "/"));
506     }
507
508     /**
509      *  アプリケーションディレクトリ設定を返す
510      *
511      *  @access public
512      *  @param  string  $key    ディレクトリタイプ("tmp", "template"...)
513      *  @return string  $keyに対応したアプリケーションディレクトリ(設定が無い場合はnull)
514      */
515     function getDirectory($key)
516     {
517         if (isset($this->directory[$key]) == false) {
518             return null;
519         }
520         return $this->directory[$key];
521     }
522
523     /**
524      *  アプリケーション拡張子設定を返す
525      *
526      *  @access public
527      *  @param  string  $key    拡張子タイプ("php", "tpl"...)
528      *  @return string  $keyに対応した拡張子(設定が無い場合はnull)
529      */
530     function getExt($key)
531     {
532         if (isset($this->ext[$key]) == false) {
533             return null;
534         }
535         return $this->ext[$key];
536     }
537
538     /**
539      *  クラスファクトリオブジェクトのアクセサ(R)
540      *
541      *  @access public
542      *  @return object  Ethna_ClassFactory  クラスファクトリオブジェクト
543      */
544     function &getClassFactory()
545     {
546         return $this->class_factory;
547     }
548
549     /**
550      *  アクションエラーオブジェクトのアクセサ
551      *
552      *  @access public
553      *  @return object  Ethna_ActionError   アクションエラーオブジェクト
554      */
555     function &getActionError()
556     {
557         return $this->class_factory->getObject('error');
558     }
559
560     /**
561      *  アクションフォームオブジェクトのアクセサ
562      *
563      *  @access public
564      *  @return object  Ethna_ActionForm    アクションフォームオブジェクト
565      */
566     function &getActionForm()
567     {
568         // 明示的にクラスファクトリを利用していない
569         return $this->action_form;
570     }
571
572     /**
573      *  ビューオブジェクトのアクセサ
574      *
575      *  @access public
576      *  @return object  Ethna_View          ビューオブジェクト
577      */
578     function &getView()
579     {
580         // 明示的にクラスファクトリを利用していない
581         return $this->view;
582     }
583
584     /**
585      *  backendオブジェクトのアクセサ
586      *
587      *  @access public
588      *  @return object  Ethna_Backend   backendオブジェクト
589      */
590     function &getBackend()
591     {
592         return $this->class_factory->getObject('backend');
593     }
594
595     /**
596      *  設定オブジェクトのアクセサ
597      *
598      *  @access public
599      *  @return object  Ethna_Config    設定オブジェクト
600      */
601     function &getConfig()
602     {
603         return $this->class_factory->getObject('config');
604     }
605
606     /**
607      *  i18nオブジェクトのアクセサ(R)
608      *
609      *  @access public
610      *  @return object  Ethna_I18N  i18nオブジェクト
611      */
612     function &getI18N()
613     {
614         return $this->class_factory->getObject('i18n');
615     }
616
617     /**
618      *  ログオブジェクトのアクセサ
619      *
620      *  @access public
621      *  @return object  Ethna_Logger        ログオブジェクト
622      */
623     function &getLogger()
624     {
625         return $this->class_factory->getObject('logger');
626     }
627
628     /**
629      *  セッションオブジェクトのアクセサ
630      *
631      *  @access public
632      *  @return object  Ethna_Session       セッションオブジェクト
633      */
634     function &getSession()
635     {
636         return $this->class_factory->getObject('session');
637     }
638
639     /**
640      *  SQLオブジェクトのアクセサ
641      *
642      *  @access public
643      *  @return object  Ethna_AppSQL    SQLオブジェクト
644      */
645     function &getSQL()
646     {
647         return $this->class_factory->getObject('sql');
648     }
649
650     /**
651      *  プラグインオブジェクトのアクセサ
652      *
653      *  @access public
654      *  @return object  Ethna_Plugin    プラグインオブジェクト
655      */
656     function &getPlugin()
657     {
658         return $this->class_factory->getObject('plugin');
659     }
660
661     /**
662      *  URLハンドラオブジェクトのアクセサ
663      *
664      *  @access public
665      *  @return object  Ethna_UrlHandler    URLハンドラオブジェクト
666      */
667     function &getUrlHandler()
668     {
669         return $this->class_factory->getObject('url_handler');
670     }
671
672     /**
673      *  マネージャ一覧を返す
674      *
675      *  @access public
676      *  @return array   マネージャ一覧
677      *  @obsolete
678      */
679     function getManagerList()
680     {
681         return $this->manager;
682     }
683
684     /**
685      *  実行中のアクション名を返す
686      *
687      *  @access public
688      *  @return string  実行中のアクション名
689      */
690     function getCurrentActionName()
691     {
692         return $this->action_name;
693     }
694
695     /**
696      *  実行中のXMLRPCメソッド名を返す
697      *
698      *  @access public
699      *  @return string  実行中のXMLRPCメソッド名
700      */
701     function getXmlrpcMethodName()
702     {
703         return $this->xmlrpc_method_name;
704     }
705
706     /**
707      *  ロケール設定、使用言語を取得する
708      *
709      *  @access public
710      *  @return array   ロケール名(e.x ja_JP, en_US 等),
711      *                  システムエンコーディング名,
712      *                  クライアントエンコーディング名 の配列
713      *                  (ロケール名は、ll_cc の形式。ll = 言語コード cc = 国コード)
714      *  @see http://www.gnu.org/software/gettext/manual/html_node/Locale-Names.html
715      */
716     function getLanguage()
717     {
718         return array($this->locale, $this->system_encoding, $this->client_encoding);
719     }
720
721     /**
722      *  ロケール名へのアクセサ(R)
723      *
724      *  @access public
725      *  @return string  ロケール名(e.x ja_JP, en_US 等),
726      *                  (ロケール名は、ll_cc の形式。ll = 言語コード cc = 国コード)
727      */
728     function getLocale()
729     {
730         return $this->locale;
731     }
732
733     /**
734      *  ロケール名へのアクセサ(W)
735      *
736      *  @access public
737      *  @param $locale ロケール名(e.x ja_JP, en_US 等),
738      *                 (ロケール名は、ll_cc の形式。ll = 言語コード cc = 国コード)
739      */
740     function setLocale($locale)
741     {
742         $this->locale = $locale;
743         $i18n =& $this->getI18N();
744         $i18n->setLanguage($this->locale, $this->system_encoding, $this->client_encoding);
745     }
746
747     /**
748      *  クライアントエンコーディング名へのアクセサ(R)
749      *
750      *  @access public
751      *  @return string  $client_encoding クライアントエンコーディング名
752      */
753     function getClientEncoding()
754     {
755         return $this->client_encoding;
756     }
757
758     /**
759      *  クライアントエンコーディング名へのアクセサ(W)
760      *
761      *  @access public
762      *  @param  string  $client_encoding クライアントエンコーディング名
763      */
764     function setClientEncoding($client_encoding)
765     {
766         $this->client_encoding = $client_encoding;
767         $i18n =& $this->getI18N();
768         $i18n->setLanguage($this->locale, $this->system_encoding, $this->client_encoding);
769     }
770
771     /**
772      *  ゲートウェイを取得する
773      *
774      *  @access public
775      */
776     function getGateway()
777     {
778         return $this->gateway;
779     }
780
781     /**
782      *  ゲートウェイモードを設定する
783      *
784      *  @access public
785      */
786     function setGateway($gateway)
787     {
788         $this->gateway = $gateway;
789     }
790
791     /**
792      *  アプリケーションのエントリポイント
793      *
794      *  @access public
795      *  @param  string  $class_name     アプリケーションコントローラのクラス名
796      *  @param  mixed   $action_name    指定のアクション名(省略可)
797      *  @param  mixed   $fallback_action_name   アクションが決定できなかった場合に実行されるアクション名(省略可)
798      *  @static
799      */
800     function main($class_name, $action_name = "", $fallback_action_name = "")
801     {
802         $c =& new $class_name;
803         $c->trigger($action_name, $fallback_action_name);
804         $c->end();
805     }
806
807     /**
808      *  CLIアプリケーションのエントリポイント
809      *
810      *  @access public
811      *  @param  string  $class_name     アプリケーションコントローラのクラス名
812      *  @param  string  $action_name    実行するアクション名
813      *  @param  bool    $enable_filter  フィルタチェインを有効にするかどうか
814      *  @static
815      */
816     function main_CLI($class_name, $action_name, $enable_filter = true)
817     {
818         $c =& new $class_name(GATEWAY_CLI);
819         $c->action_cli[$action_name] = array();
820         $c->trigger($action_name, "", $enable_filter);
821         $c->end();
822     }
823
824     /**
825      *  XMLRPCアプリケーションのエントリポイント
826      *
827      *  @access public
828      *  @static
829      */
830     function main_XMLRPC($class_name)
831     {
832         if (extension_loaded('xmlrpc') == false) {
833             die("xmlrpc extension is required to enable this gateway");
834         }
835
836         $c =& new $class_name(GATEWAY_XMLRPC);
837         $c->trigger("", "", false);
838         $c->end();
839     }
840
841     /**
842      *  SOAPアプリケーションのエントリポイント
843      *
844      *  @access public
845      *  @param  string  $class_name     アプリケーションコントローラのクラス名
846      *  @param  mixed   $action_name    指定のアクション名(省略可)
847      *  @param  mixed   $fallback_action_name   アクションが決定できなかった場合に実行されるアクション名(省略可)
848      *  @static
849      */
850     function main_SOAP($class_name, $action_name = "", $fallback_action_name = "")
851     {
852         $c =& new $class_name(GATEWAY_SOAP);
853         $c->trigger($action_name, $fallback_action_name);
854         $c->end();
855     }
856
857     /**
858      *  フレームワークの処理を開始する
859      *
860      *  @access public
861      *  @param  mixed   $default_action_name    指定のアクション名
862      *  @param  mixed   $fallback_action_name   アクション名が決定できなかった場合に実行されるアクション名
863      *  @param  bool    $enable_filter  フィルタチェインを有効にするかどうか
864      *  @return mixed   0:正常終了 Ethna_Error:エラー
865      */
866     function trigger($default_action_name = "", $fallback_action_name = "", $enable_filter = true)
867     {
868         // フィルターの生成
869         if ($enable_filter) {
870             $this->_createFilterChain();
871         }
872
873         // 実行前フィルタ
874         for ($i = 0; $i < count($this->filter_chain); $i++) {
875             $r = $this->filter_chain[$i]->preFilter();
876             if (Ethna::isError($r)) {
877                 return $r;
878             }
879         }
880
881         // trigger
882         switch ($this->getGateway()) {
883         case GATEWAY_WWW:
884             $this->_trigger_WWW($default_action_name, $fallback_action_name);
885             break;
886         case GATEWAY_CLI:
887             $this->_trigger_CLI($default_action_name);
888             break;
889         case GATEWAY_XMLRPC:
890             $this->_trigger_XMLRPC();
891             break;
892         case GATEWAY_SOAP:
893             $this->_trigger_SOAP();
894             break;
895         }
896
897         // 実行後フィルタ
898         for ($i = count($this->filter_chain) - 1; $i >= 0; $i--) {
899             $r = $this->filter_chain[$i]->postFilter();
900             if (Ethna::isError($r)) {
901                 return $r;
902             }
903         }
904     }
905
906     /**
907      *  フレームワークの処理を実行する(WWW)
908      *
909      *  引数$default_action_nameに配列が指定された場合、その配列で指定された
910      *  アクション以外は受け付けない(指定されていないアクションが指定された
911      *  場合、配列の先頭で指定されたアクションが実行される)
912      *
913      *  @access private
914      *  @param  mixed   $default_action_name    指定のアクション名
915      *  @param  mixed   $fallback_action_name   アクション名が決定できなかった場合に実行されるアクション名
916      *  @return mixed   0:正常終了 Ethna_Error:エラー
917      */
918     function _trigger_WWW($default_action_name = "", $fallback_action_name = "")
919     {
920         // アクション名の取得
921         $action_name = $this->_getActionName($default_action_name, $fallback_action_name);
922
923         // マネージャ実行チェック
924         $this->_ethnaManagerEnabledCheck($action_name);
925
926         // アクション定義の取得
927         $action_obj =& $this->_getAction($action_name);
928         if (is_null($action_obj)) {
929             if ($fallback_action_name != "") {
930                 $this->logger->log(LOG_DEBUG, 'undefined action [%s] -> try fallback action [%s]', $action_name, $fallback_action_name);
931                 $action_obj =& $this->_getAction($fallback_action_name);
932             }
933             if (is_null($action_obj)) {
934                 return Ethna::raiseError("undefined action [%s]", E_APP_UNDEFINED_ACTION, $action_name);
935             } else {
936                 $action_name = $fallback_action_name;
937             }
938         }
939
940         // アクション実行前フィルタ
941         for ($i = 0; $i < count($this->filter_chain); $i++) {
942             $r = $this->filter_chain[$i]->preActionFilter($action_name);
943             if ($r != null) {
944                 $this->logger->log(LOG_DEBUG, 'action [%s] -> [%s] by %s', $action_name, $r, get_class($this->filter_chain[$i]));
945                 $action_name = $r;
946             }
947         }
948         $this->action_name = $action_name;
949
950         // オブジェクト生成
951         $backend =& $this->getBackend();
952         $session =& $this->getSession();
953         $session->restore();
954
955         // 言語切り替えフックを呼ぶ
956         $this->_setLanguage($this->locale, $this->system_encoding, $this->client_encoding);
957
958         // アクションフォーム初期化
959         // フォーム定義、フォーム値設定
960         $form_name = $this->getActionFormName($action_name);
961         $this->action_form =& new $form_name($this);
962         $this->action_form->setFormDef_PreHelper();
963         $this->action_form->setFormVars();
964         $backend->setActionForm($this->action_form);
965
966         // バックエンド処理実行
967         $forward_name = $backend->perform($action_name);
968
969         // アクション実行後フィルタ
970         for ($i = count($this->filter_chain) - 1; $i >= 0; $i--) {
971             $r = $this->filter_chain[$i]->postActionFilter($action_name, $forward_name);
972             if ($r != null) {
973                 $this->logger->log(LOG_DEBUG, 'forward [%s] -> [%s] by %s', $forward_name, $r, get_class($this->filter_chain[$i]));
974                 $forward_name = $r;
975             }
976         }
977
978         // コントローラで遷移先を決定する(オプション)
979         $forward_name_params = $this->_sortForward($action_name, $forward_name);
980
981         // Viewへの引数があれば取り出す
982         $preforward_params = array();
983         if (is_array($forward_name_params)) {
984             $forward_name = array_shift($forward_name_params);
985             $preforward_params = $forward_name_params;
986         }
987         else {
988             $forward_name = $forward_name_params;
989         }
990
991         if ($forward_name != null) {
992             $view_class_name = $this->getViewClassName($forward_name);
993             $this->view =& new $view_class_name($backend, $forward_name, $this->_getForwardPath($forward_name));
994             call_user_func_array(array($this->view, 'preforward'), $preforward_params);
995             $this->view->forward();
996         }
997
998         return 0;
999     }
1000
1001     /**
1002      *  フレームワークの処理を実行する(CLI)
1003      *
1004      *  @access private
1005      *  @param  mixed   $default_action_name    指定のアクション名
1006      *  @return mixed   0:正常終了 Ethna_Error:エラー
1007      */
1008     function _trigger_CLI($default_action_name = "")
1009     {
1010         return $this->_trigger_WWW($default_action_name);
1011     }
1012
1013     /**
1014      *  フレームワークの処理を実行する(XMLRPC)
1015      *
1016      *  @access private
1017      *  @param  mixed   $action_name    指定のアクション名
1018      *  @return mixed   0:正常終了 Ethna_Error:エラー
1019      */
1020     function _trigger_XMLRPC($action_name = "")
1021     {
1022         // prepare xmlrpc server
1023         $xmlrpc_gateway_method_name = "_Ethna_XmlrpcGateway";
1024         $xmlrpc_server = xmlrpc_server_create();
1025
1026         $method = null;
1027         $param = xmlrpc_decode_request(file_get_contents('php://input'), $method);
1028         $this->xmlrpc_method_name = $method;
1029
1030         $request = xmlrpc_encode_request(
1031             $xmlrpc_gateway_method_name,
1032             $param,
1033             array(
1034                 'output_type'   => 'xml',
1035                 'verbosity'     => 'pretty',
1036                 'escaping'      => array('markup'),
1037                 'version'       => 'xmlrpc',
1038                 'encoding'      => 'utf-8'
1039             )
1040         );
1041
1042         xmlrpc_server_register_method(
1043             $xmlrpc_server,
1044             $xmlrpc_gateway_method_name,
1045             $xmlrpc_gateway_method_name
1046         );
1047
1048         // send request
1049         $r = xmlrpc_server_call_method(
1050             $xmlrpc_server,
1051             $request,
1052             null,
1053             array(
1054                 'output_type'   => 'xml',
1055                 'verbosity'     => 'pretty',
1056                 'escaping'      => array('markup'),
1057                 'version'       => 'xmlrpc',
1058                 'encoding'      => 'utf-8'
1059             )
1060         );
1061
1062         header('Content-Length: ' . strlen($r));
1063         header('Content-Type: text/xml; charset=UTF-8');
1064         print $r;
1065     }
1066
1067     /**
1068      *  _trigger_XMLRPCのコールバックメソッド
1069      *
1070      *  @access public
1071      */
1072     function trigger_XMLRPC($method, $param)
1073     {
1074         // アクション定義の取得
1075         $action_obj =& $this->_getAction($method);
1076         if (is_null($action_obj)) {
1077             return Ethna::raiseError("undefined xmlrpc method [%s]", E_APP_UNDEFINED_ACTION, $method);
1078         }
1079
1080         // オブジェクト生成
1081         $backend =& $this->getBackend();
1082
1083         $form_name = $this->getActionFormName($method);
1084         $this->action_form =& new $form_name($this);
1085         $def = $this->action_form->getDef();
1086         $n = 0;
1087         foreach ($def as $key => $value) {
1088             if (isset($param[$n]) == false) {
1089                 $this->action_form->set($key, null);
1090             } else {
1091                 $this->action_form->set($key, $param[$n]);
1092             }
1093             $n++;
1094         }
1095
1096         // バックエンド処理実行
1097         $backend->setActionForm($this->action_form);
1098
1099         $session =& $this->getSession();
1100         $session->restore();
1101         $r = $backend->perform($method);
1102
1103         return $r;
1104     }
1105
1106     /**
1107      *  SOAPフレームワークの処理を実行する
1108      *
1109      *  @access private
1110      */
1111     function _trigger_SOAP()
1112     {
1113         // SOAPエントリクラス
1114         $gg =& new Ethna_SOAP_GatewayGenerator();
1115         $script = $gg->generate();
1116         eval($script);
1117
1118         // SOAPリクエスト処理
1119         $server =& new SoapServer(null, array('uri' => $this->config->get('url')));
1120         $server->setClass($gg->getClassName());
1121         $server->handle();
1122     }
1123
1124     /**
1125      *  エラーハンドラ
1126      *
1127      *  エラー発生時の追加処理を行いたい場合はこのメソッドをオーバーライドする
1128      *  (アラートメール送信等−デフォルトではログ出力時にアラートメール
1129      *  が送信されるが、エラー発生時に別にアラートメールをここで送信
1130      *  させることも可能)
1131      *
1132      *  @access public
1133      *  @param  object  Ethna_Error     エラーオブジェクト
1134      */
1135     function handleError(&$error)
1136     {
1137         // ログ出力
1138         list ($log_level, $dummy) = $this->logger->errorLevelToLogLevel($error->getLevel());
1139         $message = $error->getMessage();
1140         $this->logger->log($log_level, sprintf("%s [ERROR CODE(%d)]", $message, $error->getCode()));
1141     }
1142
1143     /**
1144      *  エラーメッセージを取得する
1145      *
1146      *  @access public
1147      *  @param  int     $code       エラーコード
1148      *  @return string  エラーメッセージ
1149      */
1150     function getErrorMessage($code)
1151     {
1152         $message_list =& $GLOBALS['_Ethna_error_message_list'];
1153         for ($i = count($message_list)-1; $i >= 0; $i--) {
1154             if (array_key_exists($code, $message_list[$i])) {
1155                 return $message_list[$i][$code];
1156             }
1157         }
1158         return null;
1159     }
1160
1161     /**
1162      *  実行するアクション名を返す
1163      *
1164      *  @access private
1165      *  @param  mixed   $default_action_name    指定のアクション名
1166      *  @return string  実行するアクション名
1167      */
1168     function _getActionName($default_action_name, $fallback_action_name)
1169     {
1170         // フォームから要求されたアクション名を取得する
1171         $form_action_name = $this->_getActionName_Form();
1172         $form_action_name = preg_replace('/[^a-z0-9\-_]+/i', '', $form_action_name);
1173         $this->logger->log(LOG_DEBUG, 'form_action_name[%s]', $form_action_name);
1174
1175         // Ethnaマネージャへのフォームからのリクエストは拒否
1176         if ($form_action_name == "__ethna_info__" ||
1177             $form_action_name == "__ethna_unittest__") {
1178             $form_action_name = "";
1179         }
1180
1181         // フォームからの指定が無い場合はエントリポイントに指定されたデフォルト値を利用する
1182         if ($form_action_name == "" && count($default_action_name) > 0) {
1183             $tmp = is_array($default_action_name) ? $default_action_name[0] : $default_action_name;
1184             if ($tmp{strlen($tmp)-1} == '*') {
1185                 $tmp = substr($tmp, 0, -1);
1186             }
1187             $this->logger->log(LOG_DEBUG, '-> default_action_name[%s]', $tmp);
1188             $action_name = $tmp;
1189         } else {
1190             $action_name = $form_action_name;
1191         }
1192
1193         // エントリポイントに配列が指定されている場合は指定以外のアクション名は拒否する
1194         if (is_array($default_action_name)) {
1195             if ($this->_isAcceptableActionName($action_name, $default_action_name) == false) {
1196                 // 指定以外のアクション名で合った場合は$fallback_action_name(or デフォルト)
1197                 $tmp = $fallback_action_name != "" ? $fallback_action_name : $default_action_name[0];
1198                 if ($tmp{strlen($tmp)-1} == '*') {
1199                     $tmp = substr($tmp, 0, -1);
1200                 }
1201                 $this->logger->log(LOG_DEBUG, '-> fallback_action_name[%s]', $tmp);
1202                 $action_name = $tmp;
1203             }
1204         }
1205
1206         $this->logger->log(LOG_DEBUG, '<<< action_name[%s] >>>', $action_name);
1207
1208         return $action_name;
1209     }
1210
1211     /**
1212      *  フォームにより要求されたアクション名を返す
1213      *
1214      *  アプリケーションの性質に応じてこのメソッドをオーバーライドして下さい。
1215      *  デフォルトでは"action_"で始まるフォーム値の"action_"の部分を除いたもの
1216      *  ("action_sample"なら"sample")がアクション名として扱われます
1217      *
1218      *  @access protected
1219      *  @return string  フォームにより要求されたアクション名
1220      */
1221     function _getActionName_Form()
1222     {
1223         if (isset($_SERVER['REQUEST_METHOD']) == false) {
1224             return null;
1225         }
1226
1227         $url_handler =& $this->getUrlHandler();
1228         if ($_SERVER['REQUEST_METHOD'] == "GET") {
1229             $tmp_vars = $_GET;
1230         } else if ($_SERVER['REQUEST_METHOD'] == "POST") {
1231             $tmp_vars = $_POST;
1232         }
1233
1234         if (empty($_SERVER['URL_HANDLER']) == false) {
1235             $tmp_vars['__url_handler__'] = $_SERVER['URL_HANDLER'];
1236             $tmp_vars['__url_info__'] = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : null;
1237             $tmp_vars = $url_handler->requestToAction($tmp_vars);
1238
1239             if ($_SERVER['REQUEST_METHOD'] == "GET") {
1240                 $_GET = array_merge($_GET, $tmp_vars);
1241             } else if ($_SERVER['REQUEST_METHOD'] == "POST") {
1242                 $_POST = array_merge($_POST, $tmp_vars);
1243             }
1244             $_REQUEST = array_merge($_REQUEST, $tmp_vars);
1245         }
1246
1247         if (strcasecmp($_SERVER['REQUEST_METHOD'], 'post') == 0) {
1248             $http_vars =& $_POST;
1249         } else {
1250             $http_vars =& $_GET;
1251         }
1252
1253         // フォーム値からリクエストされたアクション名を取得する
1254         $action_name = $sub_action_name = null;
1255         foreach ($http_vars as $name => $value) {
1256             if ($value == "" || strncmp($name, 'action_', 7) != 0) {
1257                 continue;
1258             }
1259
1260             $tmp = substr($name, 7);
1261
1262             // type="image"対応
1263             if (preg_match('/_x$/', $name) || preg_match('/_y$/', $name)) {
1264                 $tmp = substr($tmp, 0, strlen($tmp)-2);
1265             }
1266
1267             // value="dummy"となっているものは優先度を下げる
1268             if ($value == "dummy") {
1269                 $sub_action_name = $tmp;
1270             } else {
1271                 $action_name = $tmp;
1272             }
1273         }
1274         if ($action_name == null) {
1275             $action_name = $sub_action_name;
1276         }
1277
1278         return $action_name;
1279     }
1280
1281     /**
1282      *  アクション名を指定するクエリ/HTMLを生成する
1283      *
1284      *  @access public
1285      *  @param  string  $action action to request
1286      *  @param  string  $type   hidden, url...
1287      *  @todo   consider gateway
1288      */
1289     function getActionRequest($action, $type = "hidden")
1290     {
1291         $s = null;
1292         if ($type == "hidden") {
1293             $s = sprintf('<input type="hidden" name="action_%s" value="true" />', htmlspecialchars($action, ENT_QUOTES));
1294         } else if ($type == "url") {
1295             $s = sprintf('action_%s=true', urlencode($action));
1296         }
1297         return $s;
1298     }
1299
1300     /**
1301      *  フォームにより要求されたアクション名に対応する定義を返す
1302      *
1303      *  @access private
1304      *  @param  string  $action_name    アクション名
1305      *  @return array   アクション定義
1306      */
1307     function &_getAction($action_name, $gateway = null)
1308     {
1309         $action = array();
1310         $gateway = is_null($gateway) ? $this->getGateway() : $gateway;
1311         switch ($gateway) {
1312         case GATEWAY_WWW:
1313             $action =& $this->action;
1314             break;
1315         case GATEWAY_CLI:
1316             $action =& $this->action_cli;
1317             break;
1318         case GATEWAY_XMLRPC:
1319             $action =& $this->action_xmlrpc;
1320             break;
1321         }
1322
1323         $action_obj = array();
1324         if (isset($action[$action_name])) {
1325             $action_obj = $action[$action_name];
1326             if (isset($action_obj['inspect']) && $action_obj['inspect']) {
1327                 return $action_obj;
1328             }
1329         } else {
1330             $this->logger->log(LOG_DEBUG, "action [%s] is not defined -> try default", $action_name);
1331         }
1332
1333         // アクションスクリプトのインクルード
1334         $this->_includeActionScript($action_obj, $action_name);
1335
1336         // 省略値の補正
1337         if (isset($action_obj['class_name']) == false) {
1338             $action_obj['class_name'] = $this->getDefaultActionClass($action_name);
1339         }
1340
1341         if (isset($action_obj['form_name']) == false) {
1342             $action_obj['form_name'] = $this->getDefaultFormClass($action_name);
1343         } else if (class_exists($action_obj['form_name']) == false) {
1344             // 明示指定されたフォームクラスが定義されていない場合は警告
1345             $this->logger->log(LOG_WARNING, 'stated form class is not defined [%s]', $action_obj['form_name']);
1346         }
1347
1348         // 必要条件の確認
1349         if (class_exists($action_obj['class_name']) == false) {
1350             $this->logger->log(LOG_NOTICE, 'action class is not defined [%s]', $action_obj['class_name']);
1351             $_ret_object = null;
1352             return $_ret_object;
1353         }
1354         if (class_exists($action_obj['form_name']) == false) {
1355             // フォームクラスは未定義でも良い
1356             $class_name = $this->class_factory->getObjectName('form');
1357             $this->logger->log(LOG_DEBUG, 'form class is not defined [%s] -> falling back to default [%s]', $action_obj['form_name'], $class_name);
1358             $action_obj['form_name'] = $class_name;
1359         }
1360
1361         $action_obj['inspect'] = true;
1362         $action[$action_name] = $action_obj;
1363         return $action[$action_name];
1364     }
1365
1366     /**
1367      *  アクション名とアクションクラスからの戻り値に基づいて遷移先を決定する
1368      *
1369      *  @access protected
1370      *  @param  string  $action_name    アクション名
1371      *  @param  string  $retval         アクションクラスからの戻り値
1372      *  @return string  遷移先
1373      */
1374     function _sortForward($action_name, $retval)
1375     {
1376         return $retval;
1377     }
1378
1379     /**
1380      *  フィルタチェインを生成する
1381      *
1382      *  @access private
1383      */
1384     function _createFilterChain()
1385     {
1386         $this->filter_chain = array();
1387         foreach ($this->filter as $filter) {
1388             $filter_plugin =& $this->plugin->getPlugin('Filter', $filter);
1389             if (Ethna::isError($filter_plugin)) {
1390                 continue;
1391             }
1392
1393             $this->filter_chain[] =& $filter_plugin;
1394         }
1395     }
1396
1397     /**
1398      *  アクション名が実行許可されているものかどうかを返す
1399      *
1400      *  @access private
1401      *  @param  string  $action_name            リクエストされたアクション名
1402      *  @param  array   $default_action_name    許可されているアクション名
1403      *  @return bool    true:許可 false:不許可
1404      */
1405     function _isAcceptableActionName($action_name, $default_action_name)
1406     {
1407         foreach (to_array($default_action_name) as $name) {
1408             if ($action_name == $name) {
1409                 return true;
1410             } else if ($name{strlen($name)-1} == '*') {
1411                 if (strncmp($action_name, substr($name, 0, -1), strlen($name)-1) == 0) {
1412                     return true;
1413                 }
1414             }
1415         }
1416         return false;
1417     }
1418
1419     /**
1420      *  指定されたアクションのフォームクラス名を返す(オブジェクトの生成は行わない)
1421      *
1422      *  @access public
1423      *  @param  string  $action_name    アクション名
1424      *  @return string  アクションのフォームクラス名
1425      */
1426     function getActionFormName($action_name)
1427     {
1428         $action_obj =& $this->_getAction($action_name);
1429         if (is_null($action_obj)) {
1430             return null;
1431         }
1432
1433         return $action_obj['form_name'];
1434     }
1435
1436     /**
1437      *  アクションに対応するフォームクラス名が省略された場合のデフォルトクラス名を返す
1438      *
1439      *  デフォルトでは[プロジェクトID]_Form_[アクション名]となるので好み応じてオーバライドする
1440      *
1441      *  @access public
1442      *  @param  string  $action_name    アクション名
1443      *  @return string  アクションフォーム名
1444      */
1445     function getDefaultFormClass($action_name, $gateway = null)
1446     {
1447         $gateway_prefix = $this->_getGatewayPrefix($gateway);
1448
1449         $postfix = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($action_name));
1450         $r = sprintf("%s_%sForm_%s", $this->getAppId(), $gateway_prefix ? $gateway_prefix . "_" : "", $postfix);
1451         $this->logger->log(LOG_DEBUG, "default action class [%s]", $r);
1452
1453         return $r;
1454     }
1455
1456     /**
1457      *  getDefaultFormClass()で取得したクラス名からアクション名を取得する
1458      *
1459      *  getDefaultFormClass()をオーバーライドした場合、こちらも合わせてオーバーライド
1460      *  することを推奨(必須ではない)
1461      *
1462      *  @access public
1463      *  @param  string  $class_name     フォームクラス名
1464      *  @return string  アクション名
1465      */
1466     function actionFormToName($class_name)
1467     {
1468         $prefix = sprintf("%s_Form_", $this->getAppId());
1469         if (preg_match("/$prefix(.*)/", $class_name, $match) == 0) {
1470             // 不明なクラス名
1471             return null;
1472         }
1473         $target = $match[1];
1474
1475         $action_name = substr(preg_replace('/([A-Z])/e', "'_' . strtolower('\$1')", $target), 1);
1476
1477         return $action_name;
1478     }
1479
1480     /**
1481      *  アクションに対応するフォームパス名が省略された場合のデフォルトパス名を返す
1482      *
1483      *  デフォルトでは_getDefaultActionPath()と同じ結果を返す(1ファイルに
1484      *  アクションクラスとフォームクラスが記述される)ので、好みに応じて
1485      *  オーバーライドする
1486      *
1487      *  @access public
1488      *  @param  string  $action_name    アクション名
1489      *  @return string  form classが定義されるスクリプトのパス名
1490      */
1491     function getDefaultFormPath($action_name)
1492     {
1493         return $this->getDefaultActionPath($action_name);
1494     }
1495
1496     /**
1497      *  指定されたアクションのクラス名を返す(オブジェクトの生成は行わない)
1498      *
1499      *  @access public
1500      *  @param  string  $action_name    アクションの名称
1501      *  @return string  アクションのクラス名
1502      */
1503     function getActionClassName($action_name)
1504     {
1505         $action_obj =& $this->_getAction($action_name);
1506         if ($action_obj == null) {
1507             return null;
1508         }
1509
1510         return $action_obj['class_name'];
1511     }
1512
1513     /**
1514      *  アクションに対応するアクションクラス名が省略された場合のデフォルトクラス名を返す
1515      *
1516      *  デフォルトでは[プロジェクトID]_Action_[アクション名]となるので好み応じてオーバライドする
1517      *
1518      *  @access public
1519      *  @param  string  $action_name    アクション名
1520      *  @return string  アクションクラス名
1521      */
1522     function getDefaultActionClass($action_name, $gateway = null)
1523     {
1524         $gateway_prefix = $this->_getGatewayPrefix($gateway);
1525
1526         $postfix = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($action_name));
1527         $r = sprintf("%s_%sAction_%s", $this->getAppId(), $gateway_prefix ? $gateway_prefix . "_" : "", $postfix);
1528         $this->logger->log(LOG_DEBUG, "default action class [%s]", $r);
1529
1530         return $r;
1531     }
1532
1533     /**
1534      *  getDefaultActionClass()で取得したクラス名からアクション名を取得する
1535      *
1536      *  getDefaultActionClass()をオーバーライドした場合、こちらも合わせてオーバーライド
1537      *  することを推奨(必須ではない)
1538      *
1539      *  @access public
1540      *  @param  string  $class_name     アクションクラス名
1541      *  @return string  アクション名
1542      */
1543     function actionClassToName($class_name)
1544     {
1545         $prefix = sprintf("%s_Action_", $this->getAppId());
1546         if (preg_match("/$prefix(.*)/", $class_name, $match) == 0) {
1547             // 不明なクラス名
1548             return null;
1549         }
1550         $target = $match[1];
1551
1552         $action_name = substr(preg_replace('/([A-Z])/e', "'_' . strtolower('\$1')", $target), 1);
1553
1554         return $action_name;
1555     }
1556
1557     /**
1558      *  アクションに対応するアクションパス名が省略された場合のデフォルトパス名を返す
1559      *
1560      *  デフォルトでは"foo_bar" -> "/Foo/Bar.php"となるので好み応じてオーバーライドする
1561      *
1562      *  @access public
1563      *  @param  string  $action_name    アクション名
1564      *  @return string  アクションクラスが定義されるスクリプトのパス名
1565      */
1566     function getDefaultActionPath($action_name)
1567     {
1568         $r = preg_replace('/_(.)/e', "'/' . strtoupper('\$1')", ucfirst($action_name)) . '.' . $this->getExt('php');
1569         $this->logger->log(LOG_DEBUG, "default action path [%s]", $r);
1570
1571         return $r;
1572     }
1573
1574     /**
1575      *  指定された遷移名に対応するビュークラス名を返す(オブジェクトの生成は行わない)
1576      *
1577      *  @access public
1578      *  @param  string  $forward_name   遷移先の名称
1579      *  @return string  view classのクラス名
1580      */
1581     function getViewClassName($forward_name)
1582     {
1583         if ($forward_name == null) {
1584             return null;
1585         }
1586
1587         if (isset($this->forward[$forward_name])) {
1588             $forward_obj = $this->forward[$forward_name];
1589         } else {
1590             $forward_obj = array();
1591         }
1592
1593         if (isset($forward_obj['view_name'])) {
1594             $class_name = $forward_obj['view_name'];
1595             if (class_exists($class_name)) {
1596                 return $class_name;
1597             }
1598         } else {
1599             $class_name = null;
1600         }
1601
1602         // viewのインクルード
1603         $this->_includeViewScript($forward_obj, $forward_name);
1604
1605         if (is_null($class_name) == false && class_exists($class_name)) {
1606             return $class_name;
1607         } else if (is_null($class_name) == false) {
1608             $this->logger->log(LOG_WARNING, 'stated view class is not defined [%s] -> try default', $class_name);
1609         }
1610
1611         $class_name = $this->getDefaultViewClass($forward_name);
1612         if (class_exists($class_name)) {
1613             return $class_name;
1614         } else {
1615             $class_name = $this->class_factory->getObjectName('view');
1616             $this->logger->log(LOG_DEBUG, 'view class is not defined for [%s] -> use default [%s]', $forward_name, $class_name);
1617             return $class_name;
1618         }
1619     }
1620
1621     /**
1622      *  遷移名に対応するビュークラス名が省略された場合のデフォルトクラス名を返す
1623      *
1624      *  デフォルトでは[プロジェクトID]_View_[遷移名]となるので好み応じてオーバライドする
1625      *
1626      *  @access public
1627      *  @param  string  $forward_name   forward名
1628      *  @return string  view classクラス名
1629      */
1630     function getDefaultViewClass($forward_name, $gateway = null)
1631     {
1632         $gateway_prefix = $this->_getGatewayPrefix($gateway);
1633
1634         $postfix = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($forward_name));
1635         $r = sprintf("%s_%sView_%s", $this->getAppId(), $gateway_prefix ? $gateway_prefix . "_" : "", $postfix);
1636         $this->logger->log(LOG_DEBUG, "default view class [%s]", $r);
1637
1638         return $r;
1639     }
1640
1641     /**
1642      *  遷移名に対応するビューパス名が省略された場合のデフォルトパス名を返す
1643      *
1644      *  デフォルトでは"foo_bar" -> "/Foo/Bar.php"となるので好み応じてオーバーライドする
1645      *
1646      *  @access public
1647      *  @param  string  $forward_name   forward名
1648      *  @return string  view classが定義されるスクリプトのパス名
1649      */
1650     function getDefaultViewPath($forward_name)
1651     {
1652         $r = preg_replace('/_(.)/e', "'/' . strtoupper('\$1')", ucfirst($forward_name)) . '.' . $this->getExt('php');
1653         $this->logger->log(LOG_DEBUG, "default view path [%s]", $r);
1654
1655         return $r;
1656     }
1657
1658     /**
1659      *  遷移名に対応するテンプレートパス名が省略された場合のデフォルトパス名を返す
1660      *
1661      *  デフォルトでは"foo_bar"というforward名が"foo/bar" + テンプレート拡張子となる
1662      *  ので好み応じてオーバライドする
1663      *
1664      *  @access public
1665      *  @param  string  $forward_name   forward名
1666      *  @return string  forwardパス名
1667      */
1668     function getDefaultForwardPath($forward_name)
1669     {
1670         return str_replace('_', '/', $forward_name) . '.' . $this->ext['tpl'];
1671     }
1672
1673     /**
1674      *  テンプレートパス名から遷移名を取得する
1675      *
1676      *  getDefaultForwardPath()をオーバーライドした場合、こちらも合わせてオーバーライド
1677      *  することを推奨(必須ではない)
1678      *
1679      *  @access public
1680      *  @param  string  $forward_path   テンプレートパス名
1681      *  @return string  遷移名
1682      */
1683     function forwardPathToName($forward_path)
1684     {
1685         $forward_path = preg_replace('/^\/+/', '', $forward_path);
1686         $forward_path = preg_replace(sprintf('/\.%s$/', $this->getExt('tpl')), '', $forward_path);
1687
1688         return str_replace('/', '_', $forward_path);
1689     }
1690
1691     /**
1692      *  遷移名からテンプレートファイルのパス名を取得する
1693      *
1694      *  @access private
1695      *  @param  string  $forward_name   forward名
1696      *  @return string  テンプレートファイルのパス名
1697      */
1698     function _getForwardPath($forward_name)
1699     {
1700         $forward_obj = null;
1701
1702         if (isset($this->forward[$forward_name]) == false) {
1703             // try default
1704             $this->forward[$forward_name] = array();
1705         }
1706         $forward_obj =& $this->forward[$forward_name];
1707         if (isset($forward_obj['forward_path']) == false) {
1708             // 省略値補正
1709             $forward_obj['forward_path'] = $this->getDefaultForwardPath($forward_name);
1710         }
1711
1712         return $forward_obj['forward_path'];
1713     }
1714
1715     /**
1716      *  レンダラを取得する(getTemplateEngine()はそのうち廃止されgetRenderer()に統合される予定)
1717      *
1718      *  @access public
1719      *  @return object  Ethna_Renderer  レンダラオブジェクト
1720      */
1721     function &getRenderer()
1722     {
1723         $_ret_object =& $this->getTemplateEngine();
1724         return $_ret_object;
1725     }
1726
1727     /**
1728      *  テンプレートエンジン取得する
1729      *
1730      *  @access public
1731      *  @return object  Ethna_Renderer  レンダラオブジェクト
1732      *  @obsolete
1733      */
1734     function &getTemplateEngine()
1735     {
1736         if (is_object($this->renderer)) {
1737             return $this->renderer;
1738         }
1739
1740         $this->renderer =& $this->class_factory->getObject('renderer');
1741
1742         //テンプレートエンジンのデフォルトの設定
1743         $this->_setDefaultTemplateEngine($this->renderer);
1744         // }}}
1745
1746         return $this->renderer;
1747     }
1748
1749     /**
1750      *  テンプレートエンジンのデフォルト状態を設定する
1751      *
1752      *  @access protected
1753      *  @param  object  Ethna_Renderer  レンダラオブジェクト
1754      *  @obsolete
1755      */
1756     function _setDefaultTemplateEngine(&$renderer)
1757     {
1758     }
1759
1760     /**
1761      *  使用言語、ロケールを設定する
1762      *  条件によって使用言語、ロケールを切り替えたい場合は、
1763      *  このメソッドをオーバーライドする。
1764      *
1765      *  @access protected
1766      *  @param  string  $locale             ロケール名(ja_JP, en_US等)
1767      *                                      (ll_cc の形式。ll = 言語コード cc = 国コード)
1768      *  @param  string  $system_encoding    システムエンコーディング名
1769      *  @param  string  $client_encoding    クライアントエンコーディング(テンプレートのエンコーディングと考えれば良い)
1770      *  @see    http://www.gnu.org/software/gettext/manual/html_node/Locale-Names.html
1771      *  @see    Ethna_Controller#_getDefaultLanguage
1772      */
1773     function _setLanguage($locale, $system_encoding = null, $client_encoding = null)
1774     {
1775         $this->locale = $locale;
1776         $this->system_encoding = $system_encoding;
1777         $this->client_encoding = $client_encoding;
1778
1779         //   $this->locale, $this->client_encoding を書き換えた場合は
1780         //   必ず Ethna_I18N クラスの setLanguageメソッドも呼ぶこと!
1781         //   さもないとカタログその他が再ロードされない!
1782         $i18n =& $this->getI18N();
1783         $i18n->setLanguage($locale, $system_encoding, $client_encoding);
1784     }
1785
1786     /**
1787      *  デフォルト状態での使用言語を取得する
1788      *  外部に出力されるEthnaのエラーメッセージ等のエンコーディングを
1789      *  切り替えたい場合は、このメソッドをオーバーライドする。
1790      *
1791      *  @access protected
1792      *  @return array   ロケール名(e.x ja_JP, en_US 等),
1793      *                  システムエンコーディング名,
1794      *                  クライアントエンコーディング名
1795      *                  (= テンプレートのエンコーディングと考えてよい) の配列
1796      *                  (ロケール名は ll_cc の形式。ll = 言語コード cc = 国コード)
1797      *
1798      *  WARNING!! : クライアントエンコーディング名が、フレームワークの内部エンコーデ
1799      *              ィングとして設定されます。つまり、クライアントエンコーディングで
1800      *              ブラウザからの入力は入ってくるものと想定しています!
1801      */
1802     function _getDefaultLanguage()
1803     {
1804         return array('ja_JP', 'UTF-8', 'UTF-8');
1805     }
1806
1807     /**
1808      *  デフォルト状態でのゲートウェイを取得する
1809      *
1810      *  @access protected
1811      *  @return int     ゲートウェイ定義(GATEWAY_WWW, GATEWAY_CLI...)
1812      */
1813     function _getDefaultGateway($gateway)
1814     {
1815         if (is_null($GLOBALS['_Ethna_gateway']) == false) {
1816             return $GLOBALS['_Ethna_gateway'];
1817         }
1818         return GATEWAY_WWW;
1819     }
1820
1821     /**
1822      *  ゲートウェイに対応したクラス名のプレフィクスを取得する
1823      *
1824      *  @access public
1825      *  @param  string  $gateway    ゲートウェイ
1826      *  @return string  ゲートウェイクラスプレフィクス
1827      */
1828     function _getGatewayPrefix($gateway = null)
1829     {
1830         $gateway = is_null($gateway) ? $this->getGateway() : $gateway;
1831         switch ($gateway) {
1832         case GATEWAY_WWW:
1833             $prefix = '';
1834             break;
1835         case GATEWAY_CLI:
1836             $prefix = 'Cli';
1837             break;
1838         case GATEWAY_XMLRPC:
1839             $prefix = 'Xmlrpc';
1840             break;
1841         default:
1842             $prefix = '';
1843             break;
1844         }
1845
1846         return $prefix;
1847     }
1848
1849     /**
1850      *  マネージャクラス名を取得する
1851      *
1852      *  @access public
1853      *  @param  string  $name   マネージャキー
1854      *  @return string  マネージャクラス名
1855      */
1856     function getManagerClassName($name)
1857     {
1858         //   アプリケーションIDと、渡された名前のはじめを大文字にして、
1859         //   組み合わせたものが返される
1860         $manager_id = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($name));
1861         return sprintf('%s_%sManager', $this->getAppId(), ucfirst($manager_id));
1862     }
1863
1864     /**
1865      *  アプリケーションオブジェクトクラス名を取得する
1866      *
1867      *  @access public
1868      *  @param  string  $name   アプリケーションオブジェクトキー
1869      *  @return string  マネージャクラス名
1870      */
1871     function getObjectClassName($name)
1872     {
1873         //  引数のはじめの一文字目と、アンダーバー直後の
1874         //  1文字を必ず大文字にする。アンダーバーは削除される。
1875         $name = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($name));
1876
1877         //  $name に foo_bar を渡し、AppID が Hogeの場合
1878         //  [Appid]_FooBar が返される
1879         return sprintf('%s_%s', $this->getAppId(), $name);
1880     }
1881
1882     /**
1883      *  アクションスクリプトをインクルードする
1884      *
1885      *  ただし、インクルードしたファイルにクラスが正しく定義されているかどうかは保証しない
1886      *
1887      *  @access private
1888      *  @param  array   $action_obj     アクション定義
1889      *  @param  string  $action_name    アクション名
1890      */
1891     function _includeActionScript($action_obj, $action_name)
1892     {
1893         $class_path = $form_path = null;
1894
1895         $action_dir = $this->getActiondir();
1896
1897         // class_path属性チェック
1898         if (isset($action_obj['class_path'])) {
1899             // フルパス指定サポート
1900             $tmp_path = $action_obj['class_path'];
1901             if (Ethna_Util::isAbsolute($tmp_path) == false) {
1902                 $tmp_path = $action_dir . $tmp_path;
1903             }
1904
1905             if (file_exists($tmp_path) == false) {
1906                 $this->logger->log(LOG_WARNING, 'class_path file not found [%s] -> try default', $tmp_path);
1907             } else {
1908                 include_once $tmp_path;
1909                 $class_path = $tmp_path;
1910             }
1911         }
1912
1913         // デフォルトチェック
1914         if (is_null($class_path)) {
1915             $class_path = $this->getDefaultActionPath($action_name);
1916             if (file_exists($action_dir . $class_path)) {
1917                 include_once $action_dir . $class_path;
1918             } else {
1919                 $this->logger->log(LOG_DEBUG, 'default action file not found [%s] -> try all files', $class_path);
1920                 return;
1921             }
1922         }
1923
1924         // form_path属性チェック
1925         if (isset($action_obj['form_path'])) {
1926             // フルパス指定サポート
1927             $tmp_path = $action_obj['form_path'];
1928             if (Ethna_Util::isAbsolute($tmp_path) == false) {
1929                 $tmp_path = $action_dir . $tmp_path;
1930             }
1931
1932             if ($tmp_path == $class_path) {
1933                 return;
1934             }
1935             if (file_exists($tmp_path) == false) {
1936                 $this->logger->log(LOG_WARNING, 'form_path file not found [%s] -> try default', $tmp_path);
1937             } else {
1938                 include_once $tmp_path;
1939                 $form_path = $tmp_path;
1940             }
1941         }
1942
1943         // デフォルトチェック
1944         if (is_null($form_path)) {
1945             $form_path = $this->getDefaultFormPath($action_name);
1946             if ($form_path == $class_path) {
1947                 return;
1948             }
1949             if (file_exists($action_dir . $form_path)) {
1950                 include_once $action_dir . $form_path;
1951             } else {
1952                 $this->logger->log(LOG_DEBUG, 'default form file not found [%s] -> maybe falling back to default form class', $form_path);
1953             }
1954         }
1955     }
1956
1957     /**
1958      *  ビュースクリプトをインクルードする
1959      *
1960      *  ただし、インクルードしたファイルにクラスが正しく定義されているかどうかは保証しない
1961      *
1962      *  @access private
1963      *  @param  array   $forward_obj    遷移定義
1964      *  @param  string  $forward_name   遷移名
1965      */
1966     function _includeViewScript($forward_obj, $forward_name)
1967     {
1968         $view_dir = $this->getViewdir();
1969
1970         // view_path属性チェック
1971         if (isset($forward_obj['view_path'])) {
1972             // フルパス指定サポート
1973             $tmp_path = $forward_obj['view_path'];
1974             if (Ethna_Util::isAbsolute($tmp_path) == false) {
1975                 $tmp_path = $view_dir . $tmp_path;
1976             }
1977
1978             if (file_exists($tmp_path) == false) {
1979                 $this->logger->log(LOG_WARNING, 'view_path file not found [%s] -> try default', $tmp_path);
1980             } else {
1981                 include_once $tmp_path;
1982                 return;
1983             }
1984         }
1985
1986         // デフォルトチェック
1987         $view_path = $this->getDefaultViewPath($forward_name);
1988         if (file_exists($view_dir . $view_path)) {
1989             include_once $view_dir . $view_path;
1990             return;
1991         } else {
1992             $this->logger->log(LOG_DEBUG, 'default view file not found [%s]', $view_path);
1993             $view_path = null;
1994         }
1995     }
1996
1997     /**
1998      *  ディレクトリ以下の全てのスクリプトをインクルードする
1999      *
2000      *  @access private
2001      */
2002     function _includeDirectory($dir)
2003     {
2004         $ext = "." . $this->ext['php'];
2005         $ext_len = strlen($ext);
2006
2007         if (is_dir($dir) == false) {
2008             return;
2009         }
2010
2011         $dh = opendir($dir);
2012         if ($dh) {
2013             while (($file = readdir($dh)) !== false) {
2014                 if ($file != '.' && $file != '..' && is_dir("$dir/$file")) {
2015                     $this->_includeDirectory("$dir/$file");
2016                 }
2017                 if (substr($file, -$ext_len, $ext_len) != $ext) {
2018                     continue;
2019                 }
2020                 include_once $dir . '/' . $file;
2021             }
2022         }
2023         closedir($dh);
2024     }
2025
2026     /**
2027      *  設定ファイルのDSN定義から使用するデータを再構築する(スレーブアクセス分岐等)
2028      *
2029      *  DSNの定義方法(デフォルト:設定ファイル)を変えたい場合はここをオーバーライドする
2030      *
2031      *  @access protected
2032      *  @return array   DSN定義(array('DBキー1' => 'dsn1', 'DBキー2' => 'dsn2', ...))
2033      */
2034     function _prepareDSN()
2035     {
2036         $r = array();
2037
2038         foreach ($this->db as $key => $value) {
2039             $config_key = "dsn";
2040             if ($key != "") {
2041                 $config_key .= "_$key";
2042             }
2043             $dsn = $this->config->get($config_key);
2044             if (is_array($dsn)) {
2045                 // 種別1つにつき複数DSNが定義されている場合はアクセス分岐
2046                 $dsn = $this->_selectDSN($key, $dsn);
2047             }
2048             $r[$key] = $dsn;
2049         }
2050         return $r;
2051     }
2052
2053     /**
2054      *  DSNのアクセス分岐を行う
2055      *
2056      *  スレーブサーバへの振分け処理(デフォルト:ランダム)を変更したい場合はこのメソッドをオーバーライドする
2057      *
2058      *  @access protected
2059      *  @param  string  $type       DB種別
2060      *  @param  array   $dsn_list   DSN一覧
2061      *  @return string  選択されたDSN
2062      */
2063     function _selectDSN($type, $dsn_list)
2064     {
2065         if (is_array($dsn_list) == false) {
2066             return $dsn_list;
2067         }
2068
2069         // デフォルト:ランダム
2070         list($usec, $sec) = explode(' ', microtime());
2071         mt_srand($sec + ((float) $usec * 100000));
2072         $n = mt_rand(0, count($dsn_list)-1);
2073
2074         return $dsn_list[$n];
2075     }
2076
2077     /**
2078      *  Ethnaマネージャを設定する
2079      *
2080      *  不要な場合は空のメソッドとしてオーバーライドしてもよい
2081      *
2082      *  @access protected
2083      */
2084     function _activateEthnaManager()
2085     {
2086         if ($this->config->get('debug') == false) {
2087             return;
2088         }
2089
2090         require_once ETHNA_BASE . '/class/Ethna_InfoManager.php';
2091
2092         // see if we have simpletest
2093         if (file_exists_ex('simpletest/unit_tester.php', true)) {
2094             require_once ETHNA_BASE . '/class/Ethna_UnitTestManager.php';
2095         }
2096
2097         // action設定
2098         $this->action['__ethna_info__'] = array(
2099             'form_name' =>  'Ethna_Form_Info',
2100             'form_path' =>  sprintf('%s/class/Action/Ethna_Action_Info.php', ETHNA_BASE),
2101             'class_name' => 'Ethna_Action_Info',
2102             'class_path' => sprintf('%s/class/Action/Ethna_Action_Info.php', ETHNA_BASE),
2103         );
2104
2105         // forward設定
2106         $this->forward['__ethna_info__'] = array(
2107             'forward_path'  => sprintf('%s/tpl/info.tpl', ETHNA_BASE),
2108             'view_name'     => 'Ethna_View_Info',
2109             'view_path'     => sprintf('%s/class/View/Ethna_View_Info.php', ETHNA_BASE),
2110         );
2111
2112
2113         // action設定
2114         $this->action['__ethna_unittest__'] = array(
2115             'form_name' =>  'Ethna_Form_UnitTest',
2116             'form_path' =>  sprintf('%s/class/Action/Ethna_Action_UnitTest.php', ETHNA_BASE),
2117             'class_name' => 'Ethna_Action_UnitTest',
2118             'class_path' => sprintf('%s/class/Action/Ethna_Action_UnitTest.php', ETHNA_BASE),
2119         );
2120
2121         // forward設定
2122         $this->forward['__ethna_unittest__'] = array(
2123             'forward_path'  => sprintf('%s/tpl/unittest.tpl', ETHNA_BASE),
2124             'view_name'     => 'Ethna_View_UnitTest',
2125             'view_path'     => sprintf('%s/class/View/Ethna_View_UnitTest.php', ETHNA_BASE),
2126         );
2127
2128     }
2129
2130     /**
2131      *  Ethnaマネージャが実行可能かをチェックする
2132      *
2133      *  Ethnaマネージャを実行するよう指示されているにも関わらず、
2134      *  debug が trueでない場合は実行を停止する。
2135      *
2136      *  @access private
2137      */
2138     function _ethnaManagerEnabledCheck($action_name)
2139     {
2140         if ($this->config->get('debug') == false
2141          && ($action_name == '__ethna_info__' || $action_name == '__ethna_unittest__')) {
2142             $this->ethnaManagerCheckErrorMsg($action_name);
2143             exit(0);
2144         }
2145     }
2146
2147     /**
2148      *  Ethnaマネージャが実行不能な場合のエラーメッセージを
2149      *  表示する。運用上の都合でこのメッセージを出力したくない
2150      *  場合は、このメソッドをオーバーライドせよ
2151      *
2152      *  @access protected
2153      */
2154      function ethnaManagerCheckErrorMsg($action_name)
2155      {
2156          $appid = strtolower($this->getAppId());
2157          $run_action = ($action_name == '__ethna_info__')
2158                      ? ' show Application Info List '
2159                      : ' run Unit Test ';
2160          echo "Ethna cannot {$run_action} under your application setting.<br>";
2161          echo "HINT: You must set {$appid}/etc/{$appid}-ini.php debug setting 'true'.<br>";
2162          echo "<br>";
2163          echo "In {$appid}-ini.php, please set as follows :<br><br>";
2164          echo "\$config = array ( 'debug' => true, );";
2165      }
2166
2167     /**
2168      *  CLI実行中フラグを取得する
2169      *
2170      *  @access public
2171      *  @return bool    CLI実行中フラグ
2172      *  @obsolete
2173      */
2174     function getCLI()
2175     {
2176         return $this->gateway == GATEWAY_CLI ? true : false;
2177     }
2178
2179     /**
2180      *  CLI実行中フラグを設定する
2181      *
2182      *  @access public
2183      *  @param  bool    CLI実行中フラグ
2184      *  @obsolete
2185      */
2186     function setCLI($cli)
2187     {
2188         $this->gateway = $cli ? GATEWAY_CLI : $this->_getDefaultGateway();
2189     }
2190 }
2191 // }}}
2192
2193 /**
2194  *  XMLRPCゲートウェイのスタブクラス
2195  *
2196  *  @access     public
2197  */
2198 function _Ethna_XmlrpcGateway($method_stub, $param)
2199 {
2200     $ctl =& Ethna_Controller::getInstance();
2201     $method = $ctl->getXmlrpcMethodName();
2202     $r = $ctl->trigger_XMLRPC($method, $param);
2203     if (Ethna::isError($r)) {
2204         return array(
2205             'faultCode' => $r->getCode(),
2206             'faultString' => $r->getMessage(),
2207         );
2208     }
2209     return $r;
2210 }
2211 ?>