OSDN Git Service

- merged changes from 2009-01-30 to 2009-04-29.
authorYoshinari Takaoka <mumumu@mumumu.org>
Fri, 16 Oct 2009 08:57:21 +0000 (17:57 +0900)
committerYoshinari Takaoka <mumumu@mumumu.org>
Fri, 16 Oct 2009 08:57:21 +0000 (17:57 +0900)
30 files changed:
CHANGES
Ethna.php
bin/ethna_handle.php
bin/ethna_run_test.php
class/Ethna_ActionForm.php
class/Ethna_Config.php
class/Ethna_Controller.php
class/Ethna_Getopt.php
class/Ethna_ViewClass.php
class/Plugin/Generator/Ethna_Plugin_Generator_Project.php
class/Plugin/Generator/Ethna_Plugin_Generator_Template.php
class/Plugin/Handle/Ethna_Plugin_Handle_AddProject.php
class/Plugin/Handle/Ethna_Plugin_Handle_AddTemplate.php
class/Plugin/Handle/Ethna_Plugin_Handle_Help.php [new file with mode: 0644]
class/Plugin/Smarty/block.form.php
class/Plugin/Smarty/function.form_input.php
skel/app.controller.php
skel/locale/ja_JP/ethna_sysmsg.ini
skel/skel.app_manager.php
skel/www.index.php
skel/www.info.php
skel/www.unittest.php
test/Ethna_Getopt_Test.php
test/Ethna_MockProject.php
test/Ethna_ViewClass_Test.php
test/Plugin/Handle/Ethna_Plugin_Handle_AddTemplate_Test.php [new file with mode: 0644]
test/Plugin/Handle/Ethna_Plugin_Handle_I18n_Test.php
test/Plugin/Handle/Ethna_Plugin_Handle_PearLocal_Test.php [new file with mode: 0644]
test/TextDetailReporter.php
test/skel/app.controller.php [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index ee92828..3f39932 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,38 @@
 * 変更点一覧
 
+** 2.5.0
+
+*** features
+
+- フォーム定義に関する変更
+-- フォーム定義を動的に変更するためのAPIをさらに追加
+-- Ethna_ActionForm#setFormDef_ViewHelper
+- APPID_Controller.php のスケルトンに継承を想定したメソッドを追加
+-- skel/app.controller.php _setDefaultTemplateEngin
+- add-project 時の www 以下に出来るエントリポイントから APPID_Controller へのパスを相対パスに変更
+- ethna コマンドの挙動変更
+-- ethna help コマンドを追加
+- 指定 Action が存在しない場合い、app/action 以下を全て include する仕様を変更
+- add-project -b オプションの挙動変更
+- controller での smarty_xx_plugin の機能を削除
+
+*** bug fix
+
+- Ethna_Controller#getTemplatedir を無視してテンプレートディレクトリを決定していたバグを修正(thanks: hiko)
+-- getTemplatedirメソッドをオーバライドしても強制的にロケールが付加されていた
+-- https://sourceforge.jp/ticket/browse.php?group_id=1343&tid=15570
+- "ethna pear-local list -a" の実行結果がエラーになってしまうバグを修正
+-- https://sourceforge.jp/ticket/browse.php?group_id=1343&tid=15760
+- safe-mode が ON の際に、CacheManager_Localfile がディレクトリを生成できないので、tmp ディレクトリ直下にキャッシュファイルを作成するようにした
+-- skel/skel.app_manager.php も修正
+- APPID-ini.php が存在しない場合,またはURLが設定にない場合,デフォルトURLが HTTP_HOST で設定されていたが,末尾に / がなかったので修正
+- フォームヘルパで自動的に出力されるhiddenタグの閉じ忘れを修正(thanks: id:syachi5150)
+- ethna add-app-manager コマンドで生成されるファイル名およびクラス名が間違っていたバグを修正(thanks: id:syachi5150)
+-- https://sourceforge.jp/ticket/browse.php?group_id=1343&tid=16137
+- Validatorが出力するメッセージからフォーム名の後ろのスペースを削るように修正。(thanks: id:syachi5150)
+-- https://sourceforge.jp/ticket/browse.php?group_id=1343&tid=16336
+
+
 ** 2.5.0-preview4
 
 *** bug fix
@@ -7,6 +40,7 @@
 - フォーム定義が配列で、Ethna_ActionForm#getHiddenVars の値を Ethna_ActionForm#setAppNE した場合、クロスサイトスクリプティング脆弱性が存在するバグを修正 (thanks: shuitic)
 -- http://sourceforge.jp/ticket/browse.php?group_id=1343&tid=17332
 
+
 ** 2.5.0-preview3
 
 *** features
index 102d9d5..1121337 100644 (file)
--- a/Ethna.php
+++ b/Ethna.php
@@ -45,7 +45,7 @@ if (!defined('DIRECTORY_SEPARATOR')) {
 }
 
 /** バージョン定義 */
-define('ETHNA_VERSION', '2.5.0-preview4');
+define('ETHNA_VERSION', '2.5.0');
 
 /**
  * ダミーのエラーモード
index 3483de0..cc9907c 100644 (file)
@@ -35,7 +35,7 @@ $eh =& new Ethna_Handle();
 list($my_arg_list, $arg_list) = _Ethna_HandleGateway_SeparateArgList($arg_list);
 $r = $opt->getopt($my_arg_list, "v", array("version"));
 if (Ethna::isError($r)) {
-    usage($eh);
+    _Ethna_HandleGateway_ShowUsage();
     exit(1);
 }
 
@@ -48,16 +48,17 @@ foreach ($r[0] as $opt) {
 }
 
 if (count($arg_list) == 0) {
-    usage($eh);
+    _Ethna_HandleGateway_ShowUsage();
     exit(1);
 }
 
 $id = array_shift($arg_list);
 
 $handler =& $eh->getHandler($id);
+$handler->eh =& $eh;
 if (Ethna::isError($handler)) {
     printf("no such command: %s\n\n", $id);
-    usage($eh);
+    _Ethna_HandleGateway_ShowUsage();
     exit(1);
 }
 
@@ -73,18 +74,15 @@ if (Ethna::isError($r)) {
 }
 
 /**
- *  usage
+ *  show usage
  */
-function usage(&$eh)
+function _Ethna_HandleGateway_ShowUsage()
 {
-    $handler_list = $eh->getHandlerList();
-    printf("usage: ethna [option] [command] [args...]\n\n");
-    printf("available options are as follows:\n\n");
-    printf("  -v, --version    show version and exit\n");
-    printf("\navailable commands are as follows:\n\n");
-    foreach ($handler_list as $handler) {
-        printf("  %s -> %s\n", $handler->getId(), $handler->getDescription());
-    }
+    $message = <<<EOD
+Type 'ethna help' for usage.
+
+EOD;
+    echo $message;
 }
 
 /**
index 0f78875..04f725f 100644 (file)
 /** Ethnaインストールルートディレクトリ */
 define('ETHNA_INSTALL_BASE', dirname(dirname(__FILE__)));
 
+/** テストケースがあるディレクトリ */
+$test_dir = ETHNA_INSTALL_BASE . '/test';
+
 /** include_pathの設定(このtest runnerがあるディレクトリを追加) */
-ini_set('include_path', dirname(ETHNA_INSTALL_BASE) . PATH_SEPARATOR . ini_get('include_path'));
+ini_set('include_path', realpath(ETHNA_INSTALL_BASE . '/class') . PATH_SEPARATOR . ini_get('include_path'));
+
 
 /** Ethna関連クラスのインクルード */
-require_once 'Ethna/Ethna.php';
+require_once ETHNA_INSTALL_BASE . '/Ethna.php';
 
 /** SimpleTestのインクルード */
 require_once 'simpletest/unit_tester.php';
 require_once 'simpletest/reporter.php';
-require_once 'Ethna/test/TextDetailReporter.php';
-require_once 'Ethna/test/Ethna_UnitTestBase.php';
-
-/** テストケースがあるディレクトリ */
-$test_dir = ETHNA_INSTALL_BASE . '/test';
+require_once $test_dir . '/TextDetailReporter.php';
+require_once $test_dir . '/Ethna_UnitTestBase.php';
 
 $test = &new GroupTest('Ethna All tests');
 
index 5672ee5..5417a96 100644 (file)
@@ -1241,8 +1241,12 @@ class Ethna_ActionForm
     }
 
     /**
+     *  フォーム定義変更用、ユーザ定義ヘルパメソッド
+     *
+     *  Ethna_ActionForm#prepare() が実行される前に
      *  ユーザが動的にフォーム定義を変更したい場合に
      *  このメソッドをオーバーライドします。
+     *
      *  $this->backend も初期化済みのため、DBやセッション
      *  の値に基づいてフォーム定義を変更することができます。
      *
@@ -1254,6 +1258,26 @@ class Ethna_ActionForm
     }
 
     /**
+     *  フォーム定義変更用、ユーザ定義ヘルパメソッド
+     *
+     *  フォームヘルパを使うときに、フォーム定義を動的に
+     *  変更したい場合に、このメソッドをオーバーライドします。
+     *
+     *  以下の定義をテンプレートで行った場合に呼び出されます。
+     *  
+     *  {form ethna_action=...} (ethna_action がない場合は呼び出されません)
+     *  {form_input action=...} (action がない場合は呼び出されません)
+     *
+     *  @access public 
+     */
+    function setFormDef_ViewHelper()
+    {
+        //   TODO: デフォルト実装は Ethna_ActionClass#prepare 前に
+        //   呼び出されるものと同じ。異なる場合にオーバライドする
+        $this->setFormDef_PreHelper(); 
+    }
+
+    /**
      *  ヘルパオブジェクト(アプリケーションオブジェクト)
      *  経由でのフォーム値定義を設定する
      *
index a3dbef6..c6e7af8 100644 (file)
@@ -117,7 +117,7 @@ class Ethna_Config
 
         // デフォルト値設定
         if (isset($_SERVER['HTTP_HOST']) && isset($config['url']) == false) {
-            $config['url'] = sprintf("http://%s", $_SERVER['HTTP_HOST']);
+            $config['url'] = sprintf("http://%s/", $_SERVER['HTTP_HOST']);
         }
         if (isset($config['dsn']) == false) {
             $config['dsn'] = "";
index a7db244..5d591c4 100644 (file)
@@ -134,25 +134,6 @@ class Ethna_Controller
     /** @var    object  レンダラー */
     var $renderer = null;
 
