Curry
PHP Framework

フォーム自動生成

HtmlFormの基本

Curryには、HTMLを直接記述せずにPHPのコーディングでフォームを生成する機能が備わっています。HtmlElementクラスを利用すればどんなタグにでも対応できるため、もちろんformタグも生成できますが、専用のHtmlFormクラスを利用すると遥かに簡素なコーディングでフォーム生成が可能です。

通常、フォームは何らかのタグでレイアウトを整える事が多くなりますが、HtmlFormではこのタグによるレイアウトを自動的に組み立てる機能が備わっており、デフォルトで有効になっています。

HtmlFormの基本的な利用方法は以下の様なものです。
HtmlFormクラスはデフォルトでは読み込まれていませんので、明示的に読み込む必要があります。

Loader::load('HtmlForm', 'html');

$sexList = array('1' => '男', '2' => '女');
$prefList = array('tokyo' => '東京都', 'osaka' => '大阪府');

$form = new HtmlForm();
$form->setAction('/user/regist');
$form->addTextbox('name');
$form->addRadio('sex', $sexList);
$form->addSelect('pref', $prefList);
$form->addTextarea('address');
$form->addSubmit('regist', '登録');
$form->render();
<form method="post" action="/user/regist">
  <div class="container">
    <span class="caption"></span>
    <span class="input">
      <input type="text" name="name" />
    </span>
  </div>
  <div class="container">
    <span class="caption"></span>
    <span class="input">
      <span>
        <label><input type="radio" name="sex" value="1" />男</label>
        <label><input type="radio" name="sex" value="2" />女</label>
      </span>
    </span>
  </div>
  <div class="container">
    <span class="caption"></span>
    <span class="input">
      <select name="pref">
        <option value="tokyo">東京都</option>
        <option value="osaka">大阪府</option>
      </select>
    </span>
  </div>
  <div class="container">
    <span class="caption"></span>
    <span class="input">
      <textarea name="address"></textarea>
    </span>
  </div>
  <div class="container">
    <span class="caption"></span>
    <span class="input">
      <input type="submit" name="regist" value="登録" />
    </span>
  </div>
</form>

このように、何も意識しなくてもレイアウト整形用のタグが含まれる状態になっています。
構造としては、フォームの入力タグを直接格納するタグ、
入力タグに対する見出しを設定した場合にその見出しを直接格納するタグ、
そしてそれらを包括するコンテナタグが存在し、このコンテナタグがフォームタグの直下に存在するような形です。
以下はそのイメージです。

formタグ
  ∟div(コンテナ)
     ∟span(見出しコンテナ) 
        ∟見出しテキスト
     ∟span(フォーム入力コンテナ) 
        ∟フォーム入力タグ
  ・
  ・
  ・

それぞれのコンテナタグにはclass属性が設定されており、cssでスタイルを設定することにより、デザインは自由に設定することができます。

この簡易レイアウトを利用したくない場合は、HtmlFormのsetIsAutoLayoutメソッドでfalseを設定します。
ユーザーインターフェイスに現れるフォームではレイアウトなしでは使いものになりませんが、例えばボタン一つのみが表示されているようなフォームとか、非表示のフォームではレイアウトは意味をなさないため、レイアウトを無効にすると良いでしょう。

$form = new HtmlForm();
// レイアウトOFF
$form->setIsAutoLayout(false);

$form->setAction('/user/regist');
$form->addTextbox('name');
$form->addRadio('sex', $sexList);
$form->addSelect('pref', $prefList);
$form->addTextarea('address');
$form->addSubmit('regist', '登録');
$form->render();
<form method="post" action="/user/regist">
  <input type="text" name="name" />
  <span>
    <label><input type="radio" name="sex" value="1" />男</label>
    <label><input type="radio" name="sex" value="2" />女</label>
  </span>
  <select name="pref">
    <option value="tokyo">東京都</option>
    <option value="osaka">大阪府</option>
  </select>
  <textarea name="address"></textarea>
  <input type="submit" name="regist" value="登録" />
</form>

入力タグ追加用のメソッドは以下のとおりです。
フォーム入力タグのエレメントはHtmlElementを継承するFormElementで、HtmlElementに加えて独自の機能を持っています。
また入力タグの中でも復数の選択項目の中から選択する形式の物は更にFormElementを継承したFormElementSetです。これは基本的に復数の選択項目タグをコンテナタグに格納した形式のものです。

