Ground Sunlight

Windowsで作る - Webプログラミングの開発環境(PHP)

ユーザ用ツール

サイト用ツール


サイドバー

メインメニュー

XAMPP アレンジ

道具箱

リポジトリ編

フレームワーク編

公開ソフトウェア

メタ
リンク


このページへのアクセス
今日: 3 / 昨日: 1
総計: 217

apricot:app:validation

Apricot バリデーション

バリデーター

Apricotでは Valitron を使いサーバ側のバリデーションで使用します。以下では、Valitron の設定方法について述べます。詳細は Valitron の README をご覧下さい。

言語ファイル

Valitronの言語ファイルを以下の手順でカスタマイズします。

  1. vendor/vlucas/valitron/lang/Valitron/ja.php を以下にコピーします
    • assets/lang/ja/vlucas.valitron.php
  2. コピーした vlucas.valitron.php を以下のように変更します。

/apricot/assets/lang/ja

vlucas.valitron.php
<?php
 
return array(
    'required'      => "を入力してください",
    'equals'        => "は「%s」と同じ内容を入力してください",
    'different'     => "は「%s」と異なる内容を入力してください",
    'accepted'      => "に同意してください",
    'numeric'       => "は数値を入力してください",
    'integer'       => "は半角数字で入力してください",
    'length'        => "は%d文字で入力してください",
    'min'           => "には%sより大きな値を入力してください",
    'max'           => "には%sより小さな値を入力してください",
    'listContains'  => "には選択できない値が含まれています",
    'in'            => "には選択できない値が含まれています",
    'notIn'         => "には選択できない値が含まれています",
    'ip'            => "はIPアドレスの書式として正しくありません",
    'email'         => "の書式が正しくありません", /* 修正 */
    'url'           => "はURLの書式として正しくありません",
    'urlActive'     => "はアクティブなドメインではありません",
    'alpha'         => "は半角英字で入力してください",
    'alphaNum'      => "は半角英数字で入力してください",
    'slug'          => "は半角英数字、もしくは「-」「_」の文字で入力してください",
    'regex'         => "の書式が正しくありません",
    'date'          => "の書式が正しくありません", /* 修正 */
    'dateFormat'    => "は「%s」の書式で日付を入力してください",
    'dateBefore'    => "は「%s」以前の日付を入力してください",
    'dateAfter'     => "は「%s」以後の日付を入力してください",
    'contains'      => "は「%s」を含んでいなければいけません",
    'boolean'       => "は真偽値である必要があります",
    'lengthBetween' => "は%d%d文字で入力してください",
    'creditCard'    => "はクレジットカード番号の書式として正しくありません",
    'lengthMin'     => "は%d文字以上入力してください",
    'lengthMax'     => "は%d文字以内で入力してください",
    'instanceOf'    => "は「%s」のインスタンスではありません",
    'ascii'         => "は半角文字で入力して下さい", /* 追加 */
    'unique'        => "は既に使用されています", /* 追加 */
);
  • 'email' と 'date' のテキストを変更します
  • 'ascii' と 'unique' のテキストを追加します


設定ファイル

以下の設定ファイルを所定の場所( /apricot/config/setting )に作成して下さい。

/apricot/config/setting

validator.setting.php
<?php
return
[
    'lang_dir' => assets_dir('lang/'.env('APP_LANG')),
    'lang' => 'vlucas.valitron',
];
  • lang_dir — 言語ファイルの保存フォルダ(既定値は /apricot/assets/lang/ja )
  • lang — 言語ファイル名( 拡張子を除いたベース名を指定 )


初期設定ファイル

以下の初期設定ファイルを所定の場所( /apricot/config/setup )に作成して下さい。

/apricot/config/setup

validator.setup.php
<?php
//-------------------------------------------------------------------
// Valitron\Validatorの初期設定
//-------------------------------------------------------------------
return function():bool
{
    \Valitron\Validator::langDir(config('validator.lang_dir'));
    \Valitron\Validator::lang(config('validator.lang'));
 
    //-------------------------------------------------------------------
    // カスタムルールの追加
    //-------------------------------------------------------------------
    /*
     * uniqueルール: ユニーク属性の検査を行う
     * [例] rule('unique','ユニークカラム名','テーブル名','IDカラム名')
     */
    Valitron\Validator::addRule('unique', function($field, $value, array $params, array $fields)
    {
        if (count($params)<1) return false;
 
        $query = ORM::for_table($params[0])->where($field, $value);
        if ((count($params)>1) && array_key_exists($params[1], $fields))
        {
            $id_field = $params[1];
            $query = $query->where_not_equal($id_field, $fields[$id_field]);
        }
        $users = $query->find_one();
 
        return ($users===false);
 
    }, 'is not unique');
 
    return true; // Must return true on success
};

