====== Apricot バリデーション ====== --- //[[http://www.y2sunlight.com|y2sunlight]] 2020-05-14// [[apricot:top|Apricot に戻る]] 関連記事 * [[apricot:configuration|Apricot プロジェクトの作成]] * [[apricot:public|Apricot 公開フォルダ]] * [[apricot:core:top|Apricot コア]] * Apricot アプリ * [[apricot:app:top|Apricot アプリ作成の準備]] * [[apricot:app:home|Apricot ホーム画面]] * [[apricot:app:error|Apricot エラー画面]] * [[apricot:app:db-model|Apricot データベースとモデル]] * [[apricot:app:user-list|Apricot ユーザ一覧画面]] * [[apricot:app:user-edit|Apricot ユーザ登録画面]] * Apricot バリデーション * [[apricot:app:transaction|Apricot トランザクション]] * [[apricot:ext:middleware|Apricot 拡張]] ユーザ登録画面にバリデーションの機能を追加します。 ---- ===== バリデーター ===== Apricotでは [[basic-library:valitron:1.4|Valitron]] を使いサーバ側のバリデーションで使用します。以下では、Valitron の設定方法について述べます。詳細は [[https://github.com/vlucas/valitron/blob/master/README.md|Valitron の README]] をご覧下さい。 ==== 言語ファイル ==== Valitronの言語ファイルを以下の手順でカスタマイズします。 - ''vendor/vlucas/valitron/lang/Valitron/ja.php'' を以下にコピーします * ''assets/lang/ja/vlucas.valitron.php'' - コピーした ''vlucas.valitron.php'' を以下のように変更します。 {{fa>folder-open-o}} ** /apricot/assets/lang/ja ** "を入力してください", '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 )に作成して下さい。 {{fa>folder-open-o}} ** /apricot/config/setting ** assets_dir('lang/'.env('APP_LANG')), 'lang' => 'vlucas.valitron', ]; * lang_dir --- 言語ファイルの保存フォルダ(既定値は ''/apricot/assets/lang/ja'' ) * lang --- 言語ファイル名( 拡張子を除いたベース名を指定 ) \\ ==== 初期設定ファイル ==== 以下の初期設定ファイルを所定の場所( /apricot/config/setup )に作成して下さい。 {{fa>folder-open-o}} ** /apricot/config/setup ** 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)に追加します。 {{fa>folder-open-o}} ** /apricot/config** [ 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クラス ==== コアの [[apricot:core:basic-class#ErrorBagクラス|ErrorBagクラス]] を継承してバリデーション用のエラーバッグ( ValidatorErrorBag )を作ります。 {{fa>folder-open-o}} ** /apricot/app/Foundation ** $value) { $errors[$key] = $value[0]; } parent::__construct($errors, self::BAG_KEY); } } * '''validator''' と言う名前でエラーバッグを生成します。 * 使用できるメソッドなど、機能的にはErrorBagクラスと全く同じです。 \\ ==== クラスエイリアス ==== ValidatorErrorBagクラスを[[apricot:app:top#クラスエイリアス|クラスエイリアス]]に追加します。 {{fa>folder-open-o}} ** /apricot/config/setup ** \App\Helpers\ViewHelper::class, 'ValidatorErrorBag' => \App\Foundation\ValidatorErrorBag::class, ]; ... return true; // Must return true on success }; * ViewHelper の下に ValidatorErrorBag のエイリアスを追加します。 \\ ===== インターセプター ===== Apricotではバリデーションをインターセプターの中に実装します。以下にインターセプターの作成方法について説明します。 >''インターセプター'' とはアクションの前処理の事で、ミドルウェアに似ていますが後処理はなく、各コントローラで独自に設定することができます。主な用途としては入力データの検証や変換です。本章では、インターセプターを直接アクションから呼び出していますが、後述の「Apricot 拡張: [[apricot:ext:interceptor|インターセプター]]」では、アクションをインターセプターに依存しない形で再実装します。 \\ ==== フォルダの作成 ==== Controllers の下に Interceptorsフォルダ を作って下さい。 apricot [プロジェクト] | ├── app [アプリ] | | | ├── Controllers [コントローラ] | | | | | ├── Interceptors [インターセプター] \\ ==== ユーザインターセプター ==== インターセプターメソッドのシグネチャには次の規則があります: * **interceptorMethod( Controller $controller, [, mixed $... ] ):mixed** - $controller --- インターセプターを呼び出したコントローラ - $... --- インターセプターを呼び出したアクションメソッドと同じ引数 * 戻り値 - 成功の場合 --- void を返す - 失敗の場合 --- Responseオブジェクトを返す 以下にユーザインターセプター( UserInterceptor )を示します。 {{fa>folder-open-o}} ** /apricot/app/Controllers/Interceptors ** 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'); } } バリデーションの手順は以下の通りです。 - Input::all()でフォームデータを取得します - Validatorの生成 * rule()メソッドで検証ルールを適用します * labels()メソッドでエラーメッセージで使う項目名を設定します - 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()'' にバリデーション処理を追加します。 - インターセプター( UserInterceptor )を生成します - アクションメソッドと同名の[[#ユーザインターセプター|インターセプターメソッド]]を呼び出します * 戻り値がResponseオブジェクトの場合はバリデーションエラーです * Responseオブジェクトを返してアクションを終了します * 戻り値がvoidの場合は正常終了です {{fa>folder-open-o}} ** /apricot/app/Controllers ** 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テンプレートを以下に示すように変更して下さい。 === 新規登録用のテンプレート === {{fa>folder-open-o}} ** /apricot/assets/views/user ** .... {{-- password --}}
{{-- password_confirmation --}}
....
*'' {{-- password --}}'' の部分を差し替えます * input-typeをpasswordに変更 * ''{{-- password_confirmation --}}'' の部分を追加します * 確認入力用に追加 === 編集用のテンプレート === {{fa>folder-open-o}} ** /apricot/assets/views/user ** .... {{-- password --}}
{{-- password_confirmation --}}
....
*'' {{-- password --}}'' の部分を差し替えます * input-typeをpasswordに変更 * ''{{-- password_confirmation --}}'' の部分を追加します * 確認入力用に追加 \\ ===== テスト実行 ===== バリデーションを使ってみましょう。ユーザ一覧画面を表示します。 [{{apricot:app:app08.png?nolink}}] ■ [新規]ボタンを押して下さい。 [{{apricot:app:app09.png?nolink}}] ■ 全て未入力の状態で、[保存]ボタンを押すとバリデーションが働き以下の画面が出ます。\\ [{{apricot:app:app10.png?nolink}}] ■ アカウントとパスワードの必須入力エラーエラーメッセージが表示されます。 === 様々なバリデーション === ユーザ新規登録画面では以下の様々なバリデーション機能があります。試してみて下さい。 * required — 必須入力(account, password) * alphaNum — 半角英数入力(account) * unique — ユニーク制約(account) * ascii — 半角入力(password) * equals — 確認入力(password = password_confirmation) * email — メールアドレス(email) \\