メソッドタグオブジェクトクラス
addTextbox input type="text" FormElement
addPassword input type="password" FormElement
addTextarea textarea FormElement
addHidden input type="hidden" FormElement
addCheckbox input type="checkbox" FormElement
addSubmit input type="submit" FormElement
addButton input type="button" FormElement
addImage input type="image" FormElement
addReset input type="reset" FormElement
addFile input type="file" FormElement
addRadio コンテナ:span
選択項目:input type="radio"
FormElementSet
addSelect コンテナ:select
選択項目:option
FormElementSet
addCheckboxes コンテナ:span
選択項目:input type="checkbox"
FormElementSet

見出しの設定

入力タグに対しては見出しを設定することが可能ですが、上の例では見出し用のタグ(class="caption"のタグ)の中身が空になっています。
これを設定するにはフォーム入力項目オブジェクトのsetCaptionメソッドを利用します。
フォーム入力項目オブジェクトはaddTextboxなどの入力項目追加メソッドの返り値として得られます。

$form = new HtmlForm();
$form->setAction('/user/regist');
$form->addTextbox('name')->setCaption('名前');
$form->addTextarea('address')->setCaption('住所');
$form->addSubmit('regist', '登録');
<form method="post" action="/user/regist">
  <div class="container">
    <div class="caption">名前</div>
    <div class="input">
      <input type="text" name="name" />
    </div>
  </div>
  <div class="container">
    <div class="caption">住所</div>
    <div class="input">
      <textarea name="address"></textarea>
    </div>
  </div>
  <div class="container">
    <div class="caption"></div>
    <div class="input">
      <input type="submit" name="regist" value="登録" />
    </div>
  </div>
</form>

簡易コンテナの設定変更

簡易コンテナのタグにはデフォルトでclass属性が設定されています。
デフォルトのクラスは入力タグのコンテナが"input"、
見出しタグのコンテナが"caption"、
それらを包括するコンテナが"container"
となっています。

これらのclass属性は任意に指定することも可能です。
以下はその設定例です。

$form = new HtmlForm();
// 入力タグのコンテナタグ
$form->setContainerTagName('dl');
// 入力タグのコンテナタグ
$form->setCaptionContainerTagName('dt');
// 見出しのコンテナタグ
$form->setInputContainerTagName('dd');
// コンテナのクラス属性
$form->setContainerClass('custom_container');
// 見出しのコンテナのクラス属性
$form->setCaptionContainerClass('custom_caption');
// 入力タグのコンテナのクラス属性
$form->setInputContainerClass('custom_input');

$form->setAction('/user/regist');
$form->addTextbox('name')->setCaption('名前');
$form->addTextarea('address')->setCaption('住所');
$form->addSubmit('regist', '登録');
<form method="post" action="/user/regist">
  <dl class="custom_container">
    <dt class="custom_caption">名前</dt>
    <dd class="custom_input">
      <input type="text" name="name" />
    </dd>
  </dl>
  <dl class="custom_container">
    <dt class="custom_caption">住所</dt>
    <dd class="custom_input">
      <textarea name="address"></textarea>
    </dd>
  </dl>
  <dl class="custom_container">
    <dt class="custom_caption"></dt>
    <dd class="custom_input">
      <input type="submit" name="regist" value="登録" />
    </dd>
  </dl>
</form>

より柔軟な利用

フォームへの入力タグの追加はadd~メソッドによって行いますが、これらのメソッドは入力タグを生成し、即座にformの要素として追加します。そして簡易レイアウトが有効になっている場合には強制的にレイアウトに組み込まれます。

add~メソッドとよく似たメソッドで、create~メソッドが存在します。これは入力タグを生成して返すだけで、フォームへの追加は行なわれません。

実はadd~メソッドで行なっているのは、内部的にcreate~メソッドにより入力タグを生成後、addFormElementメソッドでフォームへ追加しているだけです。なので、例えばaddTextboxを実行するのと、createTextboxを実行後、addFormElementでフォームへ追加するのは同じ意味になります。