-    /** @var    array   smarty modifier定義 */
-    var $smarty_modifier_plugin = array();
-
-    /** @var    array   smarty function定義 */
-    var $smarty_function_plugin = array();
-
-    /** @var    array   smarty block定義 */
-    var $smarty_block_plugin = array();
-
-    /** @var    array   smarty prefilter定義 */
-    var $smarty_prefilter_plugin = array();
-
-    /** @var    array   smarty postfilter定義 */
-    var $smarty_postfilter_plugin = array();
-
-    /** @var    array   smarty outputfilter定義 */
-    var $smarty_outputfilter_plugin = array();
-
-
     /** @var    array   フィルターチェイン(Ethna_Filterオブジェクトの配列) */
     var $filter_chain = array();
 
@@ -268,14 +249,14 @@ class Ethna_Controller
     }
 
     /**
-     *  アプリケーション実行後の後始末を行います。 
+     *  アプリケーション実行後の後始末を行います。
      *
-     *  @access protected 
+     *  @access protected
      */
     function end()
     {
         //  必要に応じてオーバライドして下さい。
-        $this->logger->end();    
+        $this->logger->end();
     }
 
     /**
@@ -459,7 +440,9 @@ class Ethna_Controller
         $template = $this->getDirectory('template');
 
         // 言語別ディレクトリ
-        if (file_exists($template . '/' . $this->locale)) {
+        // _getDerfaultLanguageメソッドでロケールが指定されていた場合は、
+        // テンプレートディレクトリにも自動的にそれを付加する。
+        if (!empty($this->locale)) {
             $template .= '/' . $this->locale;
         }
 
@@ -719,7 +702,7 @@ class Ethna_Controller
      *                  システムエンコーディング名,
      *                  クライアントエンコーディング名 の配列
      *                  (ロケール名は、ll_cc の形式。ll = 言語コード cc = 国コード)
-     *  @see http://www.gnu.org/software/gettext/manual/html_node/Locale-Names.html 
+     *  @see http://www.gnu.org/software/gettext/manual/html_node/Locale-Names.html
      */
     function getLanguage()
     {
@@ -1035,7 +1018,7 @@ class Ethna_Controller
                 'version'       => 'xmlrpc',
                 'encoding'      => 'utf-8'
             )
