smarty3,PEAR::HTML_QuickForm2 のいろいろサンプル

smarty3,pear…HTML_QuickForm2の情報が、ほとんどない!
smarty2,HTML_QuickFormから、いろいろと結構変わっていて、試行錯誤したメモです。

sample_input.php

<?php
require_once("config.php");
require_once("HTML/QuickForm2.php");
require_once("HTML/QuickForm2/Renderer.php");
require_once("EXSmarty.php");

    $smarty = new ExSmarty();
  
    //以前のフォームデータがセッションにあれば取得する
    if (isset($_SESSION["data"])) {
      $data = $_SESSION["data"];
    } else {
      $data = null;
    }
      
    $form = & new HTML_QuickForm2('inputform');

    //テキスト
    $in_o_name = $form->addElement('text', 'o_name',  array('id' => 'o_name', 'maxlength'=>50, 'autocomplete'=>"o_name", 'placeholder'=>"山田花子")); 
    $in_o_kana = $form->addElement('text', 'o_kana',  array('id' => 'o_kana', 'maxlength'=>50, 'autocomplete'=>"o_kana", 'placeholder'=>"やまだはなこ")); 

    $in_d_name = $form->addElement('text', 'd_name',  array('id' => 'd_name', 'maxlength'=>50, 'autocomplete'=>"d_name", 'placeholder'=>"山田太郎")); 

    //セレクト
    $options = array('01'=>'北海道',
     '47'=>'沖縄県');
    $form->addElement(
          'select', 'o_pref_cd', array('id'=>"o_pref_cd", 'autocomplete'=>"o_pref_cd", 'class'=>"label_pref"), array('options' => $options));

    //電話番号(オリジナルtype)
    $in_o_tel = $form->addElement('tel', 'o_tel',  array('id' => 'tel', 'autocomplete'=>"tel", 'placeholder'=>"000-0000-0000"));

    //email(オリジナルtype)
    $in_o_email = $form->addElement('email', 'o_email',  array('id' => 'email', 'autocomplete'=>"email", 'placeholder'=>"hoge@hoge.com", 'maxlength'=>"100"));

    //ラジオボタン
    $in_gp_dest = $form->addGroup('dest');
    $in_gp_dest->addElement('radio', 'sel', array('value'=> 9, 'id'=>'dest_0'));  //注文者へ送る
    $in_gp_dest->addElement('radio', 'sel', array('value'=> 1, 'id'=>'dest_1'));  //注文者以外へ送る

    $in_gp_pay = $form->addGroup('pay');
    $pay_list = array('1'=>'クレジットカード', '3'=>'銀行振り込み', '5'=>'代引き');
    if (count($pay_list) > 0) {
      foreach ($pay_list as $cd=>$val) {
        $in_gp_pay->addElement('radio', 'sel', array('value'=>$cd, 'id' => 'pay_' . $cd)); 
      }
    }

    //テキストエリア
    $in_message = $form->addElement('textarea', 'msg', array('rows' => 5),
      array('id' => 'msg')
    );
    
    //チェックボックス
    $in_agree = $form->addElement('checkbox', 'agree',  array('id' => 'agree', 'value' => 1));

    //submitボタン
    $form->addSubmit('submit', array('value' => ' OK ', 'id' => 'submit'));


    //================= Filter
    $form->addRecursiveFilter('trim');
    $in_o_kana->addFilter('_filter_mb_convert_kana_cH');

    //================= Rule
    //callbackのパラメタとして渡すために、フォームデータを取得する
    //※filter適用後の値となる
    $form_data = $form->getValue();
//print_r($form_data);      

    //必須
    $in_o_name->addRule('required', 'ご注文者 お名前:入力して下さい'); 
    $in_o_kana->addRule('required', 'ご注文者 ふりがな:入力して下さい'); 
    $in_o_email->addRule('required', 'ご注文者 メールアドレス:入力して下さい');  
    
   //マルチバイト・文字数チェック
    $in_o_name->addRule('mbmaxlength', 'ご注文者 お名前:100文字までです',100); 
    $in_message->addRule('mbmaxlength', 'メッセージ:1000文字までです',1000); 

    //ひらがな/spaceのみチェック
    $in_o_kana->addRule('callback', 'お名前(かな)は、ひらがなのみで入力してください', 
          array('callback' => 'check_zen_kana_space'));
    
    //別のフィールドとの関連チェック
    $in_d_name->addRule('callback', '別のお届先:お名前を入力してください', 
          //array('callback' => 'check_dest_field','arguments' => array(array('dest' => $form_data['dest']))));
          array('callback' => 'check_dest_field','arguments' => array(array('dest' => $form_data['dest']['sel']))));

    //必須
    $in_gp_dest->addRule('required', 'お届け先を選んで下さい'); 
    
    //必須
    $in_gp_pay->addRule('required', 'お支払い方法を選択してください');
    
    //チェックボックス:必ずチェックさせたい時
    $in_agree->addRule('required', '内容確認をお願いします');

      $msg = '';
      $errors = array();
      $defaults = array();
      if ($form->isSubmitted()) {
        if ($form->validate()) {
          //チェックOK
          //次のPGへ渡す場合、値をセッションへ格納しておく
          $_SESSION["data"] = $form->getValue();

          echo "OK!";
          print_r($form->getValue());
          exit; 
        
        } else {
          //validate()後のErrorを取得する
          foreach (new RecursiveIteratorIterator($form->getIterator(), RecursiveIteratorIterator::SELF_FIRST) as $item) {
            if (strlen($item->getError()) > 0) {
              $errors[$item->getName()] = $item->getError();
            }
          }
        }
      } else {
        //初期表示:デフォルト値をセットする
        if  (is_array($data) and isset($data)) {
          $defaults = $data;
        } else {
          $defaults = array("o_pref_cd" => 47,
              "dest" => array('sel'=> 9),
              "agree" => 0
          );
        }
      }