以下の2つはパターンの実装は同じ結果となります。

// add~メソッドで追加
$form->addTextbox('name')->setCaption('名前');

// create~メソッドで生成後、addFormElementメソッドで追加
$textbox = $form->createTextbox('name')->setCaption('名前');
$form->addFormElement($textbox);

例えば、ある入力タグだけはレイアウトの枠にはめたくないということはあるでしょう。
レイアウトに組み込む機能を提供しているのはaddFormElementメソッドなので、create~メソッドでタグオブジェクトを生成した後、addFormElementではなく、通常のaddElementメソッドでフォームへ追加すればレイアウトタグを生成せず、formタグの直下に入力タグを配置することができます。

// add~メソッドで追加するとレイアウトに格納される
$form->addTextbox('name')->setCaption('名前');

// create~メソッドで生成後、addElementメソッドで追加するとレイアウト外となる
$textarea = $form->addTextarea('address')->setCaption('住所');
$form->addElement($textarea);
<form method="post" action="/user/regist">
  <div class="container">
    <span class="caption">名前</span>
    <span class="input">
      <input type="text" name="name" />
    </span>
  </div>
  <textarea name="address"></textarea>
</form>

カスタムレイアウト

大抵の場合は標準の簡易レイアウトで事足りますが、より柔軟なレイアウトを組むこともできます。
それにはHtmlFormのaddLayoutメソッドを利用します。
addLayoutメソッドはフォームにレイアウト用のタグを追加しつつ、レイアウトタグのオブジェクトを返します。そして通常、フォームオブジェクトに直接addTextboxなどのメソッドで入力タグを追加するところを、代わりにレイアウトオブジェクトのaddTextboxメソッドを実行することで、レイアウトに組み込まれた状態で入力タグが追加されます。

レイアウトオブジェクトとはFormLayoutAbstractクラスを継承したクラスのインスタンスです。
例えばFormLayoutTableはFormLayoutAbstractクラスを継承し、タグとしてtableタグを利用したレイアウトを構築するためのクラスです。

FormLayoutAbstractを継承するクラスは名前の末尾がタグの名前となっている必要があります。
そしてHtmlFormのaddLayoutメソッドのパラメータにはこの末尾のタグ名を指定します。
例えばaddLayout('table')であればFormLayoutTableがレイアウトのクラスとして利用されます。

$form = new HtmlForm();
// $layoutにはFormLayoutTableのインスタンスが代入される
$layout = $form->addLayout('table');
$layout->addTextbox('name')->setCaption('名前');
$layout->addTextarea('address')->setCaption('住所');
<form method="post">
  <table>
    <tbody>
      <tr>
        <td class="caption">名前</td>
        <td class="input">
          <input type="text" name="name" />
        </td>
      </tr>
      <tr>
        <td class="caption">住所</td>
        <td class="input">
          <textarea name="address"></textarea>
        </td>
      </tr>
    </tbody>
  </table>
</form>

コンテナのclass属性のデフォルト設定

カスタムレイアウトのタグの種類はレイアウトクラスの定義で決まりますが、入力タグと見出しのそれぞれのコンテナのcssのクラスは設定することができます。

$form = new HtmlForm();
$layout = $form->addLayout('table');
$layout->setCaptionContainerClass('custom_caption');
$layout->setInputContainerClass('custom_input');
$layout->addTextbox('name')->setCaption('名前');
$layout->addTextarea('address')->setCaption('住所');
<form method="post">
  <table>
    <tbody>
      <tr>
        <td class="custom_caption">名前</td>
        <td class="custom_input">
          <input type="text" name="name" />
        </td>
      </tr>
      <tr>
        <td class="custom_caption">住所</td>
        <td class="custom_input">
          <textarea name="address"></textarea>
        </td>
      </tr>
    </tbody>
  </table>
</form>

入力項目ごとのclass属性の設定

また、フォーム入力項目ごとに個別にコンテナのclass属性を設定する事も可能です。
レイアウトオブジェクトのadd~メソッドはフォーム入力タグオブジェクトを返します。
フォーム入力タグのgetInputContainerメソッドやgetCaptionContainerメソッドを実行すると、それぞれ入力項目を格納するコンテナと見出しを格納するコンテナが得られます。これらはHtmlElementのインスタンスであるため、HtmlElementでできることはなんでもでき、柔軟に設定が可能になります。

