— y2sunlight 2020-05-14
関連記事
ユーザ登録画面にバリデーションの機能を追加します。
Apricotでは Valitron を使いサーバ側のバリデーションで使用します。以下では、Valitron の設定方法について述べます。詳細は Valitron の README をご覧下さい。
Valitronの言語ファイルを以下の手順でカスタマイズします。
vendor/vlucas/valitron/lang/Valitron/ja.php
を以下にコピーします
assets/lang/ja/vlucas.valitron.php
vlucas.valitron.php
を以下のように変更します。/apricot/assets/lang/ja
<?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
<?php return [ 'lang_dir' => assets_dir('lang/'.env('APP_LANG')), 'lang' => 'vlucas.valitron', ];
/apricot/assets/lang/ja
)
以下の初期設定ファイルを所定の場所( /apricot/config/setup )に作成して下さい。
/apricot/config/setup
<?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ルールはデーターベースのユニーク制約の為のルールです。
使用法: rule('unique',$unique_column_name, $table_name, $id_column_name)
// 使用例 $validator = new \Valitron\Validator($inputs); $validator->rule('unique','account', 'user', 'id');
上で作った validator.setup.php をアプリケーションの設定ファイル(app.php)に追加します。
/apricot/config
<?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' =>[], ];
コアの ErrorBagクラス を継承してバリデーション用のエラーバッグ( ValidatorErrorBag )を作ります。
/apricot/app/Foundation
<?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
' と言う名前でエラーバッグを生成します。
ValidatorErrorBagクラスをクラスエイリアスに追加します。
/apricot/config/setup
<?php //------------------------------------------------------------------- // ビューテンプレートで使うクラスエイリアスを登録 //------------------------------------------------------------------- return function():bool { $aliases = [ /* Core */ ... /* App */ 'ViewHelper' => \App\Helpers\ViewHelper::class, 'ValidatorErrorBag' => \App\Foundation\ValidatorErrorBag::class, ]; ... return true; // Must return true on success };
Apricotではバリデーションをインターセプターの中に実装します。以下にインターセプターの作成方法について説明します。
インターセプター
とはアクションの前処理の事で、ミドルウェアに似ていますが後処理はなく、各コントローラで独自に設定することができます。主な用途としては入力データの検証や変換です。本章では、インターセプターを直接アクションから呼び出していますが、後述の「Apricot 拡張: インターセプター」では、アクションをインターセプターに依存しない形で再実装します。
Controllers の下に Interceptorsフォルダ を作って下さい。
apricot [プロジェクト] | ├── app [アプリ] | | | ├── Controllers [コントローラ] | | | | | ├── Interceptors [インターセプター]
インターセプターメソッドのシグネチャには次の規則があります:
以下にユーザインターセプター( UserInterceptor )を示します。
/apricot/app/Controllers/Interceptors
<?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'); } }
バリデーションの手順は以下の通りです。
required
— 必須入力(account, password)alphaNum
— 半角英数入力(account)unique
— ユニーク制約(account)ascii
— 半角入力(password)equals
— 確認入力(password = password_confirmation)email
— メールアドレス(email)ascii
— 半角入力(password)equals
— 確認入力(password = password_confirmation)email
— メールアドレス(email)
以下の手順に従い、ユーザコントローラ( UserController )の insert()
と update()
にバリデーション処理を追加します。
/apricot/app/Controllers
<?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テンプレートを以下に示すように変更して下さい。
/apricot/assets/views/user
.... {{-- 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 --}}
の部分を差し替えます
{{-- password_confirmation --}}
の部分を追加します
/apricot/assets/views/user
.... {{-- 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 --}}
の部分を差し替えます
{{-- password_confirmation --}}
の部分を追加します
バリデーションを使ってみましょう。ユーザ一覧画面を表示します。
■ [新規]ボタンを押して下さい。
■ 全て未入力の状態で、[保存]ボタンを押すとバリデーションが働き以下の画面が出ます。
■ アカウントとパスワードの必須入力エラーエラーメッセージが表示されます。
ユーザ新規登録画面では以下の様々なバリデーション機能があります。試してみて下さい。