-        ); 
+        );
 
         xmlrpc_server_register_method(
             $xmlrpc_server,
@@ -1286,9 +1269,9 @@ class Ethna_Controller
      */
     function getActionRequest($action, $type = "hidden")
     {
-        $s = null; 
+        $s = null;
         if ($type == "hidden") {
-            $s = sprintf('<input type="hidden" name="action_%s" value="true">', htmlspecialchars($action, ENT_QUOTES));
+            $s = sprintf('<input type="hidden" name="action_%s" value="true" />', htmlspecialchars($action, ENT_QUOTES));
         } else if ($type == "url") {
             $s = sprintf('action_%s=true', urlencode($action));
         }
@@ -1667,7 +1650,7 @@ class Ethna_Controller
     {
         return str_replace('_', '/', $forward_name) . '.' . $this->ext['tpl'];
     }
-    
+
     /**
      *  テンプレートパス名から遷移名を取得する
      *
@@ -1734,71 +1717,8 @@ class Ethna_Controller
         if (is_object($this->renderer)) {
             return $this->renderer;
         }
-        
-        $this->renderer =& $this->class_factory->getObject('renderer');
-       
-        // {{{ for B.C.
-        if (strtolower(get_class($this->renderer)) == "ethna_renderer_smarty") {
-            // user defined modifiers
-            foreach ($this->smarty_modifier_plugin as $modifier) {
-                if (!is_array($modifier)) {
-                    $name = str_replace('smarty_modifier_', '', $modifier);
-                    $this->renderer->setPlugin($name,'modifier', $modifier);
-                } else {
-                    $this->renderer->setPlugin($modifier[1], 'modifier', $modifier);
-                }
-            }
-
-            // user defined functions
-            foreach ($this->smarty_function_plugin as $function) {
-                if (!is_array($function)) {
-                    $name = str_replace('smarty_function_', '', $function);
-                    $this->renderer->setPlugin($name, 'function', $function);
-                } else {
-                    $this->renderer->setPlugin($function[1], 'function', $function);
-                }
-            }
 
-            // user defined blocks
-            foreach ($this->smarty_block_plugin as $block) {
-                if (!is_array($block)) {
-                    $name = str_replace('smarty_block_', '', $block);
-                    $this->renderer->setPlugin($name,'block', $block);
-                } else {
-                    $this->renderer->setPlugin($block[1],'block', $block);
-                }
-            }
-
-            // user defined prefilters
-            foreach ($this->smarty_prefilter_plugin as $prefilter) {
-                if (!is_array($prefilter)) {
-                    $name = str_replace('smarty_prefilter_', '', $prefilter);
-                    $this->renderer->setPlugin($name,'prefilter', $prefilter);
-                } else {
-                    $this->renderer->setPlugin($prefilter[1],'prefilter', $prefilter);
-                }
-            }
-
-            // user defined postfilters
-            foreach ($this->smarty_postfilter_plugin as $postfilter) {
-                if (!is_array($postfilter)) {
-                    $name = str_replace('smarty_postfilter_', '', $postfilter);
-                    $this->renderer->setPlugin($name,'postfilter', $postfilter);
-                } else {
-                    $this->renderer->setPlugin($postfilter[1],'postfilter', $postfilter);
-                }
-            }
-
-            // user defined outputfilters
-            foreach ($this->smarty_outputfilter_plugin as $outputfilter) {
-                if (!is_array($outputfilter)) {
-                    $name = str_replace('smarty_outputfilter_', '', $outputfilter);
-                    $this->renderer->setPlugin($name,'outputfilter', $outputfilter);
-                } else {
-                    $this->renderer->setPlugin($outputfilter[1],'outputfilter', $outputfilter);
-                }
-            }
-        }
+        $this->renderer =& $this->class_factory->getObject('renderer');
 
         //テンプレートエンジンのデフォルトの設定
         $this->_setDefaultTemplateEngine($this->renderer);
@@ -1828,7 +1748,7 @@ class Ethna_Controller
      *                                      (ll_cc の形式。ll = 言語コード cc = 国コード)
      *  @param  string  $system_encoding    システムエンコーディング名
      *  @param  string  $client_encoding    クライアントエンコーディング(テンプレートのエンコーディングと考えれば良い)
-     *  @see    http://www.gnu.org/software/gettext/manual/html_node/Locale-Names.html 
+     *  @see    http://www.gnu.org/software/gettext/manual/html_node/Locale-Names.html
      *  @see    Ethna_Controller#_getDefaultLanguage
      */
     function _setLanguage($locale, $system_encoding = null, $client_encoding = null)
@@ -1917,8 +1837,9 @@ class Ethna_Controller
     function getManagerClassName($name)
     {
         //   アプリケーションIDと、渡された名前のはじめを大文字にして、
-        //   組み合わせたものが返される 
-        return sprintf('%s_%sManager', $this->getAppId(), ucfirst($name));
+        //   組み合わせたものが返される
+        $manager_id = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($name));
+        return sprintf('%s_%sManager', $this->getAppId(), ucfirst($manager_id));
     }
 
     /**
@@ -1933,7 +1854,7 @@ class Ethna_Controller
         //  引数のはじめの一文字目と、アンダーバー直後の
         //  1文字を必ず大文字にする。アンダーバーは削除される。
         $name = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($name));
-        
+
         //  $name に foo_bar を渡し、AppID が Hogeの場合
         //  [Appid]_FooBar が返される
         return sprintf('%s_%s', $this->getAppId(), $name);
@@ -1977,15 +1898,9 @@ class Ethna_Controller
                 include_once $action_dir . $class_path;
             } else {
                 $this->logger->log(LOG_DEBUG, 'default action file not found [%s] -> try all files', $class_path);
-                $class_path = null;
+                return;
             }
         }
-        
-        // 全ファイルインクルード
-        if (is_null($class_path)) {
-            $this->_includeDirectory($this->getActiondir());
-            return;
-        }
 
         // form_path属性チェック
         if (isset($action_obj['form_path'])) {
@@ -2118,7 +2033,7 @@ class Ethna_Controller
 
     /**
      *  DSNのアクセス分岐を行う
-     *  
+     *
      *  スレーブサーバへの振分け処理(デフォルト:ランダム)を変更したい場合はこのメソッドをオーバーライドする
      *
      *  @access protected
@@ -2136,7 +2051,7 @@ class Ethna_Controller
         list($usec, $sec) = explode(' ', microtime());
         mt_srand($sec + ((float) $usec * 100000));
         $n = mt_rand(0, count($dsn_list)-1);
-        
+
         return $dsn_list[$n];
     }
 
@@ -2154,7 +2069,7 @@ class Ethna_Controller
         }
 
         require_once ETHNA_BASE . '/class/Ethna_InfoManager.php';
-        
+
         // see if we have simpletest
         if (file_exists_ex('simpletest/unit_tester.php', true)) {
             require_once ETHNA_BASE . '/class/Ethna_UnitTestManager.php';
@@ -2174,8 +2089,8 @@ class Ethna_Controller
             'view_name'     => 'Ethna_View_Info',
             'view_path'     => sprintf('%s/class/View/Ethna_View_Info.php', ETHNA_BASE),
         );
-        
-        
+
+
         // action設定
         $this->action['__ethna_unittest__'] = array(
             'form_name' =>  'Ethna_Form_UnitTest',
@@ -2228,7 +2143,7 @@ class Ethna_Controller
          echo "<br>";
          echo "In {$appid}-ini.php, please set as follows :<br><br>";
          echo "\$config = array ( 'debug' => true, );";
-     } 
+     }
 
     /**
      *  CLI実行中フラグを取得する
index e0b6033..3af565b 100644 (file)
@@ -228,7 +228,17 @@ class Ethna_Getopt
                  } 
 
              } else {  // オプションとして解釈されない
-                 $nonparsed_arguments[] = $arg;
+
+                 //   non-parsed なオプションに辿り着いた
+                 //   ら、それ以降の解釈を停止する
+                 //   つまり、それ以降は全て値として解釈する
+                 //
+                 //   これは POSIX_CORRECT な実装であって
+                 //   GNU Getopt な実装ではないが、実際に
+                 //   Console_Getopt で行われている以上、
+                 //   それに従った実装
+                 $nonparsed_arguments = array_slice($args, $pos);
+                 break;
              }
         }
   
index b6970f0..3aa4964 100644 (file)
@@ -145,29 +145,40 @@ class Ethna_ViewClass
      *  helperアクションフォームオブジェクトを設定する
      *
      *  @param  string $action アクション名
+     *  @param  boolean $dynamic_helper 動的フォームヘルパを呼ぶか否か
      *  @access public
      */
-    function addActionFormHelper($action)
+    function addActionFormHelper($action, $dynamic_helper = false)
     {
+        //
+        //  既に追加されている場合は処理をしない
+        //
         if (isset($this->helper_action_form[$action])
             && is_object($this->helper_action_form[$action])) {
             return;
         }
 
+        //    現在のアクションと等しければ、対応する
+        //    アクションフォームを設定
         $ctl =& Ethna_Controller::getInstance();
         if ($action === $ctl->getCurrentActionName()) {
             $this->helper_action_form[$action] =& $this->af;
-            return;
+        } else {
+            //    アクションが異なる場合
+            $form_name = $ctl->getActionFormName($action);
+            if ($form_name === null) {
+                $this->logger->log(LOG_WARNING,
+                    'action form for the action [%s] not found.', $action);
+                return;
+            }
+            $this->helper_action_form[$action] =& new $form_name($ctl);
         }
 
-        $form_name = $ctl->getActionFormName($action);
-        if ($form_name === null) {
-            $this->logger->log(LOG_WARNING,
-                'action form for the action [%s] not found.', $action);
-            return;
+        //   動的フォームを設定するためのヘルパメソッドを呼ぶ
+        if ($dynamic_helper) {
+            $af =& $this->helper_action_form[$action];
+            $af->setFormDef_ViewHelper();
         }
-
-        $this->helper_action_form[$action] =& new $form_name($ctl);
     }
     // }}}
 
index f0f02b8..4454469 100644 (file)
@@ -71,8 +71,6 @@ class Ethna_Plugin_Generator_Project extends Ethna_Plugin_Generator
             return $r;
         }
 
-        $basedir = sprintf("%s/%s", $basedir, $id);
-
         // ディレクトリ作成
         if (is_dir($basedir) == false) {
             // confirm
index 23d0dc2..0e80cf0 100644 (file)
@@ -39,18 +39,10 @@ class Ethna_Plugin_Generator_Template extends Ethna_Plugin_Generator
         //  ロケール名がディレクトリに含まれていない場合は、
         //  ディレクトリがないためなのでそれを補正 
         $tpl_dir = $this->ctl->getTemplatedir();
-        if (!empty($locale) && strpos($tpl_dir, $locale) === false) {
-            $tpl_dir = $this->ctl->getDirectory('template');
-            $tpl_dir .= "/$locale";
-        }
-        if ($tpl_dir{strlen($tpl_dir)-1} != '/') {
-            $tpl_dir .= '/';
-        }
         $tpl_path = $this->ctl->getDefaultForwardPath($forward_name);
 
         // entity
-        $entity = $tpl_dir . $tpl_path;
+        $entity = $tpl_dir . '/' . $tpl_path;
         Ethna_Util::mkdir(dirname($entity), 0755);
 
         // skelton
index c895f0b..ff975fd 100644 (file)
@@ -46,7 +46,7 @@ class Ethna_Plugin_Handle_AddProject extends Ethna_Plugin_Handle
         if (isset($opt_list['basedir'])) {
             $basedir = realpath(end($opt_list['basedir']));
         } else {
-            $basedir = getcwd();
+            $basedir = sprintf("%s/%s", getcwd(), strtolower($app_id));
         }
 
         // skeldir
index 9b3fe4a..b8715f1 100644 (file)
@@ -63,7 +63,7 @@ class Ethna_Plugin_Handle_AddTemplate extends Ethna_Plugin_Handle_AddView
     {
         return <<<EOS
 add new template to project:
-    {$this->id} [-b|--basedir=dir] [-s|--skelfile=file] [-l|--locale] [-e|--encoding] [template]
+    {$this->id} [-b|--basedir=dir] [-s|--skelfile=file] [-l|--locale=locale] [-e|--encoding] [template]
 
 EOS;
     }
@@ -74,7 +74,7 @@ EOS;
     function getUsage()
     {
         return <<<EOS
-ethna {$this->id} [-b|--basedir=dir] [-s|--skelfile=file] [-l|--locale] [-e|--encoding] [template]
+ethna {$this->id} [-b|--basedir=dir] [-s|--skelfile=file] [-l|--locale=locale] [-e|--encoding] [template]
 EOS;
     }
 }
diff --git a/class/Plugin/Handle/Ethna_Plugin_Handle_Help.php b/class/Plugin/Handle/Ethna_Plugin_Handle_Help.php
new file mode 100644 (file)
index 0000000..803f94e
--- /dev/null
@@ -0,0 +1,87 @@
+<?php
+// vim: foldmethod=marker
+/**
+ *  Ethna_Plugin_Handle_Help.php
+ *
+ *  @author     Tomoyuki MARUTA <maru_cc@users.sourceforge.jp>
+ *  @license    http://www.opensource.org/licenses/bsd-license.php The BSD License
+ *  @package    Ethna
+ *  @version    $Id:  $
+ */
+
+// {{{ Ethna_Plugin_Handle_Help
+/**
+ *  add-action handler
+ *
+ *  @author     ICHII Takashi <ichii386@schweetheart.jp>
+ *  @access     public
+ *  @package    Ethna
+ */
+class Ethna_Plugin_Handle_Help extends Ethna_Plugin_Handle
+{
+    /**
+     *  show help
+     *
+     *  @access public
+     */
+    function perform()
+    {
+        $r =& $this->_getopt();
+        if (Ethna::isError($r)) {
+            return $r;
+        }
+        list($opt_list, $arg_list) = $r;
+
+        // action_name
+        $handle_name = array_shift($arg_list);
+        if (!strlen($handle_name)) {
+            $handler_list = $this->eh->getHandlerList();
+            printf("usage: ethna [option] [command] [args...]\n\n");
+            printf("available options are as follows:\n\n");
+            printf("  -v, --version    show version and exit\n");
+            printf("\navailable commands are as follows:\n\n");
+            foreach ($handler_list as $handler) {
+                printf("  %s\n", $handler->getId());
+            }
+            return true;
+        }
+
+        // getHandler
+        $handler =& $this->eh->getHandler($handle_name);
+        if (Ethna::isError($handler) || $handler === false) { 
+            // command not found
+            return Ethna::raiseError('command not found.', 'usage');
+        }
+
+        echo $handler->getDescription();
+
+        return true;
+
+    }
+
+    /**
+     *  get handler's description
+     *
+     *  @access public
+     */
+    function getDescription()
+    {
+        return <<<EOS
+help:
+    {$this->id} [command_name]
+
+EOS;
+    }
+
+    /**
+     *  @access public
+     */
+    function getUsage()
+    {
+        return <<<EOS
+ethna {$this->id} [command_name]
+EOS;
+    }
+}
+// }}}
+?>
index 316c6b7..b3ae1b4 100644 (file)
@@ -32,6 +32,13 @@ function smarty_block_form($params, $content, &$smarty, &$repeat)
                 = 'default';
         }
 