$form = new HtmlForm();
$layout = $form->addLayout('table');
$fomElem = $layout->addTextbox('name')->setCaption('名前');
$fomElem->getInputContainer()->setClass('name');
$fomElem->getCaptionContainer()->setClass('name_caption');
$fomElem = $layout->addTextarea('address')->setCaption('住所');
$fomElem->getInputContainer()->setClass('address');
$fomElem->getCaptionContainer()->setClass('address_caption');
<form method="post">
  <table>
    <tbody>
      <tr>
        <td class="name_caption">名前</td>
        <td class="name">
          <input type="text" name="name" />
        </td>
      </tr>
      <tr>
        <td class="address_caption">住所</td>
        <td class="address">
          <textarea name="address"></textarea>
        </td>
      </tr>
    </tbody>
  </table>
</form>
<form method="post">
  <table>
    <tbody>
      <tr>
        <td class="name_caption">名前</td>
        <td class="name">
          <input type="text" name="name" />
        </td>
      </tr>
      <tr>
        <td class="address_caption">住所</td>
        <td class="address">
          <textarea name="address"></textarea>
        </td>
      </tr>
    </tbody>
  </table>
</form>

見出しの書式設定

見出しは通常、setCaptionメソッドで設定した文字列をそのまま表示しますが、表示する形式を書式として設定することができます。書式の設定は文字列で指定し、"%s"を一つだけ含めます。そうすると、"%s"の部分がsetCaptionで設定された文字列に置き換わって表示されます。

$form = new HtmlForm();
$layout = $form->addLayout('table');
$layout->setCaptionFormat('■%s:');
$layout->addTextbox('name')->setCaption('名前');
$layout->addTextarea('address')->setCaption('住所');
<form method="post">
  <table>
    <tbody>
      <tr>
        <td class="caption">■名前:</td>
        <td class="input">
          <input type="text" name="name" />
        </td>
      </tr>
      <tr>
        <td class="caption">■住所:</td>
        <td class="input">
          <textarea name="address"></textarea>
        </td>
      </tr>
    </tbody>
  </table>
</form>

復数レイアウト

レイアウトは一つのフォームに復数設定することもできます。
それには単純にaddLayoutメソッドを複数回実行するだけです。

$form = new HtmlForm();
// レイアウト1
$layout1 = $form->addLayout('table');
$layout1->addTextbox('name')->setCaption('名前');
$layout1->addTextarea('address')->setCaption('住所');
// レイアウト2
$layout2 = $form->addLayout('dl');
$layout2->addTextbox('name')->setCaption('電話番号');
$layout2->addTextarea('address')->setCaption('メールアドレス');
<form method="post">
  <table>
    <tbody>
      <tr>
        <td class="caption">名前</td>
        <td class="input">
          <input type="text" name="name" />
        </td>
      </tr>
      <tr>
        <td class="caption">住所</td>
        <td class="input">
          <textarea name="address"></textarea>
        </td>
      </tr>
    </tbody>
  </table>
  <dl>
    <dt class="caption">電話番号</dt>
    <dd class="input">
      <input type="text" name="name" />
    </dd>
    <dt class="caption">メールアドレス</dt>
    <dd class="input">
      <textarea name="address"></textarea>
    </dd>
  </dl>
</form>

レイアウト外の入力項目

HtmlFormのaddLayoutによって生成されたレイアウトオブジェクトに対して入力項目を追加していくと自動的にレイアウト整形されますが、一部の項目はレイアウト外としたい場合はあるでしょう。そのような場合はlayoutオブジェクトは無視してフォームオブジェクトへ直接addするだけで実現できます。

$form = new HtmlForm();
$form->addHidden('ip')->setValue($req->getServer('REMOTE_ADDR'));
$layout = $form->addLayout('dl');
$layout->addTextbox('name')->setCaption('名前');
$layout->addTextarea('address')->setCaption('住所');
$form->addSubmit('regist', '登録');
<form method="post">
  <input type="hidden" name="ip" value="1.2.3.4" />
  <dl>
    <dt class="caption">名前</dt>
    <dd class="input">
      <input type="text" name="name" />
    </dd>
    <dt class="caption">住所</dt>
    <dd class="input">
      <textarea name="address"></textarea>
    </dd>
  </dl>
  <input type="submit" name="regist" value="登録" />