初期設定ファイルでは以下の事をおこないます:

  • 言語ファイルの指定
  • カスタムルール(uniqueルール)の追加

uniqueルール

uniqueルールはデーターベースのユニーク制約の為のルールです。

使用法: rule('unique',$unique_column_name, $table_name, $id_column_name)

  • $unique_column_name — ユニークカラム名
  • $table_name — テーブル名
  • $id_column_name — IDカラム名
// 使用例
$validator = new \Valitron\Validator($inputs);
$validator->rule('unique','account', 'user', 'id');


アプリケーション設定の変更

上で作った validator.setup.php をアプリケーションの設定ファイル(app.php)に追加します。

/apricot/config

app.php
<?php
return
[
    'setup' =>[
        config_dir('setup/whoops.setup.php'),    /* Error handler(whoops) */
        config_dir('setup/bladeone.setup.php'),  /* View template (BladeOne) */
        config_dir('setup/aliases.setup.php'),   /* Class aliases for view template and so on */
        config_dir('setup/idiorm.setup.php'),    /* ORM(idiorm) */
        config_dir('setup/validator.setup.php'), /* Valitron\Validator */
    ],
    'middleware' =>[],
    'auth' =>[],
    'csrf' =>[],
];


エラーバッグ

ValidatorErrorBagクラス

コアの ErrorBagクラス を継承してバリデーション用のエラーバッグ( ValidatorErrorBag )を作ります。

/apricot/app/Foundation

ValidatorErrorBag.php
<?php
namespace App\Foundation;
 
use Core\Foundation\ErrorBag;
 
class ValidatorErrorBag extends ErrorBag
{
    public const BAG_KEY = 'validator';
 
    /**
     * Create Validator Error Bag
     * @param array $errors \Valitron\Validator Errors
     */
    public function __construct($validator_errors)
    {
        $errors = [];
        foreach($validator_errors as $key=>$value)
        {
            $errors[$key] = $value[0];
        }
        parent::__construct($errors, self::BAG_KEY);
    }
}
  • 'validator' と言う名前でエラーバッグを生成します。
  • 使用できるメソッドなど、機能的にはErrorBagクラスと全く同じです。


クラスエイリアス

ValidatorErrorBagクラスをクラスエイリアスに追加します。

/apricot/config/setup

aliases.setup.php
<?php
//-------------------------------------------------------------------
// ビューテンプレートで使うクラスエイリアスを登録
//-------------------------------------------------------------------
return function():bool
{
    $aliases =
    [
        /* Core */
        ...
 
        /* App */
        'ViewHelper' => \App\Helpers\ViewHelper::class,
        'ValidatorErrorBag' => \App\Foundation\ValidatorErrorBag::class,
    ];
 
    ...
 
    return true; // Must return true on success
};
  • ViewHelper の下に ValidatorErrorBag のエイリアスを追加します。


インターセプター

Apricotではバリデーションをインターセプターの中に実装します。以下にインターセプターの作成方法について説明します。

インターセプター とはアクションの前処理の事で、ミドルウェアに似ていますが後処理はなく、各コントローラで独自に設定することができます。主な用途としては入力データの検証や変換です。本章では、インターセプターを直接アクションから呼び出していますが、後述の「Apricot 拡張: インターセプター」では、アクションをインターセプターに依存しない形で再実装します。


フォルダの作成 

Controllers の下に Interceptorsフォルダ を作って下さい。

apricot [プロジェクト]
 |
 ├── app [アプリ]
 |    |
 |    ├── Controllers [コントローラ]
 |    |    |
 |    |    ├── Interceptors [インターセプター]


ユーザインターセプター 

インターセプターメソッドのシグネチャには次の規則があります:

  • interceptorMethod( Controller $controller, [, mixed $… ] ):mixed
    1. $controller — インターセプターを呼び出したコントローラ
    2. $… — インターセプターを呼び出したアクションメソッドと同じ引数
    • 戻り値
      1. 成功の場合 — void を返す
      2. 失敗の場合 — Responseオブジェクトを返す

