====== 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)
\\