//print_r($defaults);
      
      //Smarty
      $form->addDataSource(new HTML_QuickForm2_DataSource_Array($defaults));
      
      HTML_QuickForm2_Renderer::register('smarty','HTML_QuickForm2_Renderer_Smarty');
      $renderer = HTML_QuickForm2_Renderer::factory('smarty');
      $FormData = $form->render($renderer)->toArray();
      $smarty->assign('form', $FormData);
//print_r($FormData);     
     
      $smarty->assign('pay_list', $pay_list);

      //エラー情報
      $smarty->assign('errors', $errors);

     $smarty->display("test/sample_input.tpl.html");


function check_dest_field($owner_field, $fields){
  if ($fields["dest"] == 1) { //注文者以外の新住所へ送る時
    if (strlen(trim($owner_field)) <= 0) {
      return False;
    }
  }
  return True;
}

//全角かな+空白のみか? チェック
function check_zen_kana_space($p_field) {
  return preg_match("/^[ ぁ-ん ]+$/u", $p_field);
}

// c : 「全角カタカナ」を「全角ひらがな」 
// H : 「半角カタカナ」を「全角ひらがな」
function _filter_mb_convert_kana_cH($p_word) {
  return mb_convert_kana($p_word, "cH");
}

?>

ExSmarty.php

<?php
//require_once("config.php"); //独自のconfigファイル
require_once("Smarty.class.php");

class ExSmarty extends Smarty {

  public function __construct() {
    parent::__construct();
    
    //各パスを設定する
    //  複数の場合はarray()指定可能
    $this->setTemplateDir(
      array("/hoge/templates/", "/hogehoge/templates/"));
    $this->setCompileDir(/hoge/templates_c/);
    $this->setCacheDir(/hoge/cache/);

    //効かなかった…
    //$this->setPluginsDir(
    //  array(/hoge/plugins/, /hogehoge/plugins/));

    //output filter
    $this->registerFilter("output", "change_src_path");

    //plugin
    $this->registerPlugin("function", "bc_show_login_name", "smarty_bc_show_login_name");
  }
}

//output filter
// <img> src="..."の前に、所定のサイトURLを付加する
function change_src_path($tpl_output, $smarty) {
    $add =  "http://hoge.com/";
    $tpl_output = preg_replace('/(<img[\s]+[^>]*?src=\"\/["\']?)/i', "$1$add", $tpl_output) ;
    $tpl_output = str_replace(array(' src="/http://',' src="/https://'), array(' src="http://',' src="https://'), $tpl_output);
  return $tpl_output;
}

//pluginと
//セッションに保存した名前があれば出力する
//なければ「ゲスト」を出力する
function smarty_bc_show_login_name($param, &$smarty) {
  $smarty->cache_lifetime = 0;
  $_name = $_SESSION["name"];
  if (strlen($_name) <= 0) {
    $_name = "ゲスト";
  }
  echo $_name;
}

?>

sample_input.tpl.html

<html>
<head>
<title>注文情報入力</title>
<style type="text/css">
.error {
font-size: 91%;
color:red;
}
</style>
</head>
<body>
<h1>注文情報入力</h1>

<form {$form.attributes}>
{if ($form.hidden)}
  {foreach from=$form.hidden item=item}
    {$item}
  {/foreach}
 {/if}
 

{if count($errors) > 0}
{foreach from=$errors key=key item=error} 
  <div class="error">{*$key}:*}{$error}</div>
{/foreach}
{/if}

<h2>注文者情報</h2>

<p><label for="o_name">お名前</label>
{$form.o_name.html}</p>
{if isset($errors['o_name'])}<p class="error">{$errors['o_name']}</p>{/if}

