symfonyのウィジェット TIPS

こんにちは、牧野です。最近、symfony1.2を使っています。
ということで今日はsymfonyのウィジェットについてです。

ウィジェットクラスはHTMLフォームのinputタグ等を簡単に生成するためのクラス群です。
詳しくはこちらのページを見てください。
http://www.symfony-project.org/forms/1_2/ja/A-Widgets

フォームクラス、バリデータークラスと一緒に組み合わせて使うとデータの登録、編集画面が簡単に作れるようになります。
また、ウィジェットクラスは様々なものが用意されていて、大抵の入力項目はウィジェットを使って作ることができます。

が、使っているうちにちょっとカスタマイズしたい場面が出てくると思います。
今回はそんな時に役立つかもしれないTIPSです。

・ラジオボタンのHTMLタグ
デフォルトのままでテンプレート内でrenderメソッドを呼び出すと、ラジオボタンとラベルがセットでリスト形式になります。


$radio = new sfWidgetFormSelectRadio(array(
  'label' => '性別',
  'choices' => array('m' => '男性', 'f' => '女性')
));

リスト形式を変更したい場合は、自分で作ったメソッドをinputタグ生成用に指定します。


class testformatter
{
  public $radio_part_separator = ' ';
  public function format_radio($widget, $inputs)
  {
    foreach ((array)$inputs as $input) {
      $radio_list[] = $input['input'].$widget->getOption('label_separator').$input['label'];
    }
    return implode($this->radio_part_separator, $radio_list);
  }
}
$formatter = new radioformat();
$radio = new sfWidgetFormSelectRadio(array(
  'label' => '性別',
  'choices' => array('m' => '男性', 'f' => '女性'),
  'formatter' => array($formatter, 'format_radio'),
));

・ラジオボタンだけを個別に表示したい
まともに、綺麗に直そうとすると、複数のクラスを作る必要が出てきそうだったので、renderメソッドをオーバーライドしました。


class sfWidgetFormMySelectRadio extends sfWidgetFormSelectRadio
{
  public $render_radio_one_attribute_name = 'render_one';
  public function render($name, $value = null, $attributes = array(), $errors = array())
  {
    if ('[]' != substr($name, -2)) {
      $name .= '[]';
    }
    $choices = $this->getOption('choices');
    if ($choices instanceof sfCallable) {
      $choices = $choices->call();
    }
    //renderメソッドに追加ここから
    //$attributesは、テンプレート内で使用するFormFieldクラスのrenderメソッドの引数として渡される。
    if (array_key_exists($this->render_radio_one_attribute_name, $attributes)) {
      $key = $attributes[$this->render_radio_one_attribute_name];
      unset($attributes[$this->render_radio_one_attribute_name]);
      $baseAttributes = array(
        'name'  => substr($name, 0, -2),
        'type'  => 'radio',
        'value' => self::escapeOnce($key),
        'id'    => $id = $this->generateId($name, self::escapeOnce($key)),
      );
      if (strval($key) == strval($value === false ? 0 : $value)) {
        $baseAttributes['checked'] = 'checked';
      }
      return $this->renderTag('input', array_merge($baseAttributes, $attributes));
    }
    //renderメソッドに追加ここまで
    // with groups?
    if (count($choices)  & & is_array(next($choices))) {
      $parts = array();
      foreach ($choices as $key => $option) {
        $parts[] = strtr($this->getOption('template'), array('%group%' => $key, '%options%' => $this->formatChoices($name, $value, $option, $attributes)));
      }
      return implode("\n", $parts);
    } else {
      return $this->formatChoices($name, $value, $choices, $attributes);
    }
  }
}

これで、


$radio->render(array('render_one' => 'm'));

のような感じでラジオボタンを1つずつ書けます。

ウィジェットには細かいバグっぽいところもあったりはするのですが、一通り欲しい機能をそろえることができれば結構便利に使えるのではないかと思います。