fuelphpのfieldsetはすごく便利です。
formの出力とバリデーションが一体となって、似たようなコードを何回も欠かずに済みますし、文言の修正等も一箇所ですむようになります。

でも、webで検索していろいろ見ると、皆さんview画面が自由にカスタマイズできないから使えないと言ってバッサリ切ってしまっています。
すごくもったいないです。

かという自分も、view画面はきっちりと自分で作りたい派(というより仕事内容的に作らざるを得ない派)なので、fieldsetは使えないでいました。
しかし、個人サイトを作るときにfieldsetを使って以来、使えないのがストレスになってきたので、拡張して使えるようにしてみました!

これでストレス無く、制作が簡単なfieldsetを使うことができます

どう拡張したのか

coreをいじるのは嫌だったので、継承したクラスたちをpackageでまとめるという形にしました。
できるようにしたのは

  • viewで簡単にinputタグ系とlabel系、エラー系を分けて出力できるようにした(メイン)
  • モデル側でfieldsetをまとめて書きたいけど、それぞれの画面で入力項目が微妙に違うよ!って場合用にaddだけじゃなくてremoveメソッドを追加
  • ついでにfieldsetにadd_textやadd_checkboxなどhtmlタグに沿ったaddメソッドを追加
  • さらについでに自分のよく使う日付選択に沿ったaddメソッドを追加

です。

htmlタグに沿ったaddメソッドを追加できるようにする部分はkenjiさんの
FuelPHP の Fieldset を使おう(Form の自動生成)
を参考にさせていただきました。

使い方

viewformという名前でgithubで公開しています。

使う前の準備としては次の4点です。

  1. githubよりダウンロード or チェックアウトして、fuel/packages/viewformに展開
  2. fuel/app/config/config.phpの中の
    'packages'  => array(...) 

    のarrayの中に’viewform’を追加

  3. (忘れがち)fuel/app/config/config.phpの中の
    'whitelisted_classes'  => array(...) 

    のarrayの中に’ViewForm¥¥fieldset’を追加
    (viewにviewform¥fieldsetを渡すために必要です)

  4. (忘れがち)fuel/core/config/form.phpをfuel/app/config/form.phpにコピーし、中の
    'inline_errors'         => false, 

    をtrueに<
    (これをやらないとエラー各項目でのエラーが表示されません)

実際に使うときはcontroller側は普通のfieldsetと大して変わりません。
適宜html用ショートカットメソッドを使ってラクラクーと書いてください。

view側はcontroller側から渡されたfieldsetインスタンスを使って

echo $fieldset->field('nickname')->label_text();
echo $fieldset->field('nickname')->field_text();
if $fieldset->field('nickname')->has_error()){
	echo $fieldset->field('nickname')->error_text();
}

といった形でlabelとinputタグが別々にかけます。
もちろんタグの属性を引数に渡すこともできます。

echo $fieldset->field('nickname')->label_text(array('class'=>'control-label'));

(ただし、add_dateだけはちょっと特殊)

具体例

最後に、ひとつ自分が作ったものをそのままコピペしてみます
実際に使ってるコードなので、smartyだったりメソッド全部網羅してなかったりtwitter bootstrapだったりするのは勘弁してください

controller側


    public function action_user() {

        $fieldset = $this->_fieldset();
        $fieldset->repopulate();


        $val = $fieldset->validation();
        if ($val->run()) {
            //保存処理
            $user     = Model_User::forge();
            $saveKeys = array(
                'nickname', 'gender', 'country', 'email', 'birthday',);
            foreach ($saveKeys as $key) {
                $user->$key = $val->validated($key);
            }

            $user->save();

            return Fuel¥Core¥Response::redirect("setting/finished");
        }
        $smarty = Parser¥View_Smarty::forge('setting/user.tpl')
                ->set('fieldset', $fieldset);
        return Fuel¥Core¥Response::forge($smarty);
    }

    /**
     * 
     * @return ViewForm¥Fieldset
     */
    protected function _fieldset() {
        $fieldset = ViewForm¥Fieldset::forge();

        // textboxはadd をadd_textにするだけで使える
        $fieldset->add_text('nickname', 'ニックネーム')
                ->add_rule('required')
                ->add_rule('max_length', 10);

        // radio 用は add_radio 
        // value => 表示名 の配列 で選択肢を設定
        $genders = array('male'   => "男性", 'female' => "女性",);
        $fieldset->add_radio('gender', '性別', $genders)
                ->add_rule('required');


        // radio 用は add_select 
        // value => 表示名 の配列 で選択肢を設定 (radioと同じ)
        $countries = array('jp' => '日本','us' => 'アメリカ');
        $fieldset->add_select('country', '国籍', $countries)
                ->add_rule('required');


        $fieldset->add_text('email', 'メールアドレス')
                ->add_rule('required')
                ->add_rule('valid_email');

        // 年月日用selectbox 
        // 年を数値で指定 または 現在の年からの差で指定できる
        // 
        // ちなみにvalidate後はunixtimeに変換されている
        $fieldset->add_date_select('birthday', '誕生日', 1900, +0);

        return $fieldset;
    }