+        // 動的フォームヘルパを呼ぶ
+        if (isset($params['ethna_action'])) {
+            $ethna_action = $params['ethna_action'];
+            $view =& $c->getView();
+            $view->addActionFormHelper($ethna_action, true);
+        }  
+
         // ここで返す値は出力されない
         return '';
 
index 3e8a77e..6d62936 100644 (file)
@@ -39,7 +39,7 @@ function smarty_function_form_input($params, &$smarty)
         $action = $block_params['ethna_action'];
     }
     if ($action !== null) {
-        $view->addActionFormHelper($action);
+        $view->addActionFormHelper($action, true);
     }
 
     // default
index ebe6d5e..29ef5e1 100644 (file)
@@ -13,7 +13,7 @@ define('BASE', dirname(dirname(__FILE__)));
 /** include_path setting (adding "/app" and "/lib" directory to include_path) */
 $app = BASE . "/app";
 $lib = BASE . "/lib";
-ini_set('include_path', implode(PATH_SEPARATOR, array($app, $lib)) . PATH_SEPARATOR . ini_get('include_path'));
+set_include_path(implode(PATH_SEPARATOR, array($app, $lib)) . PATH_SEPARATOR . get_include_path());
 
 
 /** including application library. */
@@ -65,7 +65,12 @@ class {$project_id}_Controller extends Ethna_Controller
          *
          *  Example:
          *