</form>

更に、レイアウト外とする入力タグを、何らかのタグに格納した状態でフォームに追加したい場合は、一旦create~メソッドによってフォームへの追加はせずにオブジェクトだけ取得し、別途HtmlElementを生成してその中へ格納し、HtmlElementのインスタンスをフォームへ追加するという方法で実現が可能です。

$form = new HtmlForm();
$layout = $form->addLayout('dl');
$layout->addTextbox('name')->setCaption('名前');
$layout->addTextarea('address')->setCaption('住所');
// submit生成
$submit = $form->createSubmit('regist', '登録');
// divを生成してsubmitを格納
$div = HtmlElement::create('div')->addStyle('text-align', 'center')->addElement($submit);
// フォームへdivを追加
$form->addElement($div);
<form method="post">
  <dl>
    <dt class="caption">名前</dt>
    <dd class="input">
      <input type="text" name="name" />
    </dd>
    <dt class="caption">住所</dt>
    <dd class="input">
      <textarea name="address"></textarea>
    </dd>
  </dl>
  <div style="text-align:center">
    <input type="submit" name="regist" value="登録" />
  </div>
</form>

ユーザー定義レイアウトクラス

レイアウトクラスはFormLayoutAbstractを継承している必要があり、
Curryのパッケージに含まれるのは、

の3つです。

FormLayoutを継承すれば、レイアウトクラスは自由に作成することができます。
このクラスで必要なことは以下の3つです。

レイアウトのトップレベルのタグ名は、$_tagNameで定義したものになりますが、定義しなかった場合、クラス名の末尾がタグ名となります。ただし、当然既に定義存在するクラス名のものは作ることが出来ないため、例えばFormLayoutDivは標準で存在するため、divタグとしたい場合はクラス名は別のものにし、$_tagNameフィールドに"div"と指定剃る必要があります。

タグの内側で入力タグのコンテナとなるタグを設定するのが$_inputContainerTagNameフィールドです。
見出しのコンテナとなるタグを設定するのが$_captionContainerTagNameフィールドです。
また入力タグに対して入力エラーメッセージを表示する場合のタグもレイアウトの一部として組み込まれており、デフォルトのタグはspanに設定されていますが、必要に応じて$_errorContainerTagNameフィールドを定義することで指定が可能です。

そしてaddFormElementContainerメソッドはFormLayoutAbstractの抽象メソッドであり、必ず継承する必要があります。
addFormElementContainerは引数が2つで、第1引数が入力タグのコンテナタグのHtmlElementインスタンスです。
第2引数が見出しのコンテナタグのHtmlElementインスタンスです。
つまり$_inputContainerTagNameフィールドと$_captionContainerTagNameフィールドで指定したタグ名で生成されたそれぞれのコンテナのHtmlElementインスタンスが引数で入ってきます。
そしてこれをレイアウトに追加するのがaddFormElementContainerの役割で、例えばそれぞれのタグをレイアウトのトップレベルのタグの直下に格納する場合はそれぞれのインスタンスをaddElementメソッドで追加するだけになります。

例えばコンテナのトップレベルのタグがdiv、見出しのコンテナがp、入力のコンテンもpの場合は以下の様なクラスになります。

class FormLayoutDivP extends FormLayoutAbstract
{
    protected $_tagName = 'div';	
    protected $_captionContainerTagName = 'p';
    protected $_inputContainerTagName = 'p';
    protected $_errorTagName = 'div';
	
    protected function addFormElementContainer(HtmlElement $inputContainer, HtmlElement $captionContainer)
    {
        $this->addElement($captionContainer);
        $this->addElement($inputContainer);
    }
}

そしてこのレイアウトを利用すると以下のようになります。

$form = new HtmlForm();
$layout = $form->addLayout('div_p');
$layout->addTextbox('name')->setCaption('名前')->setErrorMessage('入力してください。');
$layout->addTextarea('address')->setCaption('住所');
<form method="post">
  <div>
    <p class="caption">名前</p>
    <p class="input">
      <input type="text" name="name" />
      <div class="error">入力してください。</div>
    </p>
    <p class="caption">住所</p>
    <p class="input">
      <textarea name="address"></textarea>
    </p>
  </div>