<p><label for="o_kana"> (ふりがな) </label>
{$form.o_kana.html}</p>
{if isset($errors['o_kana'])}<p class="error">{$errors['o_kana']}</p>{/if}

<p><label for="o_pref"> 都道府県 </label>
{$form.o_pref_cd.html}</p>

<p><label for="tel"> 電話番号</label>
{$form.o_tel.html}</p>
{if isset($errors['o_tel'])}<p class="error">{$errors['o_tel']}</p>{/if}
        
<p><label for="email"> メールアドレス</label>
{$form.o_email.html}</p>
{if isset($errors['o_email'])}<p class="error">{$errors['o_email']}</p>{/if}
        
<h2>お届け先</h2>
<p><label>
{$form.dest.sel.elements[9].html}
注文者情報と同じ </label>
<label>
{$form.dest.sel.elements[1].html}
別のお届け先 </label></p>
{if isset($errors['dest'])}<p class="error">{$errors['dest']}</p>{/if}

<p><label for="d_name">お名前</label>
{$form.d_name.html}</p>
{if isset($errors['d_name'])}<p class="error">{$errors['d_name']}</p>{/if}

<h2>お支払い方法</h2>
<p><label>
{$form.pay.sel.elements[1].html}
{$pay_list[1]} <small>VISA,MASTER,AMEX</small> </label></p>
<p><label>
{$form.pay.sel.elements[3].html}
{$pay_list[3]} <small>XX銀行 XX支店</small></label></p>
<p><label>
{$form.pay.sel.elements[5].html}
{$pay_list[5]} </label></p>
{if isset($errors['pay'])}<p class="error">{$errors['pay']}</p>{/if}

<h2>ご注文について</h2>
<p><label>
{$form.agree.html}
確認しました</label></p>
{if isset($errors['agree'])}<p class="error">{$errors['agree']}</p>{/if}

<p>{$form.submit.html}</p>
</form>
</body>
</html>

※input tel,email、はオリジナルのelementとして作成。
 mbmaxlength(マルチバイト文字数チェック)は、オリジナルのルールとして作成。
 いずれも、後日、UP予定。

生成htmlソース

<html>
<head>
<title>注文情報入力</title>
<style type="text/css">
.error {
font-size: 91%;
color:red;
}
</style>
</head>
<body>
<h1>注文情報入力</h1>


<form  method="post" id="inputform" action="/ap/p/test/sample_input.php">
      <input type="hidden" id="qf:inputform" name="_qf__inputform" />
  
  


<h2>注文者様情報</h2>

<p><label for="o_name">お名前</label>
  <input type="text" id="o_name" maxlength="50" autocomplete="o_name" placeholder="山田花子" name="o_name" /></p>
<p><label for="o_kana"> (ふりがな) </label>
  <input type="text" id="o_kana" maxlength="50" autocomplete="o_kana" placeholder="やまだはなこ" name="o_kana" /></p>

<p><label for="o_pref"> 都道府県 </label>
  <select id="o_pref_cd" autocomplete="o_pref_cd" class="label_pref" name="o_pref_cd">
  <option value="01">北海道</option>
  <option value="47" selected="selected">沖縄県</option>
  </select></p>

<p><label for="tel"> 電話番号</label>
  <input type="tel" id="tel" autocomplete="tel" placeholder="000-0000-0000" name="o_tel" /></p>
        
<p><label for="email"> メールアドレス</label>
  <input type="email" id="email" autocomplete="email" placeholder="hoge@hoge.com" maxlength="100" name="o_email" /></p>

<h2>お届け先</h2>
<p><label>
  <input type="radio" value="9" id="dest_0" name="dest[sel]" checked="checked" />
  注文者情報と同じ </label>
<label>
  <input type="radio" value="1" id="dest_1" name="dest[sel]" />
  別のお届け先 </label></p>

<p><label for="d_name">お名前</label>
  <input type="text" id="d_name" maxlength="50" autocomplete="d_name" placeholder="山田太郎" name="d_name" /></p>

<h2>お支払い方法</h2>
<p><label>
  <input type="radio" value="1" id="pay_1" name="pay[sel]" />
  クレジットカード <small>VISA,MASTER,AMEX</small> </label></p>
<p><label>
  <input type="radio" value="3" id="pay_3" name="pay[sel]" />
  銀行振り込み <small>XX銀行 XX支店</small></label></p>
<p><label>
  <input type="radio" value="5" id="pay_5" name="pay[sel]" />
  代引き </label></p>

<h2>ご注文について</h2>
<p><label>
  <input type="checkbox" id="agree" value="1" name="agree" />
  確認しました</label></p>

<p><input type="submit" id="submit" value=" OK " name="submit" /></p>
</form>
</body>
</html>