-         *  'index'     => array(),
+         *  'index'     => array(
+         *      'form_name' => 'Sample_Form_SomeAction',
+         *      'form_path' => 'Some/Action.php',
+         *      'class_name' => 'Sample_Action_SomeAction',
+         *      'class_path' => 'Some/Action.php',
+         *  ),
          */
     );
 
@@ -178,84 +183,6 @@ class {$project_id}_Controller extends Ethna_Controller
          */
     );
 
-    /**
-     *  @var    array   smarty modifier definition.
-     */
-    var $smarty_modifier_plugin = array(
-        /*
-         *  TODO: write user defined smarty modifier here.
-         *
-         *  Example:
-         *
-         *  'smarty_modifier_foo_bar',
-         */
-    );
-
-    /**
-     *  @var    array   smarty function definition.
-     */
-    var $smarty_function_plugin = array(
-        /*
-         *  TODO: write user defined smarty function here.
-         *
-         *  Example:
-         *
-         *  'smarty_function_foo_bar',
-         */
-    );
-
-    /**
-     *  @var    array   smarty block definition.
-     */
-    var $smarty_block_plugin = array(
-        /*
-         *  TODO: write user defined smarty block here.
-         *
-         *  Example:
-         * 
-         *  'smarty_block_foo_bar',
-         */
-    );
-
-    /**
-     *  @var    array   smarty prefilter definition.
-     */
-    var $smarty_prefilter_plugin = array(
-        /*
-         *  TODO: write user defined smarty prefilter here.
-         *
-         *  Example:
-         *
-         *  'smarty_prefilter_foo_bar',
-         */
-    );
-
-    /**
-     *  @var    array   smarty postfilter definition.
-     */
-    var $smarty_postfilter_plugin = array(
-        /*
-         *  TODO: write user defined smarty postfilter here.
-         *
-         *  Example:
-         *
-         *  'smarty_postfilter_foo_bar',
-         */
-    );
-
-    /**
-     *  @var    array   smarty outputfilter definition.
-     */
-    var $smarty_outputfilter_plugin = array(
-        /*
-         *  TODO: write user defined smarty outputfilter here.
-         *
-         *  Example:
-         *
-         *  'smarty_outputfilter_foo_bar',
-         */
-    );
-
     /**#@-*/
 
     /**
@@ -272,6 +199,17 @@ class {$project_id}_Controller extends Ethna_Controller
     {
         return array('{$locale}', 'UTF-8', '{$client_enc}');
     }
+
+    /**
+     *  テンプレートエンジンのデフォルト状態を設定する
+     *
+     *  @access protected
+     *  @param  object  Ethna_Renderer  レンダラオブジェクト
+     *  @obsolete
+     */
+    function _setDefaultTemplateEngine(&$renderer)
+    {
+    }
 }
 
 ?>
index c8a806a..91a7fe2 100644 (file)
@@ -20,8 +20,8 @@
 "Please input {form} properly." = "{form}を正しく入力してください"
 "Please input {form}." = "{form}を入力して下さい"
 "Please select {form}." = "{form}を選択して下さい"
-"{form} was not selected." = "{form} が選択されていません"
-"no input to {form}." = "{form} が入力されていません"
+"{form} was not selected." = "{form}が選択されていません"
+"no input to {form}." = "{form}が入力されていません"
 "Required item of {form} was not selected." = "{form}の必要な項目が選択されていません"
 "Required item of {form} was not submitted." = "{form}の必要な項目が入力されていません"
 "Please input scalar value to {form}." = "{form}にはスカラー値を入力して下さい"
@@ -50,7 +50,7 @@
 "File was not uploaded." = "ファイルはアップロードされませんでした。"
 "Temporary folder was not found." = "テンポラリフォルダがありません。"
 "Could not write uploaded file to disk." = "ディスクへの書き込みに失敗しました。"
-"invalid tmp_name." = "tmp_name が不正です。"
+"invalid tmp_name." = "tmp_nameが不正です。"
 "Invalid file name." = "ファイル名が正しくありません"
 "Invalid file type." = "ファイルタイプが正しくありません。"
 "Uploaded file size must be less than %s." = "ファイルサイズは%s以下にしてください。"
index 8e09b77..d4af361 100644 (file)
@@ -8,13 +8,13 @@
  */
 
 /**
- *  {$app_manager}Manager
+ *  {$app_manager}
  *
  *  @author     {$author}
  *  @access     public
  *  @package    {$project_id}
  */
-class {$app_manager}Manager extends Ethna_AppManager
+class {$app_manager} extends Ethna_AppManager
 {
 }
 ?>
index c968fd1..f5f69ab 100644 (file)
@@ -1,5 +1,5 @@
 <?php