</form>

FormLayoutAbstractはHtmlFormを継承しているため、HtmlFormの持つ機能は全て備えています。つまり、レイアウトは自由にカスタマイズが出来るということです。

例えば以下のように属性を自由に設定したり、レイアウトのタグ階層も自由に組むことができます。

class FormLayoutCustom extends FormLayoutAbstract
{
    protected $_tagName = 'div';	
    protected $_captionContainerTagName = 'span';
    protected $_inputContainerTagName = 'span';
    
    protected $_subContainer;
    
    public function __construct(HtmlForm $form)
    {
        // レイアウトのトップレベルタグにクラス属性設定
        $this->addClass('layout');
        
        // サブコンテナを生成
        $this->_subContainer = HtmlElement::create('div')->setClass('sub');
        $this->addElement($this->_subContainer);
        parent::__construct($form);
    }
    	
    protected function addFormElementContainer(HtmlElement $inputContainer, HtmlElement $captionContainer)
    {
        $inputContainer->setClass('custom_input');
        
        $elements = $inputContainer->getElementsByTagName('input');
        if (count($elements) > 0 && $elements[0]->getType() == 'submit') {
            // class属性が"button"の場合はサブコンテナの中に入れずにボタン専用のコンテナに格納
            $buttonContainer = HtmlElement::create('div')->setClass('buttons');
            $buttonContainer->addElement($inputContainer);
            $this->addElement($buttonContainer);
        } else {
            // それ以外はサブコンテナの中に更に入力タグごとのサブコンテナを生成して格納
            $subSubContainer = HtmlElement::create('p')->setClass('sub_sub');
            $subSubContainer->addElement($captionContainer);
            $subSubContainer->addElement($inputContainer);
            $this->_subContainer->addElement($subSubContainer);
        }
    }
}
$form = new HtmlForm();
$layout = $form->addLayout('custom');
$layout->addTextbox('name')->setCaption('名前');
$layout->addTextarea('address')->setCaption('住所');
$layout->addSubmit('regist', '登録')->addClass('button');
<form method="post">
  <div class="layout">
    <div class="sub">
      <p class="sub_sub">
        <span class="caption">名前</span>
        <span class="custom_input">
          <input type="text" name="name" />
        </span>
      </p>
      <p class="sub_sub">
        <span class="caption">住所</span>
        <span class="custom_input">
          <textarea name="address"></textarea>
        </span>
      </p>
    </div>
    <div class="buttons">
      <span class="custom_input">
        <input class="button" type="submit" name="regist" value="登録" />
      </span>
    </div>
  </div>
</form>

入力タグのvalue初期値設定

フォーム入力タグの初期値はvalue属性で設定するため、FormElementのsetValueメソッドで設定することができます。textareaについてはタグのテキストノードが値となるため、setTextで設定する事はもちろん出来ますが、setValueメソッドでも設定することが可能です。

selectなどのFormElementSetクラスを利用した物の初期選択状態の設定についてもsetValueメソッドで可能です。

$data = array(
    'name'    => '山田太郎',
    'sex'     => '1',
    'address' => '東京都',
);
$form = new HtmlForm();
$form->addTextbox('name')->setCaption('名前')->setValue($data['name']);
$form->addRadio('sex', array('1' => '男', '2' => '女'))->setCaption('名前')->setValue($data['sex']);
$form->addTextarea('address')->setCaption('住所')->setValue($data['address']);
$form->addSubmit('regist', '登録');
$form->render();
<form method="post">
  <div class="container">
    <span class="caption">名前</span>
    <span class="input">
      <input type="text" name="name" value="山田太郎" />
    </span>
  </div>
  <div class="container">
    <span class="caption">名前</span>
    <span class="input">
      <span>
        <label><input type="radio" name="sex" value="1" checked="checked" />男</label>
        <label><input type="radio" name="sex" value="2" />女</label>
      </span>
    </span>
  </div>
  <div class="container">
    <span class="caption">住所</span>
    <span class="input">
      <textarea name="address">東京都</textarea>
    </span>
  </div>
  <div class="container">
    <span class="caption"></span>
    <span class="input">
      <input type="submit" name="regist" value="登録" />
    </span>
  </div>