以下にユーザインターセプター( UserInterceptor )を示します。

/apricot/app/Controllers/Interceptors

UserInterceptor.php
<?php
namespace App\Controllers\Interceptors;
 
use Core\Input;
use App\Foundation\Controller;
use App\Foundation\ValidatorErrorBag;
 
/**
 * ユーザインターセプタ―
 */
class UserInterceptor
{
    /**
     * ユーザレコード挿入
     * @return void|\Core\Foundation\Response return Response if failed
     */
    public function insert(Controller $controller)
    {
        $inputs = Input::all();
 
        // Validation
        $v =(new \Valitron\Validator($inputs))
        ->rule('required', ['account','password'])
        ->rule('alphaNum','account')
        ->rule('unique','account','user','id')
        ->rule('ascii','password')
        ->rule('equals','password','password_confirmation')
        ->rule('email', 'email')
        ->labels(inputLabels('messages.user.create'));
 
        if(!$v->validate())
        {
            $errorBag = new ValidatorErrorBag($v->errors());
            return redirect(back())->withInputs()->withErrors($errorBag);
        }
 
        // Remove unnecessary inputs
        Input::remove('password_confirmation');
    }
 
    /**
     * ユーザレコード更新
     * @param int $id
     * @return void|\Core\Foundation\Response return Response if failed
     */
    public function update(Controller $controller, int $id)
    {
        $inputs = Input::all();
 
        // Validation
        $v =(new \Valitron\Validator($inputs))
        ->rule('ascii','password')
        ->rule('equals','password','password_confirmation')
        ->rule('email', 'email')
        ->labels(inputLabels('messages.user.create'));
 
        if(!$v->validate())
        {
            $errorBag = new ValidatorErrorBag($v->errors());
            return redirect(back())->withInputs()->withErrors($errorBag);
        }
 
        // Remove unnecessary inputs
        Input::remove('password_confirmation');
    }
}

バリデーションの手順は以下の通りです。

  1. Input::all()でフォームデータを取得します
  2. Validatorの生成
    • rule()メソッドで検証ルールを適用します
    • labels()メソッドでエラーメッセージで使う項目名を設定します
  3. Validatorのvalidate()メソッドで検証します
    • 検証エラーの時
      • withInputs()で入力変数をフラッシュ変数に保存します
      • withErrors()でバリデーションのエラーバッグをフラッシュ変数に保存します
      • redirect()で前画面にリダイレクトするResponseオブジェクトをします
    • 検証成功の時
      • 不要になったバリデーション用のフォームデータを削除します

検証ルール

  • insert() : レコード挿入時
    • required — 必須入力(account, password)
    • alphaNum — 半角英数入力(account)
    • unique — ユニーク制約(account)
    • ascii — 半角入力(password)
    • equals — 確認入力(password = password_confirmation)
    • email — メールアドレス(email)
  • update() : レコード更新時
    • ascii — 半角入力(password)
    • equals — 確認入力(password = password_confirmation)
    • email — メールアドレス(email)


ユーザコントローラ

以下の手順に従い、ユーザコントローラ( UserController )の insert()update() にバリデーション処理を追加します。

  1. インターセプター( UserInterceptor )を生成します
  2. アクションメソッドと同名のインターセプターメソッドを呼び出します
    • 戻り値がResponseオブジェクトの場合はバリデーションエラーです
      • Responseオブジェクトを返してアクションを終了します
    • 戻り値がvoidの場合は正常終了です

/apricot/app/Controllers

UserController.php
<?php
namespace App\Controllers;
 
use App\Exceptions\ApplicationException;
use App\Foundation\Controller;
use App\Models\User;
use Core\Input;
 
/**
 * ユーザコントローラ
 */
class UserController extends Controller
{
    ...
 
    /**
     * ユーザレコード挿入
     * @return \Core\Foundation\Response
     */
    public function insert()
    {
        // バリデーション
        $response = (new Interceptors\UserInterceptor())->insert($this);
        if ($response instanceof \Core\Foundation\Response)
        {
            return $response;
        }
 
        $inputs = Input::all();
 
        try
        {
            // ユーザレコード挿入
            $user = $this->user->insert($inputs);
        }
        catch(\Exception $e)
        {
            throw new ApplicationException(__('messages.error.db.insert'),$e->getMessage(),0,$e);
        }
 
        // ユーザ一編集画面にリダイレクト
        return redirect(route("user/{$user->id}/edit"))->with('msg',__('messages.success.db.insert'));
    }
 