-require_once '{$basedir}/app/{$project_id}_Controller.php';
+require_once dirname(__FILE__) . '/../app/{$project_id}_Controller.php';
 
 {$project_id}_Controller::main('{$project_id}_Controller', 'index');
 ?>
index 57e5f1c..dcc668f 100644 (file)
@@ -1,5 +1,5 @@
 <?php
-require_once '{$basedir}/app/{$project_id}_Controller.php';
+require_once dirname(__FILE__) . '/../app/{$project_id}_Controller.php';
 
 {$project_id}_Controller::main('{$project_id}_Controller', array(
     '__ethna_info__',
index a401a64..6a245bb 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 error_reporting(E_ALL);
-require_once '{$basedir}/app/{$project_id}_Controller.php';
+require_once dirname(__FILE__) . '/../app/{$project_id}_Controller.php';
 
 {$project_id}_Controller::main('{$project_id}_Controller', array(
     '__ethna_unittest__',
index c1ddf9e..0d345ac 100644 (file)
@@ -181,14 +181,13 @@ class Ethna_Getopt_Test extends Ethna_UnitTestBase
         $parsed_arg = array_shift($r);
         $this->assertEqual('a', $parsed_arg[0][0]);
         $this->assertNULL($parsed_arg[0][1]);
-        $this->assertEqual('c', $parsed_arg[1][0]);
-        $this->assertEqual('d', $parsed_arg[1][1]);
-        $this->assertEqual('e', $parsed_arg[2][0]);
-        $this->assertNULL($parsed_arg[2][1]);
  
         $nonparsed_arg = array_shift($r);
         $this->assertEqual('b', $nonparsed_arg[0]);
-        $this->assertEqual('f', $nonparsed_arg[1]);
+        $this->assertEqual('-c', $nonparsed_arg[1]);
+        $this->assertEqual('d', $nonparsed_arg[2]);
+        $this->assertEqual('-e', $nonparsed_arg[3]);
+        $this->assertEqual('f', $nonparsed_arg[4]);
     }
 
     function test_shortopt_complex()
@@ -196,7 +195,7 @@ class Ethna_Getopt_Test extends Ethna_UnitTestBase
         //  complex option part 1.
         $args = array();
         $shortopt = 'ab:c::';
-        $args = array('-abc', '-cd');
+        $args = array('-abcd', '-cd');
         $r = $this->opt->getopt($args, $shortopt);
         $this->assertFalse(Ethna::isError($r));
 
@@ -205,7 +204,7 @@ class Ethna_Getopt_Test extends Ethna_UnitTestBase
         $this->assertNULL($parsed_arg[0][1]);
 
         $this->assertEqual('b', $parsed_arg[1][0]);
-        $this->assertEqual('c', $parsed_arg[1][1]);
+        $this->assertEqual('cd', $parsed_arg[1][1]);
 
         $this->assertEqual('c', $parsed_arg[2][0]);
         $this->assertEqual('d', $parsed_arg[2][1]);
@@ -289,8 +288,8 @@ class Ethna_Getopt_Test extends Ethna_UnitTestBase
         $nonparsed_arg = array_shift($r);
         $this->assertEqual('hoge', $nonparsed_arg[0]);
  
-        // --foo option value is bar. hoge is nonparsed.
-        $args = array('--foo', 'bar', 'hoge');
+        // --foo option value is bar. hoge, -fuga is nonparsed.
+        $args = array('--foo', 'bar', 'hoge', '-fuga');
         $shortopt = NULL;
         $longopt = array("foo=");
         $r = $this->opt->getopt($args, $shortopt, $longopt);
@@ -302,6 +301,7 @@ class Ethna_Getopt_Test extends Ethna_UnitTestBase
 
         $nonparsed_arg = array_shift($r);
         $this->assertEqual('hoge', $nonparsed_arg[0]);
+        $this->assertEqual('-fuga', $nonparsed_arg[1]);
     }
 
     function test_longopt_optional()
@@ -417,12 +417,11 @@ class Ethna_Getopt_Test extends Ethna_UnitTestBase
         $this->assertEqual('bar', $parsed_arg[1][1]);
         $this->assertequal('--bar', $parsed_arg[2][0]);
         $this->assertEqual('moge', $parsed_arg[2][1]);
-        $this->assertequal('--hoge', $parsed_arg[3][0]);
-        $this->assertNULL($parsed_arg[3][1]);
 
 
         $nonparsed_arg = array_shift($r);
         $this->assertEqual('hoge', $nonparsed_arg[0]);
+        $this->assertEqual('--hoge', $nonparsed_arg[1]);
     }
     // }}}
 }
index 593986c..2cd797f 100644 (file)
@@ -65,7 +65,7 @@ class Ethna_MockProject
         $id = 'add-project';
         $options = array(
                        '-b',
-                       $this->basedir,
+                       $this->basedir . '/' . $this->project_name,
                        '-s',
                        $this->skel_dir, 
                        $this->project_name,
@@ -104,8 +104,8 @@ class Ethna_MockProject
             }
         }
         if (!$in_basedir_opt) { 
-            $options[] = '-b';
-            $options[] = $this->proj_basedir;
+            $base_opt = array('-b', $this->proj_basedir);
+            $options = array_merge($base_opt, $options);
         }
 
         $eh =& new Ethna_Handle();
index 18a932d..df2b32c 100644 (file)
@@ -6,8 +6,6 @@
  *  @author halt feits <halt.feits@gmail.com>
  */
 