</form>

setValueメソッドで個別に設定することも可能ですが、FormクラスのbindValuesメソッドを利用すると一度に値を設定することができます。

bindValuesに設定する値は入力タグのname属性をキーとした配列になります。
タグのname属性と設定するデータのキーが一致していれば、bindValuesメソッドだけで全ての項目の初期値が設定できるため、便利です。

以下の例は上の例と同じ結果となります。

$data = array(
    'name'    => '山田太郎',
    'sex'     => '1',
    'address' => '東京都',
);
$form = new HtmlForm();
$form->setIsAutoLayout(false);
$form->addTextbox('name')->setCaption('名前');
$form->addRadio('sex', array('1' => '男', '2' => '女'))->setCaption('名前');
$form->addTextarea('address')->setCaption('住所');
$form->addSubmit('regist', '登録');
$form->bindValues($data);
$form->render();

FormLayoutSetの場合、setValueで指定する値は配列も可能です。
checkboxの場合、またはselecでsetMultiple(true)などで複数選択可能状態であれば複数選択された状態となります。

$prefList = array('tokyo' => '東京都', 'osaka' => '大阪府');
$form->addSelect('pref', $prefList)->setValue(array('osaka', 'tokyo'))->setMultiple(true);
$form->addCheckboxes('pref2', $prefList)->setValue(array('osaka', 'tokyo'));
<select name="pref" multiple="multiple">
  <option value="tokyo" selected="selected">東京都</option>
  <option value="osaka" selected="selected">大阪府</option>
</select>
<span>
  <label><input type="checkbox" value="tokyo" name="pref2" checked="checked" />東京都</label>
  <label><input type="checkbox" value="osaka" name="pref2" checked="checked" />大阪府</label>
</span>

便利な機能

内部コンテナ

formタグの直下に、formタグの内容を包括する形のコンテナタグを挟むことができます。
それにはHtmlFormのsetInnerContainerメソッドでコンテナにしたいHtmlElementのインスタンスを指定します。

$form = new HtmlForm();
$form->setInnerContainer(HtmlElement::create('div')->setClass('inner_container'));
$form->addTextbox('name')->setCaption('名前');
$form->addTextarea('address')->setCaption('住所');
$form->render();
<form method="post">
  <div class="inner_container">
    <div class="container">
      <span class="caption">名前</span>
      <span class="input">
        <input type="text" name="name" />
      </span>
    </div>
    <div class="container">
      <span class="caption">住所</span>
      <span class="input">
        <textarea name="address"></textarea>
      </span>
    </div>
  </div>
</form>

エラーメッセージ表示

フォームの入力に対しては通常、入力チェックを行います。そしてエラー時はフォームに戻り、エラーメッセージを表示するのが通例です。
FormElementにはエラーメッセージを設定する機能が備わっています。
設定方法は、FormElementのインスタンスに対してsetErrorMessageメソッドでエラーメッセージを指定します。
ただし簡易レイアウトもしくはカスタムレイアウトが有効になっている必要があります。

$errors = array(
    'name'    => '入力してください',
    'address' => '全て全角で入力してください'
);
$form = new HtmlForm();
$name = $form->addTextbox('name')->setCaption('名前');
if (isset($errors['name'])) {
    $name->setErrorMessage($errors['name']);
}
$addr = $form->addTextarea('address')->setCaption('住所');
if (isset($errors['address'])) {
    $addr->setErrorMessage($errors['address']);
}
<form method="post">
  <div class="container">
    <span class="caption">名前</span>
    <span class="input">
      <input type="text" name="name" />
      <span class="error">入力してください</span>
    </span>
  </div>
  <div class="container">
    <span class="caption">住所</span>
    <span class="input">
      <textarea name="address"></textarea>
      <span class="error">全て全角で入力してください</span>
    </span>
  </div>
</form>

また、フォームの全ての項目のエラーメッセージを一度に設定する事もできます。
それにはbindErrorsメソッドで、フォーム入力タグのname属性をキーとするエラーメッセージの配列を指定します。

以下は上の例と同じ結果となります。