    ...
 
    /**
     * ユーザレコード更新
     * @param int $id
     * @return \Core\Foundation\Response
     */
    public function update(int $id)
    {
        // バリデーション
        $response = (new Interceptors\UserInterceptor())->update($this, $id);
        if ($response instanceof \Core\Foundation\Response)
        {
            return $response;
        }
 
        $inputs = Input::all();
 
        try
        {
            // レコード更新
            $this->user->update($id, $inputs);
        }
        catch(ApplicationException $e)
        {
            throw $e;
        }
        catch(\Exception $e)
        {
            throw new ApplicationException(__('messages.error.db.update'),$e->getMessage(),0,$e);
        }
 
        // ユーザ一編集画面にリダイレクト
        return redirect(route("user/{$id}/edit"))->with('msg',__('messages.success.db.update'));
    }
 
    ...
}


HTMLテンプレート

HTMLテンプレートを以下に示すように変更して下さい。

新規登録用のテンプレート

/apricot/assets/views/user

create.blade.php
        ....
 
        {{-- password --}}
        <div class="form-group row">
            <label for="password" class="col-md-2 col-form-label">{{__('messages.user.create.password')}}</label>
            <div class="col-md-10">
                <input type="password" name="password" id="password" class="form-control" value="{{old('password')}}"
                    placeholder="{{__('messages.user.create.hint_password')}}">
            </div>
        </div>
        {{-- password_confirmation --}}
        <div class="form-group row">
            <label for="password_confirmation" class="col-md-2 col-form-label">{{__('messages.user.create.password_confirmation')}}</label>
            <div class="col-md-10">
                <input type="password" name="password_confirmation" id="password_confirmation" class="form-control" value="{{old('password_confirmation')}}"
                    placeholder="{{__('messages.user.create.hint_password_confirmation')}}">
            </div>
        </div>
 
        ....
  • {{-- password --}} の部分を差し替えます
    • input-typeをpasswordに変更
  • {{-- password_confirmation --}} の部分を追加します
    • 確認入力用に追加

編集用のテンプレート

/apricot/assets/views/user

edit.blade.php
        ....
 
        {{-- password --}}
        <div class="form-group row">
            <label for="password" class="col-md-2 col-form-label">{{__('messages.user.edit.password')}}</label>
            <div class="col-md-10">
                <input type="password" name="password" id="password" class="form-control" value="{{old('password')}}"
                    placeholder="{{__('messages.user.edit.hint_password')}}">
            </div>
        </div>
        {{-- password_confirmation --}}
        <div class="form-group row">
            <label for="password_confirmation" class="col-md-2 col-form-label">{{__('messages.user.edit.password_confirmation')}}</label>
            <div class="col-md-10">
                <input type="password" name="password_confirmation" id="password_confirmation" class="form-control" value="{{old('password_confirmation')}}"
                    placeholder="{{__('messages.user.edit.hint_password_confirmation')}}">
            </div>
        </div>
 
        ....
  • {{-- password --}} の部分を差し替えます
    • input-typeをpasswordに変更
  • {{-- password_confirmation --}} の部分を追加します
    • 確認入力用に追加


テスト実行

バリデーションを使ってみましょう。ユーザ一覧画面を表示します。

■ [新規]ボタンを押して下さい。

■ 全て未入力の状態で、[保存]ボタンを押すとバリデーションが働き以下の画面が出ます。

■ アカウントとパスワードの必須入力エラーエラーメッセージが表示されます。

様々なバリデーション

ユーザ新規登録画面では以下の様々なバリデーション機能があります。試してみて下さい。

  • required — 必須入力(account, password)
  • alphaNum — 半角英数入力(account)
  • unique — ユニーク制約(account)
  • ascii — 半角入力(password)
  • equals — 確認入力(password = password_confirmation)
  • email — メールアドレス(email)


コメント

コメントを入力. Wiki文法が有効です:
 
apricot/app/validation.txt · 最終更新: 2020/06/03 14:37 by tanaka