-//error_reporting(E_ALL);
-
 /**
  *  Ethna_ViewClassクラスのテストケース
  *
diff --git a/test/Plugin/Handle/Ethna_Plugin_Handle_AddTemplate_Test.php b/test/Plugin/Handle/Ethna_Plugin_Handle_AddTemplate_Test.php
new file mode 100644 (file)
index 0000000..e0eabd7
--- /dev/null
@@ -0,0 +1,93 @@
+<?php
+// vim: foldmethod=marker
+/**
+ *  Ethna_Plugin_Handle_AddTemplate_Test.php
+ *
+ *  @author     Yoshinari Takaoka <takaoka@beatcraft.com>
+ *  @version    $Id$
+ */
+
+require_once ETHNA_BASE . '/test/Ethna_MockProject.php';
+
+//{{{  Ethna_Plugin_Handle_AddTemplate_Test
+/**
+ *  Test Case For Ethna_Plugin_Handle_AddTemplate_Test
+ *
+ *  @access public
+ */
+class Ethna_Plugin_Handle_AddTemplate_Test extends Ethna_UnitTestBase 
+{
+    var $proj;
+
+    function setUp()
+    {
+        $this->proj = new Ethna_MockProject();
+        $r = $this->proj->create();
+        if (Ethna::isError($r)) {
+            $this->fail($r->getMessage());    
+        }
+    }
+
+    function tearDown()
+    {
+        $this->proj->delete();
+    }
+
+    function test_template_dir_exists()
+    {
+        $ctl =& $this->proj->getController(); 
+
+        //    default locale 
+        $r = $this->proj->runCmd('add-template', array('test'));
+        $template_dir = $ctl->getTemplatedir();
+        $this->assertTrue(file_exists($template_dir));
+
+        //    new locale 
+        $r = $this->proj->runCmd('add-template', array('-l', 'en_US', 'test'));
+        $template_dir = $ctl->getTemplatedir();
+        $this->assertTrue(file_exists($template_dir));
+    }
+
+    function test_cmd_option()
+    {
+        //    unrecognized option
+        $r = $this->proj->runCmd('add-template', array('-k'));
+        $this->assertTrue(Ethna::isError($r));
+        $this->assertEqual('unrecognized option -k', $r->getMessage());
+
+        //    skel requires an argument
+        $r = $this->proj->runCmd('add-template', array('-s'));
+        $this->assertTrue(Ethna::isError($r));
+        $this->assertEqual('option -s requires an argument', $r->getMessage());
+
+        $r = $this->proj->runCmd('add-template', array('--skelfile'));
+        $this->assertTrue(Ethna::isError($r));
+        $this->assertEqual('option --skelfile requires an argument', $r->getMessage());
+
+        //    locale requires an argument
+        $r = $this->proj->runCmd('add-template', array('-l'));
+        $this->assertTrue(Ethna::isError($r));
+        $this->assertEqual('option -l requires an argument', $r->getMessage());
+
+        $r = $this->proj->runCmd('add-template', array('--locale'));
+        $this->assertTrue(Ethna::isError($r));
+        $this->assertEqual('option --locale requires an argument', $r->getMessage());
+
+        //    template name isn't set
+        $r = $this->proj->runCmd('add-template', array());
+        $this->assertTrue(Ethna::isError($r));
+        $this->assertEqual('template name isn\'t set.', $r->getMessage());
+
+        //    invalid locale
+        $r = $this->proj->runCmd('add-template', array('-l', 'invalid::locale', 'test'));
+        $this->assertTrue(Ethna::isError($r));
+        $this->assertEqual('You specified locale, but invalid : invalid::locale', $r->getMessage());
+
+        //    normal command exexute
+        $r = $this->proj->runCmd('add-template', array('-l', 'ja_JP', 'test'));
+        $this->assertFalse(Ethna::isError($r));
+    }
+}
+// }}}
+
+?>
index 9179cf2..96d1bb8 100644 (file)
@@ -124,6 +124,44 @@ class Ethna_Plugin_Handle_I18n_Test extends Ethna_UnitTestBase
         $this->assertTrue(isset($catalog['template i18n multiple modifier']));
     } 
 
+    function test_cmd_option()
+    {
+        //    unrecognized option
+        $r = $this->proj->runCmd('i18n', array('-k'));
+        $this->assertTrue(Ethna::isError($r));
+        $this->assertEqual('unrecognized option -k', $r->getMessage());
+
+        //    --locale(requires an argument)
+        $r = $this->proj->runCmd('i18n', array('-l'));
+        $this->assertTrue(Ethna::isError($r));
+        $this->assertEqual('option -l requires an argument', $r->getMessage());
+
+        $r = $this->proj->runCmd('i18n', array('-l', 'ko_KR'));
+        $this->assertFalse(Ethna::isError($r));
+        
+        $r = $this->proj->runCmd('i18n', array('--locale'));
+        $this->assertTrue(Ethna::isError($r));
+        $this->assertEqual('option --locale requires an argument', $r->getMessage());
+
+        //    --gettext option only
+        $r = $this->proj->runCmd('i18n', array('-g'));
+        $this->assertFalse(Ethna::isError($r));
+
+        $r = $this->proj->runCmd('i18n', array('--gettext'));
+        $this->assertFalse(Ethna::isError($r));
+
+        //    --gettext not allowed an argument 
+        $r = $this->proj->runCmd('i18n', array('--gettext=foo'));
+        $this->assertTrue(Ethna::isError($r));
+        $this->assertEqual("option --gettext doesn't allow an argument", $r->getMessage());
+
+        //    --locale and --gettext mixin
+        $r = $this->proj->runCmd('i18n', array('-g', '-l', 'ko_KR'));
+        $this->assertFalse(Ethna::isError($r));
+
+        $r = $this->proj->runCmd('i18n', array('--gettext', '--locale=ko_KR'));
+        $this->assertFalse(Ethna::isError($r));
+    }
    
     function run_i18n_cmd()
     {
@@ -133,6 +171,8 @@ class Ethna_Plugin_Handle_I18n_Test extends Ethna_UnitTestBase
             return;
         }
     } 
+
+
 }
 // }}}
 