$errors = array(
    'name'    => '入力してください',
    'address' => '全て全角で入力してください'
);
$form = new HtmlForm();
$form->addTextbox('name')->setCaption('名前');
$form->addTextarea('address')->setCaption('住所');
$form->bindErrorsc($errors);

配列データをもとにフォームの構築

フォームの項目情報を定義した配列によって一度にフォームを構築する事ができます。

$form = new HtmlForm();
$formElements = array(
    array(
        'type'    => 'textbox',
        'name'    => 'name',
        'caption' => '名前',
    ),
    array(
        'type'    => 'radio',
        'name'    => 'sex',
        'caption' => '性別',
        'list'    => array(1 => '男', 2 => '女'),
    ),
    array(
        'type'    => 'textarea',
        'name'    => 'address',
        'caption' => '住所',
    ),
    array(
        'type'  => 'submit',
        'name'  => 'regist',
        'value' => '登録',
    ),
);
$form->buildFromArray($formElements);
<form method="post">
  <div class="container">
    <span class="caption">名前</span>
    <span class="input">
      <input type="text" name="name" />
    </span>
  </div>
  <div class="container">
    <span class="caption">性別</span>
    <span class="input">
      <span>
        <label><input type="radio" name="sex" value="1" />男</label>
        <label><input type="radio" name="sex" value="2" />女</label>
      </span>
    </span>
  </div>
  <div class="container">
    <span class="caption">住所</span>
    <span class="input">
      <textarea name="address"></textarea>
    </span>
  </div>
  <div class="container">
    <span class="caption"></span>
    <span class="input">
      <input type="submit" name="regist" value="登録" />
    </span>
  </div>
</form>

カスタムレイアウトを利用する場合は先にaddLayoutメソッドでレイアウトオブジェクトを生成しておき、フォーム項目定義配列の"layout"キーにレイアウトオブジェクトのインスタンスを指定します。

また、"container"キーにHtmlElementのインスタンスを指定すると、そのフォーム項目は指定されたタグの下に配置されます。

$form = new HtmlForm();
$layout = $form->addLayout('dl');

$formElements = array(
    array(
        'layout'  => $layout,
        'type'    => 'textbox',
        'name'    => 'name',
        'caption' => '名前',
    ),
    array(
        'layout'  => $layout,
        'type'    => 'radio',
        'name'    => 'sex',
        'caption' => '性別',
        'list'    => array(1 => '男', 2 => '女'),
    ),
    array(
        'layout'  => $layout,
        'type'    => 'textarea',
        'name'    => 'address',
        'caption' => '住所',
    ),
    array(
        'container' => HtmlElement::create('div')->addStyle('text-align', 'center'),
        'type'  => 'submit',
        'name'  => 'regist',
        'value' => '登録',
    ),
);
$form->buildFromArray($formElements);
<form method="post">
  <dl>
    <dt class="caption">名前</dt>
    <dd class="input">
      <input type="text" name="name" />
    </dd>
    <dt class="caption">性別</dt>
    <dd class="input">
      <span>
        <label><input type="radio" name="sex" value="1" />男</label>
        <label><input type="radio" name="sex" value="2" />女</label>
      </span>
    </dd>
    <dt class="caption">住所</dt>
    <dd class="input">
      <textarea name="address"></textarea>
    </dd>
  </dl>
  <div style="text-align:center">
    <input type="submit" name="regist" value="登録" />
  </div>
</form>

buildFromArrayで受け付ける配列のキーは以下のとおりです。

キー意味指定方法
layout レイアウト HtmlLayoutAbstractを継承するクラスのインスタンス。これを指定することで、入力タグはそのレイアウトに含まれます。また、boolean型のtrueを指定すると、フォームに含まれる1番目のレイアウトに含まれるようになります。
container 入力タグのコンテナタグ HtmlElementのインスタンスを指定することで、入力タグがそのコンテナタグに格納された形とすること事ができます。
caption 見出し 入力タグに対する見出し文字列を指定します。
list 選択系入力タグの選択項目情報配列 typeでselect、radio、checkboxesを指定した場合の選択項目リスト情報を定義した配列を指定します。
上記以外 タグ属性情報 指定されたキーがそのまま属性名としてタグに設定されます。