view側

{@Form::open(['class' => 'form-horizontal'])@}
{@$fieldset->show_errors()@}
<fieldset>
  <div class="control-group {@if $fieldset->field('nickname')->has_error()@}error{@/if@}">
    {@$fieldset->field('nickname')->label_text(['class'=>"control-label"])@}
    <div class="controls">
      {@$fieldset->field('nickname')->field_text(['class'=>'span9'])@}
      <span class="help-inline">{@$fieldset->field('nickname')->error_text()@}</span>
    </div>
  </div>

  <div class="control-group {@if $fieldset->field('gender')->has_error()@}error{@/if@}">
    {@$fieldset->field('gender')->label_text(['class'=>"control-label"])@}
    <div class="controls">
      {@$fieldset->field('gender')->field_text()@}
      <span class="help-inline">{@$fieldset->field('gender')->error_text()@}</span>
    </div>
  </div>

  <div class="control-group {@if $fieldset->field('country')->has_error()@}error{@/if@}">
    {@$fieldset->field('country')->label_text(['class'=>"control-label"])@}
    <div class="controls">
      {@$fieldset->field('country')->field_text()@}
      <span class="help-inline">{@$fieldset->field('country')->error_text()@}</span>
    </div>
  </div>

  <div class="control-group {@if $fieldset->field('email')->has_error()@}error{@/if@}">
    {@$fieldset->field('email')->label_text(['class'=>"control-label"])@}
    <div class="controls">
      {@$fieldset->field('email')->field_text()@}
      <span class="help-inline">{@$fieldset->field('email')->error_text()@}</span>
    </div>
  </div>

  <div class="control-group {@if $fieldset->field('birthday')->has_error()@}error{@/if@}">
    {@$fieldset->field('birthday')->label_text(['class'=>"control-label"])@}
    <div class="controls">
      {@$fieldset->field('birthday_year')->field_text(['class' => 'span2' ])@}年
      {@$fieldset->field('birthday_month')->field_text(['class' => 'span2' ])@}月
      {@$fieldset->field('birthday_day')->field_text(['class' => 'span2' ])@}日
      <span class="help-inline">{@$fieldset->field('birthday')->error_text()@}</span>
    </div>
  </div>

  <div class="control-group">
    <div class="controls">
      <div class="actions">
        {@Form::submit('submit', '保存',['class' => 'btn btn-primary btn-large'])@}
      </div></div>
  </div>

</fieldset>
{@Form::close()@}

 

4 Responses to fuelphpのfieldsetがもったいないので拡張してみた

  1. すがわら より:

    利用させてもらっていますm(__)m
    下記メソッドがあると嬉しいです。
    public function description_text() {
    return $this->description;
    }

  2. wicket より:

    利用してくれて嬉しいです!

    descriptionなんてあるんですね・・・すっかり見落としてました・・・。
    Fieldset_Field に public function description_text()追加してみました!

  3. すがわら より:

    ありがとうございます!!

  4. Harbie34 より:

    使ってみたのですが、add_radioのvalidationはin_arrayではなくarray_key_existsでないと、具体例のようにvalueと表示名が違っている場合に期待通りの動作をしないような気がしますがいかがでしょうか?
    それからせっかくなのでadd_*系にはhidden/reset/submitもあるといいですね。
    ご確認、ご検討よろしくお願いいたします。m(_ _)m

Harbie34 にコメントする コメントをキャンセル

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>