diff --git a/test/Plugin/Handle/Ethna_Plugin_Handle_PearLocal_Test.php b/test/Plugin/Handle/Ethna_Plugin_Handle_PearLocal_Test.php
new file mode 100644 (file)
index 0000000..29e682c
--- /dev/null
@@ -0,0 +1,64 @@
+<?php
+// vim: foldmethod=marker
+/**
+ *  Ethna_Plugin_Handle_PearLocal_Test.php
+ *
+ *  @author     Yoshinari Takaoka <takaoka@beatcraft.com>
+ *  @version    $Id$
+ */
+
+require_once ETHNA_BASE . '/test/Ethna_MockProject.php';
+
+//{{{  Ethna_Plugin_Handle_PearLocal_Test
+/**
+ *  Test Case For Ethna_Plugin_Handle_PearLocal_Test
+ *
+ *  @access public
+ */
+class Ethna_Plugin_Handle_PearLocal_Test extends Ethna_UnitTestBase 
+{
+    var $proj;
+
+    function setUp()
+    {
+        $this->proj = new Ethna_MockProject();
+        $r = $this->proj->create();
+        if (Ethna::isError($r)) {
+            $this->fail($r->getMessage());    
+        }
+    }
+
+    function tearDown()
+    {
+        $this->proj->delete();
+    }
+
+    function test_cmd_option()
+    {
+        //    unrecognized option
+        $r = $this->proj->runCmd('pear-local', array('-k'));
+        $this->assertTrue(Ethna::isError($r));
+        $this->assertEqual('unrecognized option -k', $r->getMessage());
+
+        //    pear list -a(get no error)
+        //    @see http://sourceforge.jp/ticket/browse.php?group_id=1343&tid=15760
+        $r = $this->proj->runCmd('pear-local', array('list', '-a'));
+        $this->assertFalse(Ethna::isError($r));
+
+        //    channel requires an argument
+        $r = $this->proj->runCmd('pear-local', array('-c'));
+        $this->assertTrue(Ethna::isError($r));
+        $this->assertEqual('option -c requires an argument', $r->getMessage());
+
+        $r = $this->proj->runCmd('pear-local', array('--channel'));
+        $this->assertTrue(Ethna::isError($r));
+        $this->assertEqual('option --channel requires an argument', $r->getMessage());
+
+        //    normal command exexute(offline only)
+        $r = $this->proj->runCmd('pear-local', array('config-set', 'default_channel', 'pear.php.net'));
+        $this->assertFalse(Ethna::isError($r));
+    }
+}
+// }}}
+
+?>
index 627150b..089c46e 100644 (file)
@@ -60,7 +60,7 @@ class TextDetailReporter extends SimpleReporter {
      */
     function paintFail($message) {
         parent::paintFail($message);
-        print $this->getFailCount() . ") $message\n";
+        print "\n\t" . $this->getFailCount() . ") $message\n";
         $breadcrumb = $this->getTestList();
         array_shift($breadcrumb);
         print "\tin " . implode("\n\tin ", array_reverse($breadcrumb));
diff --git a/test/skel/app.controller.php b/test/skel/app.controller.php
new file mode 100644 (file)
index 0000000..0c8a0ba
--- /dev/null
@@ -0,0 +1,199 @@
+<?php
+/**
+ *  {$project_id}_Controller.php
+ *
+ *  @author     {$author}
+ *  @package    {$project_id}
+ *  @version    $Id$
+ */
+
+/** Application base directory */
+define('BASE', dirname(dirname(__FILE__)));
+
+/** include_path setting (adding "/app" and "/lib" directory to include_path) */
+$app = BASE . "/app";
+$lib = BASE . "/lib";
+ini_set('include_path', implode(PATH_SEPARATOR, array($app, $lib)) . PATH_SEPARATOR . ini_get('include_path'));
+
+
+/** including application library. */
+require_once ETHNA_INSTALL_BASE . '/Ethna.php';
+require_once '{$project_id}_Error.php';
+require_once '{$project_id}_ActionClass.php';
+require_once '{$project_id}_ActionForm.php';
+require_once '{$project_id}_ViewClass.php';
+
+/**
+ *  {$project_id} application Controller definition.
+ *
+ *  @author     {$author}
+ *  @access     public
+ *  @package    {$project_id}
+ */
+class {$project_id}_Controller extends Ethna_Controller
+{
+    /**#@+
+     *  @access private
+     */
+
+    /**
+     *  @var    string  Application ID(appid)
+     */
+    var $appid = '{$application_id}';
+
+    /**
+     *  @var    array   forward definition.
+     */
+    var $forward = array(
+        /*
+         *  TODO: write forward definition here.
+         *
+         *  Example:
+         *
+         *  'index'         => array(
+         *      'view_name' => '{$project_id}_View_Index',
+         *  ),
+         */
+    );
+
+    /**
+     *  @var    array   action definition.
+     */
+    var $action = array(
+        /*
+         *  TODO: write action definition here.
+         *
+         *  Example:
+         *
+         *  'index'     => array(),
+         */
+    );
+
+    /**
+     *  @var    array   SOAP action definition.
+     */
+    var $soap_action = array(
+        /*
+         *  TODO: write action definition for SOAP application here.
+         *  Example:
+         *
+         *  'sample'            => array(),
+         */
+    );
+
+    /**
+     *  @var    array       application directory.
+     */
+    var $directory = array(
+        'action'        => 'app/action',
+        'action_cli'    => 'app/action_cli',
+        'action_xmlrpc' => 'app/action_xmlrpc',
+        'app'           => 'app',
+        'plugin'        => 'app/plugin',
+        'bin'           => 'bin',
+        'etc'           => 'etc',
+        'filter'        => 'app/filter',
+        'locale'        => 'locale',
+        'log'           => 'log',
+        'plugins'       => array('app/plugin/Smarty',),
+        'template'      => 'template',
+        'template_c'    => 'tmp',
+        'tmp'           => 'tmp',
+        'view'          => 'app/view',
+        'www'           => 'www',
+        'test'          => 'app/test',
+    );
+
+    /**
+     *  @var    array       database access definition.
+     */
+    var $db = array(
+        ''              => DB_TYPE_RW,
+    );
+
+    /**
+     *  @var    array       extention(.php, etc) configuration.
+     */
+    var $ext = array(
+        'php'           => 'php',
+        'tpl'           => 'tpl',
+    );
+
+    /**
+     *  @var    array   class definition.
+     */
+    var $class = array(
+        /*
+         *  TODO: When you override Configuration class, Logger class,
+         *        SQL class, don't forget to change definition as follows!
+         */
+        'class'         => 'Ethna_ClassFactory',
+        'backend'       => 'Ethna_Backend',
+        'config'        => 'Ethna_Config',
+        'db'            => 'Ethna_DB_PEAR',
+        'error'         => 'Ethna_ActionError',
+        'form'          => '{$project_id}_ActionForm',
+        'i18n'          => 'Ethna_I18N',
+        'logger'        => 'Ethna_Logger',
+        'plugin'        => 'Ethna_Plugin',
+        'session'       => 'Ethna_Session',
+        'sql'           => 'Ethna_AppSQL',
+        'view'          => '{$project_id}_ViewClass',
+        'renderer'      => 'Ethna_Renderer_Smarty',
+        'url_handler'   => '{$project_id}_UrlHandler',
+    );
+
+    /**
+     *  @var    array       list of application id where Ethna searches plugin.
+     */
+    var $plugin_search_appids = array(
+        /*
+         *  write list of application id where Ethna searches plugin.
+         *
+         *  Example:
+         *  When there are plugins whose name are like "Common_Plugin_Foo_Bar" in
+         *  application plugin directory, Ethna searches them in the following order.
+         *
+         *  1. Common_Plugin_Foo_Bar,
+         *  2. {$project_id}_Plugin_Foo_Bar
+         *  3. Ethna_Plugin_Foo_Bar
+         *
+         *  'Common', '{$project_id}', 'Ethna',
+         */
+        '{$project_id}', 'Ethna',
+    );
+
+    /**
+     *  @var    array       filter definition.
+     */
+    var $filter = array(
+        /*
+         *  TODO: when you use filter, write filter plugin name here.
+         *  (If you specify class name, Ethna reads filter class in 
+         *   filter directory)
+         *
+         *  Example:
+         *
+         *  'ExecutionTime',
+         */
+    );
+
+    /**#@-*/
+
+    /**
+     *  Get Default language and locale setting.
+     *  If you want to change Ethna's output encoding, override this method.
+     *
+     *  @access protected
+     *  @return array   locale name(e.x ja_JP, en_US .etc),
+     *                  system encoding name,
+     *                  client encoding name(= template encoding)
+     *                  (locale name is "ll_cc" format. ll = language code. cc = country code.)
+     */
+    function _getDefaultLanguage()
+    {
+        return array('{$locale}', 'UTF-8', '{$client_enc}');
+    }
+}
+
+?>