OSDN Git Service

Remove PHP closing tag
[ethna/ethna.git] / class / Ethna_ViewClass.php
1 <?php
2 // vim: foldmethod=marker
3 /**
4  *  Ethna_ViewClass.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_ViewClass
13 /**
14  *  viewクラス
15  *
16  *  @author     Masaki Fujimoto <fujimoto@php.net>
17  *  @access     public
18  *  @package    Ethna
19  */
20 class Ethna_ViewClass
21 {
22     /**#@+
23      *  @access private
24      */
25
26     /** @var    object  Ethna_Controller    Controllerオブジェクト */
27     var $ctl;
28
29     /** @var    object  Ethna_Backend       backendオブジェクト */
30     var $backend;
31
32     /** @var    object  Ethna_Config        設定オブジェクト    */
33     var $config;
34
35     /** @var    object  Ethna_I18N          i18nオブジェクト */
36     var $i18n;
37
38     /** @var    object  Ethna_Logger    ログオブジェクト */
39     var $logger;
40
41     /** @var    object  Ethna_Plugin    プラグインオブジェクト */
42     var $plugin;
43
44     /** @var    object  Ethna_ActionError   アクションエラーオブジェクト */
45     var $action_error;
46
47     /** @var    object  Ethna_ActionError   アクションエラーオブジェクト(省略形) */
48     var $ae;
49
50     /** @var    object  Ethna_ActionForm    アクションフォームオブジェクト */
51     var $action_form;
52
53     /** @var    object  Ethna_ActionForm    アクションフォームオブジェクト(省略形) */
54     var $af;
55
56     /** @var    array   アクションフォームオブジェクト(helper) */
57     var $helper_action_form = array();
58
59     /** @var    array   helperでhtmlのattributeにはしないパラメータの一覧 */
60     var $helper_parameter_keys = array('default', 'option', 'separator');
61
62     /** @var    object  Ethna_Session       セッションオブジェクト */
63     var $session;
64
65     /** @var    string  遷移名 */
66     var $forward_name;
67
68     /** @var    string  遷移先テンプレートファイル名 */
69     var $forward_path;
70
71     /** @var    boolean  配列フォームを呼んだカウンタをリセットするか否か */
72     var $reset_counter = false;
73
74     /**#@-*/
75
76     /**#@+
77      *  @access protected
78      */
79
80     /** @var  string レイアウト(HTMLの外枠を記述するファイル)のテンプレートファイルを指定(拡張子は除く)   */
81     var $_layout_file = 'layout';
82
83     /**#@-*/
84
85     /**#@+
86      *  @access public
87      */
88
89     /** @var boolean  レイアウトテンプレートの使用フラグ       */
90     var $use_layout = true;
91
92     /** @var  boolean  デフォルトのヘッダ出力を使用するか否か  */
93     /**                ヘッダ出力を改造する場合はfalseにする   */
94     var $has_default_header = true;
95
96     /** @var  array    デフォルトのヘッダ出力を使用するか否か  */
97     /**                ヘッダ出力を改造する場合はfalseにする   */
98     var $default_header = array(
99         'Pragma' => 'no-cache',
100         'Cache-Control' => 'no-cache, no-store, must-revalidate',
101     );
102
103     // {{{ Ethna_ViewClass
104     /**
105      *  Ethna_ViewClassのコンストラクタ
106      *
107      *  @access public
108      *  @param  object  Ethna_Backend   $backend    backendオブジェクト
109      *  @param  string  $forward_name   ビューに関連付けられている遷移名
110      *  @param  string  $forward_path   ビューに関連付けられているテンプレートファイル名
111      */
112     function Ethna_ViewClass(&$backend, $forward_name, $forward_path)
113     {
114         $c =& $backend->getController();
115         $this->ctl =& $c;
116         $this->backend =& $backend;
117         $this->config =& $this->backend->getConfig();
118         $this->i18n =& $this->backend->getI18N();
119         $this->logger =& $this->backend->getLogger();
120         $this->plugin =& $this->backend->getPlugin();
121
122         $this->action_error =& $this->backend->getActionError();
123         $this->ae =& $this->action_error;
124
125         $this->action_form =& $this->backend->getActionForm();
126         $this->af =& $this->action_form;
127
128         $this->session =& $this->backend->getSession();
129
130         $this->forward_name = $forward_name;
131         $this->forward_path = $forward_path;
132
133         foreach (array_keys($this->helper_action_form) as $action) {
134             $this->addActionFormHelper($action);
135         }
136     }
137     // }}}
138
139     // {{{ preforward
140     /**
141      *  画面表示前処理
142      *
143      *  テンプレートに設定する値でコンテキストに依存しないものは
144      *  ここで設定する(例:セレクトボックス等)
145      *
146      *  @access public
147      *  @param  mixed  $params  アクションクラスから返された引数 
148      *                          array('forward_name', $param) の形でアクション
149      *                          から値を返すことで、$params に値が渡されます。
150      */
151     function preforward($params = NULL)
152     {
153     }
154     // }}}
155
156     // {{{ forward
157     /**
158      *  遷移名に対応する画面を出力する
159      *
160      *  特殊な画面を表示する場合を除いて特にオーバーライドする必要は無い
161      *  (preforward()のみオーバーライドすれば良い)
162      *
163      *  @access public
164      */
165     function forward()
166     {
167         $renderer =& $this->_getRenderer();
168         $this->_setDefault($renderer);
169
170         if ($this->has_default_header) {
171             $this->default_header['Content-Type'] = 'text/html; charset=' . $this->ctl->getClientEncoding();
172             $this->header($this->default_header);
173         }
174
175         // using layout.tpl flag
176         if ($this->use_layout) {
177
178             // check : layout file existance
179             $layout = $this->getLayout();
180             if ($this->templateExists($layout)) {
181                 $content = $renderer->perform($this->forward_path, true);
182
183                 if (Ethna::isError($content)) {
184                     if ($content->getCode() == E_GENERAL) {
185                         $error = 404;
186                     }
187                     else {
188                         $error = 500;
189                     }
190
191                     $this->error($error);
192                     $content = $renderer->perform($this->forward_path, true);
193                 }
194
195                 $renderer->setProp('content', $content);
196                 $renderer->perform($layout, serialize($_SERVER['REQUEST_URI']));
197             } else {
198                 return Ethna::raiseWarning('file "'.$layout.'" not found');
199             }
200         } else {
201             $renderer->perform($this->forward_path);
202         }
203     }
204     // }}}
205
206     // {{{ header
207     /**
208      *  HTTPヘッダを送信します。
209      *
210      *  @param  mixed   ヘッダを設定する値
211      *                  配列指定の場合、header => value の形式
212      *                  整数指定の場合は、HTTPステータスコード
213      *                  文字列で指定する場合は、ヘッダ出力をそのまま指定
214      *  @access public
215      */
216     function header($status)
217     {
218         if (is_array($status)) {
219             foreach ($status as $key => $status) {
220                 header ($key . ": " . $status);
221             }
222         } else if (is_int($status)) {
223             $codes = array(
224                 100 => "Continue",
225                 101 => "Switching Protocols",
226                 200 => "OK",
227                 201 => "Created",
228                 202 => "Accepted",
229                 203 => "Non-Authoritative Information",
230                 204 => "No Content",
231                 205 => "Reset Content",
232                 206 => "Partial Content",
233                 300 => "Multiple Choices",
234                 301 => "Moved Permanently",
235                 302 => "Found",
236                 303 => "See Other",
237                 304 => "Not Modified",
238                 305 => "Use Proxy",
239                 307 => "Temporary Redirect",
240                 400 => "Bad Request",
241                 401 => "Unauthorized",
242                 402 => "Payment Required",
243                 403 => "Forbidden",
244                 404 => "Not Found",
245                 405 => "Method Not Allowed",
246                 406 => "Not Acceptable",
247                 407 => "Proxy Authentication Required",
248                 408 => "Request Time-out",
249                 409 => "Conflict",
250                 410 => "Gone",
251                 411 => "Length Required",
252                 412 => "Precondition Failed",
253                 413 => "Request Entity Too Large",
254                 414 => "Request-URI Too Large",
255                 415 => "Unsupported Media Type",
256                 416 => "Requested range not satisfiable",
257                 417 => "Expectation Failed",
258                 500 => "Internal Server Error",
259                 501 => "Not Implemented",
260                 502 => "Bad Gateway",
261                 503 => "Service Unavailable",
262                 504 => "Gateway Time-out"
263             );
264
265             if (array_key_exists($status, $codes)) {
266                 header("HTTP/1.1: {$status} {$codes[$status]}");
267             }
268         } else {
269             // check valid header
270             if (preg_match("/^.+\:\s.+$/", $status)) {
271                 header($status);
272             }
273         }
274     }
275     // }}}
276
277     // {{{ redirect
278     /**
279      *  リダイレクト処理
280      *   - デフォルトのヘッダを送信しない
281      *   - レイアウトテンプレートの使用をしない
282      *
283      *  @param  string  リダイレクト先(URL)
284      *  @param  int     HTTPステータスコード (3xx)
285      *  @access public
286      */
287     function redirect($url, $staus_code = 302)
288     {
289         $this->has_default_header = false;
290         $this->use_layout = false;
291
292         $this->header($staus_code);
293         $this->header(array('Location' => $url));
294     }
295     // }}}
296
297     // {{{ setLayout
298     /**
299      *  レイアウトテンプレートのファイル名を設定します。
300      *  レイアウトテンプレートは、HTML の外枠を設定するのに使用します。
301      *  
302      *  @param string $filename  レイアウトファイル名
303      *  @access public
304      */
305     function setLayout($filename)
306     {
307         // check layout file existance
308         if ($this->templateExists($filename . '.' . $this->ctl->ext['tpl'])) {
309             $this->_layout_file = $filename;
310             return true;
311         } else {
312             return Ethna::raiseWarning('file "'. $filename . '.' . $this->ctl->ext['tpl'] . '" not found');
313         }
314     }
315     // }}}
316
317     // {{{ getLayout
318     /**
319      *  レイアウトテンプレートファイル名を取得します。
320      *  
321      *  @return string  レイアウトテンプレートのファイル名
322      *  @access public
323      */
324     function getLayout()
325     {
326         return $this->_layout_file . '.' . $this->ctl->ext['tpl'];
327     }
328     // }}}
329
330     // {{{ templateExists
331     /**
332      *  テンプレートファイルが存在するか否かを返します。
333      *
334      * @param   string  $filename  チェック対象のテンプレートファイル
335      * @access  public
336      * @return  boolean 指定したテンプレートファイルが存在すればtrue
337      *                  存在しなければfalse
338      */
339     function templateExists($filename)
340     {
341         $renderer = $this->_getRenderer();
342         if ($renderer->templateExists($filename)) {
343             return true;
344         }
345         else {
346             return false;
347         }
348     }
349     // }}}
350
351     // {{{ error 
352     /**
353      *  エラーページ出力用のHTTPステータスコードを指定します。
354      *
355      *  @param  int  HTTPステータスコード
356      *  @access public
357      */
358     function error($code)
359     {
360         $this->has_default_header = false;
361         $this->header($code);
362
363         // template 以下に error404.tpl とかがあれば, 
364         // preforward で $this->error(404); とかすればいい
365         $this->forward_path = "error{$code}.tpl";
366     }
367     // }}}
368
369     // {{{ addActionFormHelper
370     /**
371      *  helperアクションフォームオブジェクトを設定する
372      *
373      *  @param  string $action アクション名
374      *  @param  boolean $dynamic_helper 動的フォームヘルパを呼ぶか否か
375      *  @access public
376      */
377     function addActionFormHelper($action, $dynamic_helper = false)
378     {
379         //
380         //  既に追加されている場合は処理をしない
381         //
382         if (isset($this->helper_action_form[$action])
383             && is_object($this->helper_action_form[$action])) {
384             return;
385         }
386
387         //    現在のアクションと等しければ、対応する
388         //    アクションフォームを設定
389         $ctl =& Ethna_Controller::getInstance();
390         if ($action === $ctl->getCurrentActionName()) {
391             $this->helper_action_form[$action] =& $this->af;
392         } else {
393             //    アクションが異なる場合
394             $form_name = $ctl->getActionFormName($action);
395             if ($form_name === null) {
396                 $this->logger->log(LOG_WARNING,
397                     'action form for the action [%s] not found.', $action);
398                 return;
399             }
400             $this->helper_action_form[$action] =& new $form_name($ctl);
401         }
402
403         //   動的フォームを設定するためのヘルパメソッドを呼ぶ
404         if ($dynamic_helper) {
405             $af =& $this->helper_action_form[$action];
406             $af->setFormDef_ViewHelper();
407         }
408     }
409     // }}}
410
411     // {{{ clearActionFormHelper
412     /**
413      *  helperアクションフォームオブジェクトを削除する
414      *
415      *  @access public
416      */
417     function clearActionFormHelper($action)
418     {
419         unset($this->helper_action_form[$action]);
420     }
421     // }}}
422
423     // {{{ _getHelperActionForm
424     /**
425      *  アクションフォームオブジェクト(helper)を取得する
426      *  $action === null で $name が指定されているときは、$nameの定義を
427      *  含むものを探す
428      *
429      *  @access protected
430      *  @param  string  action  取得するアクション名
431      *  @param  string  name    定義されていることを期待するフォーム名
432      *  @return object  Ethna_ActionFormまたは継承オブジェクト
433      */
434     function &_getHelperActionForm($action = null, $name = null)
435     {
436         // $action が指定されている場合
437         if ($action !== null) {
438             if (isset($this->helper_action_form[$action])
439                 && is_object($this->helper_action_form[$action])) {
440                 return $this->helper_action_form[$action];
441             } else {
442                 $this->logger->log(LOG_WARNING,
443                     'helper action form for action [%s] not found',
444                     $action);
445                 return null;
446             }
447         }
448
449         // 最初に $this->af を調べる
450         $def = $this->af->getDef($name);
451         if ($def !== null) {
452             return $this->af;
453         }
454
455         // $this->helper_action_form を順に調べる
456         foreach (array_keys($this->helper_action_form) as $action) {
457             if (is_object($this->helper_action_form[$action]) === false) {
458                 continue;
459             }
460             $af =& $this->helper_action_form[$action];
461             $def = $af->getDef($name);
462             if (is_null($def) === false) {
463                 return $af;
464             }
465         }
466
467         // 見付からなかった
468         $this->logger->log(LOG_WARNING,
469             'action form defining form [%s] not found', $name);
470         return null;
471     }
472     // }}}
473
474     // {{{ resetFormCounter
475     /**
476      *  フォームヘルパ用、内部フォームカウンタをリセットする
477      *
478      *  @access public
479      */
480     function resetFormCounter()
481     {
482         $this->reset_counter = true;
483     }
484     // }}}
485
486     // {{{ getFormName
487     /**
488      *  指定されたフォーム項目に対応するフォーム名(w/ レンダリング)を取得する
489      *
490      *  @access public
491      */
492     function getFormName($name, $action, $params)
493     {
494         $af =& $this->_getHelperActionForm($action, $name);
495         if ($af === null) {
496             return $name;
497         }
498
499         $def = $af->getDef($name);
500         if ($def === null || isset($def['name']) === false) {
501             return $name;
502         }
503
504         return $def['name'];
505     }
506     // }}}
507
508     // {{{ getFormSubmit
509     /**
510      *  submitボタンを取得する(送信先アクションで受け取るよう
511      *  定義されていないときに、たんにsubmitボタンを作るのに使う)
512      *
513      *  @access public
514      */
515     function getFormSubmit($params)
516     {
517         if (isset($params['type']) === false) {
518             $params['type'] = 'submit';
519         }
520         return $this->_getFormInput_Html('input', $params);
521     }
522     // }}}
523
524     // {{{ getFormInput
525     /**
526      *  指定されたフォーム項目に対応するフォームタグを取得する
527      *
528      *  @access public
529      *  @todo   JavaScript対応
530      */
531     function getFormInput($name, $action, $params)
532     {
533         $af =& $this->_getHelperActionForm($action, $name);
534         if ($af === null) {
535             return '';
536         }
537
538         $def = $af->getDef($name);
539         if ($def === null) {
540             return '';
541         }
542
543         if (isset($def['form_type']) === false) {
544             $def['form_type'] = FORM_TYPE_TEXT;
545         }
546
547         // 配列フォームが何回呼ばれたかを保存するカウンタ
548         if (isset($def['type']) && is_array($def['type'])) {
549             static $form_counter = array();
550             if ($this->reset_counter) {
551                 $form_counter = array();
552                 $this->reset_counter = false;
553             }
554
555             if (isset($form_counter[$action]) === false) {
556                 $form_counter[$action] = array();
557             }
558             if (isset($form_counter[$action][$name]) === false) {
559                 $form_counter[$action][$name] = 0;
560             }
561             $def['_form_counter'] = $form_counter[$action][$name]++;
562         }
563
564         switch ($def['form_type']) {
565         case FORM_TYPE_BUTTON:
566             $input = $this->_getFormInput_Button($name, $def, $params);
567             break;
568
569         case FORM_TYPE_CHECKBOX:
570             $def['option'] = $this->_getSelectorOptions($af, $def, $params);
571             $input = $this->_getFormInput_Checkbox($name, $def, $params);
572             break;
573
574         case FORM_TYPE_FILE:
575             $input = $this->_getFormInput_File($name, $def, $params);
576             break;
577
578         case FORM_TYPE_HIDDEN:
579             $input = $this->_getFormInput_Hidden($name, $def, $params);
580             break;
581
582         case FORM_TYPE_PASSWORD:
583             $input = $this->_getFormInput_Password($name, $def, $params);
584             break;
585
586         case FORM_TYPE_RADIO:
587             $def['option'] = $this->_getSelectorOptions($af, $def, $params);
588             $input = $this->_getFormInput_Radio($name, $def, $params);
589             break;
590
591         case FORM_TYPE_SELECT:
592             $def['option'] = $this->_getSelectorOptions($af, $def, $params);
593             $input = $this->_getFormInput_Select($name, $def, $params);
594             break;
595
596         case FORM_TYPE_SUBMIT:
597             $input = $this->_getFormInput_Submit($name, $def, $params);
598             break;
599
600         case FORM_TYPE_TEXTAREA:
601             $input = $this->_getFormInput_Textarea($name, $def, $params);
602             break;
603
604         case FORM_TYPE_TEXT:
605         default:
606             $input = $this->_getFormInput_Text($name, $def, $params);
607             break;
608         }
609
610         return $input;
611     }
612     // }}}
613
614     // {{{ getFormBlock
615     /**
616      *  フォームタグを取得する(type="form")
617      *
618      *  @access protected
619      */
620     function getFormBlock($content, $params)
621     {
622         // method
623         if (isset($params['method']) === false) {
624             $params['method'] = 'post';
625         }
626
627         return $this->_getFormInput_Html('form', $params, $content, false);
628     }
629     // }}}
630
631     // {{{ _getSelectorOptions
632     /**
633      *  select, radio, checkbox の選択肢を取得する
634      *
635      *  @access protected
636      */
637     function _getSelectorOptions(&$af, $def, $params)
638     {
639         // $params, $def の順で調べる
640         $source = null;
641         if (isset($params['option'])) {
642             $source = $params['option'];
643         } else if (isset($def['option'])) {
644             $source = $def['option'];
645         }
646
647         // 未定義 or 定義済みの場合はそのまま
648         if ($source === null) {
649             return null;
650         } else if (is_array($source)) {
651             return $source;
652         }
653         
654         // 選択肢を取得
655         $options = null;
656         $split = array_map("trim", explode(',', $source));
657         if (count($split) === 1) {
658             // アクションフォームから取得
659             $method_or_property = $split[0];
660             if (method_exists($af, $method_or_property)) {
661                 $options = $af->$method_or_property();
662             } else {
663                 $options = $af->$method_or_property;
664             }
665         } else {
666             // マネージャから取得
667             $mgr =& $this->backend->getManager($split[0]);
668             $attr_list = $mgr->getAttrList($split[1]);
669             if (is_array($attr_list)) {
670                 foreach ($attr_list as $key => $val) {
671                     $options[$key] = $val['name'];
672                 }
673             }
674         }
675
676         if (is_array($options) === false) {
677             $this->logger->log(LOG_WARNING,
678                 'selector option is not valid. [actionform=%s, option=%s]',
679                 get_class($af), $source);
680             return null;
681         }
682
683         return $options;
684     }
685     // }}}
686
687     // {{{ _getFormInput_Button
688     /**
689      *  フォームタグを取得する(type="button")
690      *
691      *  @access protected
692      */
693     function _getFormInput_Button($name, $def, $params)
694     {
695         $params['type'] = 'button';
696         
697         if (isset($def['type'])) {
698             $params['name'] = is_array($def['type']) ? $name . '[]' : $name;
699         } else {
700             $params['name'] = $name;
701         }
702         if (isset($params['value']) === false) {
703             if (isset($def['name'])) {
704                 $params['value'] = $def['name'];
705             }
706         }
707         if (isset($params['value']) && is_array($params['value'])) {
708             $params['value'] = $params['value'][0];
709         }
710
711         return $this->_getFormInput_Html('input', $params);
712     }
713     // }}}
714
715     // {{{ _getFormInput_Checkbox
716     /**
717      *  チェックボックスタグを取得する(type="check")
718      *
719      *  @access protected
720      */
721     function _getFormInput_Checkbox($name, $def, $params)
722     {
723         $params['type'] = 'checkbox';
724         if (isset($def['type'])) {
725             $params['name'] = is_array($def['type']) ? $name . '[]' : $name;
726         } else {
727             $params['name'] = $name;
728         }
729
730         // オプションの一覧(alist)を取得
731         if (isset($def['option']) && is_array($def['option'])) {
732             $options = $def['option'];
733         } else {
734             $options = array();
735         }
736
737         // default値の設定
738         if (isset($params['default'])) {
739             $current_value = $params['default'];
740         } else if (isset($def['default'])) {
741             $current_value = $def['default'];
742         } else {
743             $current_value = array();
744         }
745         $current_value = array_map('strval', to_array($current_value));
746
747         // タグのセパレータ
748         if (isset($params['separator'])) {
749             $separator = $params['separator'];
750         } else {
751             $separator = "\n";
752         }
753
754         $ret = array();
755         $i = 1;
756         foreach ($options as $key => $value) {
757             $params['value'] = $key;
758             $params['id'] = $name . '_' . $i++;
759
760             // checked
761             if (in_array((string) $key, $current_value, true)) {
762                 $params['checked'] = 'checked';
763             } else {
764                 unset($params['checked']);
765             }
766
767             // <input type="checkbox" />
768             $input_tag = $this->_getFormInput_Html('input', $params);
769
770             // <label for="id">..</label>
771             $ret[] = $this->_getFormInput_Html('label', array('for' => $params['id']),
772                                                $input_tag . $value, false);
773         }
774
775         return implode($separator, $ret);
776     }
777     // }}}
778
779     // {{{ _getFormInput_File
780     /**
781      *  フォームタグを取得する(type="file")
782      *
783      *  @access protected
784      */
785     function _getFormInput_File($name, $def, $params)
786     {
787         $params['type'] = 'file';
788         if (isset($def['type'])) {
789             $params['name'] = is_array($def['type']) ? $name . '[]' : $name;
790         } else {
791             $params['name'] = $name;
792         }
793         $params['value'] = '';
794
795         return $this->_getFormInput_Html('input', $params);
796     }
797     // }}}
798
799     // {{{ _getFormInput_Hidden
800     /**
801      *  フォームタグを取得する(type="hidden")
802      *
803      *  @access protected
804      */
805     function _getFormInput_Hidden($name, $def, $params)
806     {
807         $params['type'] = 'hidden';
808         if (isset($def['type'])) {
809             $params['name'] = is_array($def['type']) ? $name . '[]' : $name;
810         } else {
811             $params['name'] = $name;
812         }
813
814         // value
815         $value = '';
816         if (isset($params['value'])) {
817             $value = $params['value'];
818         } else if (isset($params['default'])) {
819             $value = $params['default'];
820         } else if (isset($def['default'])) {
821             $value = $def['default'];
822         }
823         if (is_array($value)) {
824             if ($def['_form_counter'] < count($value)) {
825                 $params['value'] = $value[$def['_form_counter']];
826             } else {
827                 $params['value'] = '';
828             }
829         } else {
830             $params['value'] = $value;
831         }
832
833         return $this->_getFormInput_Html('input', $params);
834     }
835     // }}}
836
837     // {{{ _getFormInput_Password
838     /**
839      *  フォームタグを取得する(type="password")
840      *
841      *  @access protected
842      */
843     function _getFormInput_Password($name, $def, $params)
844     {
845         $params['type'] = 'password';
846         if (isset($def['type'])) {
847             $params['name'] = is_array($def['type']) ? $name . '[]' : $name;
848         } else {
849             $params['name'] = $name;
850         }
851
852         // value
853         $value = '';
854         if (isset($params['value'])) {
855             $value = $params['value'];
856         } else if (isset($params['default'])) {
857             $value = $params['default'];
858         } else if (isset($def['default'])) {
859             $value = $def['default'];
860         }
861         if (is_array($value)) {
862             if ($def['_form_counter'] < count($value)) {
863                 $params['value'] = $value[$def['_form_counter']];
864             } else {
865                 $params['value'] = '';
866             }
867         } else {
868             $params['value'] = $value;
869         }
870
871         //   maxlength と フォーム定義のmax連携はサポートしない
872         //   @see http://sourceforge.jp/ticket/browse.php?group_id=1343&tid=16325
873
874         return $this->_getFormInput_Html('input', $params);
875     }
876     // }}}
877
878     // {{{ _getFormInput_Radio
879     /**
880      *  ラジオボタンタグを取得する(type="radio")
881      *
882      *  @access protected
883      */
884     function _getFormInput_Radio($name, $def, $params)
885     {
886         $params['type'] = 'radio';
887         if (isset($def['type'])) {
888             $params['name'] = is_array($def['type']) ? $name . '[]' : $name;
889         } else {
890             $params['name'] = $name;
891         }
892
893         // オプションの一覧(alist)を取得
894         if (isset($def['option']) && is_array($def['option'])) {
895             $options = $def['option'];
896         } else {
897             $options = array();
898         }
899
900         // default値の設定
901         if (isset($params['default'])) {
902             $current_value = $params['default'];
903         } else if (isset($def['default'])) {
904             $current_value = $def['default'];
905         } else {
906             $current_value = null;
907         }
908
909         // タグのセパレータ
910         if (isset($params['separator'])) {
911             $separator = $params['separator'];
912         } else {
913             $separator = "\n";
914         }
915
916         $ret = array();
917         $i = 1;
918         foreach ($options as $key => $value) {
919             $params['value'] = $key;
920             $params['id'] = $name . '_' . $i++;
921
922             // checked
923             if (strcmp($current_value,$key) === 0) {
924                 $params['checked'] = 'checked';
925             } else {
926                 unset($params['checked']);
927             }
928
929             // <input type="radio" />
930             $input_tag = $this->_getFormInput_Html('input', $params);
931
932             // <label for="id">..</label>
933             $ret[] = $this->_getFormInput_Html('label', array('for' => $params['id']),
934                                                $input_tag . $value, false);
935         }
936
937         return implode($separator, $ret);
938     }
939     // }}}
940
941     // {{{ _getFormInput_Select
942     /**
943      *  セレクトボックスタグを取得する(type="select")
944      *
945      *  @access protected
946      */
947     function _getFormInput_Select($name, $def, $params)
948     {
949         if (isset($def['type'])) {
950             $params['name'] = is_array($def['type']) ? $name . '[]' : $name;
951         } else {
952             $params['name'] = $name;
953         }
954
955         // オプションの一覧(alist)を取得
956         if (isset($def['option']) && is_array($def['option'])) {
957             $options = $def['option'];
958         } else {
959             $options = array();
960         }
961
962         // default値の設定
963         if (isset($params['default'])) {
964             $current_value = $params['default'];
965         } else if (isset($def['default'])) {
966             $current_value = $def['default'];
967         } else {
968             $current_value = array();
969         }
970         $current_value = array_map('strval', to_array($current_value));
971
972         // タグのセパレータ
973         if (isset($params['separator'])) {
974             $separator = $params['separator'];
975         } else {
976             $separator = "\n";
977         }
978
979         // selectタグの中身を作る
980         $contents = array();
981         $selected = false;
982         foreach ($options as $key => $value) {
983             $attr = array('value' => $key);
984             $def['_form_counter'] = empty($def['_form_counter']) ? 0 : $def['_form_counter'];
985             if (isset($params['multiple']) &&
986                     in_array((string)$key, $current_value, true) ||
987                !isset($params['multiple']) && $selected === false &&
988                     strcmp($current_value[$def['_form_counter']], $key) === 0) {
989                 $attr['selected'] = 'selected';
990                 $selected = true;
991             }
992             $contents[] = $this->_getFormInput_Html('option', $attr, $value);
993         }
994
995         // 空エントリ
996         if (isset($params['emptyoption'])) {
997             $attr = array('value' => '');
998             if ($selected === false) {
999                 $attr['selected'] = 'selected';
1000             }
1001             array_unshift($contents,
1002                           $this->_getFormInput_Html('option',
1003                                                     $attr,
1004                                                     $params['emptyoption']));
1005             unset($params['emptyoption']);
1006         }
1007
1008         $element = $separator . implode($separator, $contents) . $separator;
1009         return $this->_getFormInput_Html('select', $params, $element, false);
1010     }
1011     // }}}
1012
1013     // {{{ _getFormInput_Submit
1014     /**
1015      *  フォームタグを取得する(type="submit")
1016      *
1017      *  @access protected
1018      */
1019     function _getFormInput_Submit($name, $def, $params)
1020     {
1021         $params['type'] = 'submit';
1022         if (isset($def['type'])) {
1023             $params['name'] = is_array($def['type']) ? $name . '[]' : $name;
1024         } else {
1025             $params['name'] = $name;
1026         }
1027         if (isset($params['value']) === false) {
1028             if (isset($def['name'])) {
1029                 $params['value'] = $def['name'];
1030             }
1031         }
1032         if (is_array($params['value'])) {
1033             $params['value'] = $params['value'][0];
1034         }
1035
1036         return $this->_getFormInput_Html('input', $params);
1037     }
1038     // }}}
1039
1040     // {{{ _getFormInput_Textarea
1041     /**
1042      *  フォームタグを取得する(textarea)
1043      *
1044      *  @access protected
1045      */
1046     function _getFormInput_Textarea($name, $def, $params)
1047     {
1048         if (isset($def['type'])) {
1049             $params['name'] = is_array($def['type']) ? $name . '[]' : $name;
1050         } else {
1051             $params['name'] = $name;
1052         }
1053
1054         // element
1055         $element = '';
1056         if (isset($params['value'])) {
1057             $element = $params['value'];
1058         } else if (isset($params['default'])) {
1059             $element = $params['default'];
1060         } else if (isset($def['default'])) {
1061             $element = $def['default'];
1062         }
1063         if (is_array($element)) {
1064             if ($def['_form_counter'] < count($element)) {
1065                 $element = $element[$def['_form_counter']];
1066             } else {
1067                 $element = '';
1068             }
1069         }
1070
1071         return $this->_getFormInput_Html('textarea', $params, $element);
1072     }
1073     // }}}
1074
1075     // {{{ _getFormInput_Text
1076     /**
1077      *  フォームタグを取得する(type="text")
1078      *
1079      *  @access protected
1080      */
1081     function _getFormInput_Text($name, $def, $params)
1082     {
1083         // type
1084         $params['type'] = 'text';
1085
1086         // name
1087         if (isset($def['type'])) {
1088             $params['name'] = is_array($def['type']) ? $name . '[]' : $name;
1089         } else {
1090             $params['name'] = $name;
1091         }
1092
1093         // value
1094         $value = '';
1095         if (isset($params['value'])) {
1096             $value = $params['value'];
1097         } else if (isset($params['default'])) {
1098             $value = $params['default'];
1099         } else if (isset($def['default'])) {
1100             $value = $def['default'];
1101         }
1102         if (is_array($value)) {
1103             if ($def['_form_counter'] < count($value)) {
1104                 $params['value'] = $value[$def['_form_counter']];
1105             } else {
1106                 $params['value'] = '';
1107             }
1108         } else {
1109             $params['value'] = $value;
1110         }
1111
1112         //   maxlength と フォーム定義のmax連携はサポートしない
1113         //   @see http://sourceforge.jp/ticket/browse.php?group_id=1343&tid=16325
1114
1115         return $this->_getFormInput_Html('input', $params);
1116     }
1117     // }}}
1118
1119     // {{{ _getFormInput_Html
1120     /**
1121      *  HTMLタグを取得する
1122      *
1123      *  @access protected
1124      */
1125     function _getFormInput_Html($tag, $attr, $element = null, $escape_element = true)
1126     {
1127         // 不要なパラメータは消す
1128         foreach ($this->helper_parameter_keys as $key) {
1129             unset($attr[$key]);
1130         }
1131
1132         $r = "<$tag";
1133
1134         foreach ($attr as $key => $value) {
1135             if ($value === null) {
1136                 $r .= sprintf(' %s', $key);
1137             } else {
1138                 $r .= sprintf(' %s="%s"', $key, htmlspecialchars($value, ENT_QUOTES));
1139             }
1140         }
1141
1142         if ($element === null) {
1143             $r .= ' />';
1144         } else if ($escape_element) {
1145             $r .= sprintf('>%s</%s>', htmlspecialchars($element, ENT_QUOTES), $tag);
1146         } else {
1147             $r .= sprintf('>%s</%s>', $element, $tag);
1148         }
1149
1150         return $r;
1151     }
1152     // }}}
1153
1154     // {{{ _getRenderer
1155     /**
1156      *  レンダラオブジェクトを取得する
1157      *
1158      *  @access protected
1159      *  @return object  Ethna_Renderer  レンダラオブジェクト
1160      */
1161     function &_getRenderer()
1162     {
1163         $c =& $this->backend->getController();
1164         $renderer =& $c->getRenderer();
1165
1166         $form_array =& $this->af->getArray();
1167         $app_array =& $this->af->getAppArray();
1168         $app_ne_array =& $this->af->getAppNEArray();
1169         $renderer->setPropByRef('form', $form_array);
1170         $renderer->setPropByRef('app', $app_array);
1171         $renderer->setPropByRef('app_ne', $app_ne_array);
1172         $message_list = Ethna_Util::escapeHtml($this->ae->getMessageList());
1173         $renderer->setPropByRef('errors', $message_list);
1174         if (isset($_SESSION)) {
1175             $tmp_session = Ethna_Util::escapeHtml($_SESSION);
1176             $renderer->setPropByRef('session', $tmp_session);
1177         }
1178         $renderer->setProp('script',
1179             htmlspecialchars(basename($_SERVER['SCRIPT_NAME']), ENT_QUOTES));
1180         $renderer->setProp('request_uri',
1181             isset($_SERVER['REQUEST_URI'])
1182             ? htmlspecialchars($_SERVER['REQUEST_URI'], ENT_QUOTES)
1183             : '');
1184         $renderer->setProp('config', $this->config->get());
1185
1186         return $renderer;
1187     }
1188     // }}}
1189
1190     // {{{ _setDefault
1191     /**
1192      *  共通値を設定する
1193      *
1194      *  @access protected
1195      *  @param  object  Ethna_Renderer  レンダラオブジェクト
1196      */
1197     function _setDefault(&$renderer)
1198     {
1199     }
1200     // }}}
1201 }
1202 // }}}