Logicky Blog

Logickyの開発ブログです

fuelphp 1.8 - カスタムバリデーション

どうも、Uploadをすると、Uploadクラスのバリデーションを使うことになりますが、これとfieldsetのValidationクラスとの連動がいまいちうまくできない。Fieldsetはform.phpの、inline_errorsをtrueにすると勝手にエラーを表示してくれるが、このエラーに自動的にuploadのエラーも連動するようにしたい。他にやり方があるかもしれないが、Upload関連のエラーをValidationのカスタマイズルールとして作成することで、実現してみる。

モデルでFieldsetを作成する

fileというフィールドに、uploadというルールを設定している。これはデフォルトではないので、カスタマイズルールになります。引数は、フィールド名。あとでこのuploadというルールを作成します。

public static function fieldset()
{
    //大カテゴリー取得
    $big_categories = Model_Category::get_big_category_list();

    $fset = Fieldset::forge();
    $fset->add('file', '動画ファイル', array('type' => 'file'))->add_rule('upload', 'file');
    $fset->add('title', 'タイトル')->add_rule('required')->add_rule('max_length', 150);
    $fset->add('description', '説明', array('type' => 'textarea'))->add_rule('required')->add_rule('max_length', 500);
    $fset->add('big_category_id', '大カテゴリー', array('type' => 'select', 'options' => $big_categories));
    $fset->add('category_id', '小カテゴリー', array('type' => 'select'))->add_rule('required');
    $fset->add('order_no', '表示順')->add_rule('required')->add_rule('numeric_between', 1, 100);
    return $fset;
}

カスタムバリデーションのクラスファイルを作成する

fuel/app/classes/model/validation/upload.phpというのを作成してみる。

<?php
class Model_Validation_Upload
{
    public static function _validation_upload($field_name)
    {
        if(Upload::is_valid())
        {
            Upload::save();
            return true;
        }
        else
        {
            $error = Upload::get_errors($field_name);
            if(!empty($error['errors'][0]['message']))
            {
                Validation::active()->set_message('upload', $error['errors'][0]['message']);
            }else{
                Validation::active()->set_message('upload', 'ファイルのアップロードでエラーが発生しました');
            }
            return false;
        }
    }
}

コントローラを作成する

フィールドセットを作って、Upload:processを走らせて、フィールドセットからバリデーションを取りだして、バリデーションにuploadルールを読めるように設定する。

public function action_add()
{
    //フィールドセットの取得
    $fset = Model_Movie::fieldset();

    if (Input::post()){
        Upload::process();

        // バリデーションチェック
        $val = $fset->validation();
        $val->add_callable('Model_Validation_Upload');

        if( $val->run() ){
            //動画情報をデータベースに登録
            $file = Upload::get_files( 0 );
            if( Model_Movie::add( Input::post(), $file ) ){
                Session::set_flash( 'msg', '動画を登録しました。' );
                return Response::redirect( 'admin/movies/' );
            }else{
                //保存ファイルの削除
                File::delete( DOCROOT . 'assets/movie/' . $file[ 'saved_as' ] );
            }
        }

        //小カテゴリのoptionsの取得・設定
        $big_id = Input::post( 'big_category_id' );
        $fset   = Model_Category::set_small_cat_options( $big_id, $fset );

        $fset->repopulate();

        Session::set_flash( 'msg', '動画が登録できませんでした。恐れ入りますが、再度お試しください。' );
    }

    //set view
    $this->template->content = View::forge('admin/movies/add');
    $this->template->content->set_safe('fset', $fset);
}

View

uploadは、enctypeの表示が必要。Fieldsetのフィールドをbuildしてるだけ。bootstrapを使っているので、set_attributeでform-controlクラスを設定している。

<?php echo Form::open(array('enctype' => 'multipart/form-data'))?>
<?php echo $fset->field('file')->set_attribute('class', 'form-control')->build()?>
<?php echo $fset->field('title')->set_attribute('class', 'form-control')->build()?>
<?php echo $fset->field('description')->set_attribute('class', 'form-control')->build()?>
<?php echo $fset->field('big_category_id')
    ->set_attribute('class', 'form-control')
    ->set_attribute('onchange', 'get_small_cat("' . Uri::create('rest/admin/categories/small_cat.json') . '");')
    ->build()?>
<?php echo $fset->field('category_id')->set_attribute('class', 'form-control')->build()?>
<?php echo $fset->field('order_no')->set_attribute('class', 'form-control')->build()?>
<button type="submit" class="btn btn-primary">登録</button>
<?php echo Html::anchor('admin/movies/', 'キャンセル', array('class' => 'btn btn-default'))?>
<?php echo Form::close()?>