検証済み、検証済み...、検証済み! PHPでデータバリデーターを比較する



Michiana Stransportation( 自転車店 )から撮影した画像







それでもKontrolioが何であるかわからない場合は、最初の部分「 データを管理する 」を読むことをお勧めします。 要するに、これはPHPで書かれた私のデータ検証ライブラリです。

前の記事で、私は自分のライブラリと他の利用可能なソリューションとの比較を書くことを約束したので、今日はAura.FilterRespect ValidationSirius Validation 、およびValitronを使用した検証について見ていきます。







開発中の特定の公共サービスがあることを想像してみましょう。これには、すべての機能へのフルアクセスのためのユーザーの登録が含まれます。 したがって、登録フォームには次のフィールドが含まれます。







  1. 名前。 正確に2つの単語を含める必要があります。最初の単語はユーザー名で、2番目の単語は姓です。

  2. ログインします。 値が渡される場合、ラテン文字、ハイフン、アンダースコアのみが使用されます。

  3. メール 有効なメールアドレスを含める必要があります。

  4. パスワード。 インストールする必要があり、長さは64文字以下である必要があります。

  5. 同意した。 利用規約への同意を確認するためにユーザーが設定する必要がある典型的なフラグ。



したがって、架空のサービスに登録するためにユーザーが入力する必要がある5つのフィールドがあります。 完全に無効なデータを受け取ったと想像してみましょう。







$data = [ 'name' => '', //     'login' => '@lbert', // ""  @ 'email' => '-  ', //    e-mail 'password' => '' //     // 'agreed'   ,       ];
      
      





Aura.filter



Aura.Filterを使用した検証は、フィルターファクトリから始まります。 個々の値ではなく配列を検証するため、いわゆる「サブジェクトフィルター」を作成する必要があります。







ルールを定義する



 use Aura\Filter\FilterFactory; $filter = (new FilterFactory)->newSubjectFilter(); $filter->validate('name') ->isNotBlank() ->is('two_words') ->setMessage('     .'); $filter->validate('login') ->isBlankOr('alnum') ->setMessage('   ,      .'); $filter->validate('email') ->isNotBlank() ->is('email') ->setMessage(',    . .'); $filter->validate('password') ->isNotBlank() ->is('strlenMax', 64) ->setMessage(',  .'); $filter->validate('agreed') ->is('callback', function($subject, $field) { return $subject->{$field} === true; })->setMessage('     .');
      
      





ご覧のとおり、ルールの説明は非常に簡単です。 Aura.Filterは、すぐに使える便利なルールのセット全体を提供し、それらのいくつかは上の例で使用されています







  1. isNotBlankメソッド。 フィールドをnullにできないことを示します。

  2. このルールでは、ラテン文字のみが許可されます。

  3. メール そして、それは明らかです:)

  4. strlenMax。 is



    メソッドの2番目の引数で指定された長さをフィールドが超えられないことを示します。

  5. コールバック。 このタイプのルールは、Kontrolioのクロージャーに似ています。 クロージャーの形式でルールを定義できます。 このクロージャでは、Aura.Filterが「件名」、フォームからのデータの配列、およびこの場合agreed



    したフィールドを渡します。



きっとあなたは、私がtwo_words



ルールを指定しなかったことに気づいたでしょう。 当然、Aura.Filterにはそのようなルールはないため、作成する必要があります。 ドキュメンテーションが言うように、これはルールのために別のクラスを使用して行われます:







 /** * ,    . *      :   ,   . */ class UserNameRule { /** *   . * * @param object|array $subject * @param string $field * @param int $max * * @return bool */ public function __invoke($subject, $field, $max = null) { $value = $subject->{$field}; if ( ! is_scalar($value)) { return false; } return (bool) preg_match('/^[A-Za-z]+\s[A-Za-z]+$/u', $value); } }
      
      





2番目のステップは、フィルターファクトリーに新しいルールを知らせることです。 これは、最初の引数をルールの配列としてフィルターファクトリに渡すことで実行されます。







次のステップは、新しいルールを作成し、それを使用することをAura.Filterに通知することです。 これは、ルールの配列をファクトリーの最初の引数に渡すことで実行されます。







 use Aura\Filter\FilterFactory; $rules = [ 'two_words' => function() { return new UserNameRule; } ]; $filter = (new FilterFactory($rules))->newSubjectFilter();
      
      





これで、 two_words



ルールは、標準パッケージの他のルールと同じ方法で使用できます。







フィードバック



覚えているように、各フィールドに間違った値が含まれているか、まったく含まれていないため、検証する入力データは完全に無効です。 したがって、検証の結果として、エラーおよびエラーに関する対応するメッセージを受け取ると想定されます。







次のようにAura.Filterで検証します。







 $valid = $filter->apply($data); if ( ! $valid) { $failures = $filter->getFailures(); $messages = $failures->getMessages(); }
      
      





配列は$ messagesに書き込まれるため、メッセージを表示するには、ネストされた2つのforeachが必要です。







 <ul class="errors"> <?php foreach ($messages as $field => $errors) { foreach ($errors as $error) { printf('<li class="error">%s</li>', $error); } } ?> </ul>
      
      





検証の尊重



比較で使用した2番目のライブラリは、 Respect Validationと呼ばれる比較的一般的なソリューションです。 人々は彼女を信頼しているので、見るべきものがあると思います。







実験の純度のために、ライブラリを比較するとき、最初に定義された同じデータセットを使用します。







 use Respect\Validation\Validator as v; $data = [ 'name' => '', //     'login' => '@lbert', // ""  @ 'email' => '-  ', //    e-mail 'password' => '' //     // 'agreed'   ,       ];
      
      





ルールを定義する



Aura.Filterと同様に、ユーザー名に独自の検証ルールが必要なので、始めましょう:







 namespace MyNamespace; use Respect\Validation\Rules\AbstractRule; class UserNameRule extends AbstractRule { public function validate($input) { return (bool) preg_match('/^[A-Za-z]+\s[A-Za-z]+$/u', $input); } }
      
      





外部ルールAPIはAura.Filterとほぼ同じです。__invoke()マジックの代わりにvalidate()メソッドのみが使用されます。 私にとって、このAPIはよりシンプルで理解しやすいように見えました。 まあ、それはKontrolioに近いです:)







ドキュメントにはこれに関する言及はありませんでしたが、ルール自体に加えて、独自のタイプの例外を作成する必要があります。 例外クラスの名前は、ルールのクラス名と例外の接尾辞で構成する必要があります。







 use Respect\Validation\Exceptions\NestedValidationException; class UserNameRuleException extends NestedValidationException { // }
      
      





さて、最後に、データを検証できます。 最初に、バリデーターに新しいルールを渡して、彼がそれについて学習し、将来使用できるようにします。 Respect Validationでは、 with()メソッドを呼び出して、非標準のルールを含むネームスペースを渡すことでこれを行います。







 v::with('MyNamespace\\');
      
      





これで、 MyNamespace名前空間にあるすべての非標準ルールがバリデーターによって「認識」されます。 次のステップは、必要なルールを記述し、検証を実行することです。







 v::attribute('name', v::userNameRule()) ->attribute('login', v::alnum('-_')) ->attribute('email', v::email()) ->attribute('password', v::notEmpty()->stringType()->length(null, 64)) ->attribute('agreed', v::trueVal()) ->assert((object) $data);
      
      





name属性にルールを適用する方法に注目してください。 ここでは、クラスルールの名前がバリデータメソッドの名前に変換されました。 一般に、残りのルールは直感的です。







それとは別に、 $データ配列をオブジェクトにキャストする理由に言及する価値があります。 事実は、Respect Validationは配列ではなく入力としてオブジェクトを受け入れるということです。 このライブラリを使用して開発する場合は、これを考慮する必要があります。







フィードバック



Aura.Filterとは異なり、Respectバリデーターは検証が失敗すると例外をスローします。 また、この例外には検証エラーメッセージが含まれています。 したがって、今示した例は次のように記述する必要があります。







 try { v::with('RespectValidationExample\\'); v::attribute('name', v::userNameRule()) ->attribute('login', v::alnum('-_')) ->attribute('email', v::email()) ->attribute('password', v::notEmpty()->stringType()->length(null, 64)) ->attribute('agreed', v::trueVal()) ->assert((object) $data); } catch (NestedValidationException $ex) { $messages = $ex->getMessages(); }
      
      





getMessages()を使用して、検証プロセス中にバリデーターが収集したすべてのメッセージのフラット配列を取得します。 配列をダンプすると、次のような結果が得られます。







 array(5) { [0] => string(29) “Data validation failed for %s” [1] => string(60) “login must contain only letters (az), digits (09) and “-_”” [2] => string(25) “email must be valid email” [3] => string(26) “password must not be empty” [4] => string(32) “Attribute agreed must be present” }
      
      





メッセージは自分で交換できます。 おそらく私はこのライブラリを何らかの形で誤解しているかもしれませんが、このプロセスは私にはそれほど明白ではないようです。処理された例外でfindMessages()メソッドを使用する必要があります。







 $ex->findMessages([ 'userNameRule' => '      .', 'alnum' => '    .', 'email' => '       e-mail.', 'notEmpty' => '     ?', 'agreed' => ',    .' ]);
      
      





間違いが何なのかはわかりませんが、理解できなかったことがいくつかあります。 上記の方法でルールを定義すると、次のようになります。







 array(5) { [0] => string(40) “      .” [1] => string(31) “    .” [2] => string(25) “email must be valid email” [3] => string(5) “     ?” [4] => string(9) “,    .” }
      
      





ご覧のとおり、電子メールフィールドのメッセージは適用されず、標準のままです。 しかし、インデックス4の背後にあるメッセージは逆です! これは、ルールの名前ではなく、フィールドの名前を使用したにもかかわらずです。 一方、ルールの名前(trueVal)を使用した場合、メッセージはどこかで失われます。 このライブラリの経験豊富なユーザーによるコメントは大歓迎です。







シリウス検証



では、次のライブラリに移り、同様のタスクをどのように処理するかを見てみましょう。







ルールを定義する



繰り返しますが、ユーザー名のルールを定義する必要があります。 次のように記述します。







 class UserNameRule extends AbstractRule { //    const MESSAGE = '      .'; const LABELED_MESSAGE = '{label}     .'; public function validate($value, $valueIdentifier = null) { return (bool) preg_match('/^[A-Za-z]+\s[A-Za-z]+$/u', $value); } }
      
      





すでに検討されているライブラリと比較したアプローチの違いに注意してください。 プロパティ、メソッド、またはルール引数を使用するのではなく、定数で2種類のメッセージを定義します。







次に、検証ロジックについて説明します。







 $validator = new Validator; $validator ->add('name', 'required | MyApp\Validation\Rule\UserNameRule') ->add('login', 'required | alphanumhyphen', null, '     ,   .') ->add('email', 'required | email', null, ',   e-mail.') ->add('password', 'required | maxlength(64)', null, ' , .') ->add('agree', 'required | equal(true)', null, '    ?');
      
      





ご覧のとおり、ルールのセットは非常にシンプルで読みやすいです。 説明のために、水平ダッシュで区切られた名前を使用します。 このアプローチは、LaravelとKontrolioで使用されているアプローチに似ています。







add()メソッドの4番目の引数は、検証が失敗した場合にSiriusが使用する検証エラーメッセージを示します。 新しいUserNameRuleルールにメッセージを追加しなかったのはなぜですか?







 $validator->add('name', 'required | MyApp\Validation\Rule\UserNameRule')
      
      





これは、メッセージがクラス定数で既に記述されているためです。







 class UserNameRule extends AbstractRule { //    const MESSAGE = '      .'; ...
      
      





別のオプションは、バリデーター自体のaddMessage()メソッドを使用することです。







 $validator->addMessage('email', ',   e-mail.');
      
      





カスタムルールはクラスのフルネームで識別されますが、Kontrolioではエイリアス/エイリアスを設定できます。







フィードバック



検証を実行するには、バリデーターのvalidate()メソッドを呼び出し、データを渡します:







 $data = [ 'name' => '', //     'login' => '@lbert', // ""  @ 'email' => '-  ', //    e-mail 'password' => '' //     // 'agreed'   ,       ]; $validator->validate($data);
      
      





Respectとは異なり、Siriusは例外をスローせず、単にfalseを返します 。 検証エラーメッセージは、 getMessages()バリデータメソッドを介して取得できます。 属性ごとにグループ化されたエラーを返すため、エラーを通過するには2つのforeachループが必要です。







 foreach ($validator->getMessages() as $attribute => $messages) { foreach ($messages as $message) { echo $message->getTemplate() . "\n"; } }
      
      





ここで、$ messageはSirius \ Validation \ ErrorMessageクラスのオブジェクトであり、必要なメッセージを返すgetTemplate()メソッドがあります。







バリトロン



さらに進みましょう。 別の興味深いソリューションは、 Valitronです。 バリトロンは、検証ルールの追加と記述の実装において他と異なります。







ルールを定義する



最初の違い:新しいルールを追加するには、別のクラスを作成する必要はありません。 ブール値の結果を返すクロージャを使用するだけです。







カスタムルールを追加するために、Valitronには静的なaddRule()メソッドがあります。このメソッドでは、最初の2つの引数が必須で、3番目の引数はオプションです。 ここでは、ルールの識別子、ロジック、エラーメッセージがすぐに1か所に表示されるため、この方法が気に入りました。







 use Valitron\Validator; Validator::addRule('two_words', function($field, $value) { return (bool) preg_match('/^[A-Za-z]+\s[A-Za-z]+$/u', $value); }, '       .');
      
      





2番目の違いは、ルールが属性に適用される方法です。 これまでのすべてのケースで、属性が本来のものであることがわかりました。







Valitronは逆の方法で、最初に検証ルールを設定しました。 ルールを記述するとき、これらのルールに属性を適用します。逆の場合も同様です。







 $validator = new Validator($data); $validator ->rule('two_words', 'name')->label('') ->rule('required', [ 'name', 'login', 'email', 'password', 'agreed' ]) ->rule('slug', 'login') ->rule('email', 'email') ->rule('accepted', 'agreed');
      
      





例からわかるように、 rule()メソッドでは、最初にルールの名前を記述し、次にこのルールに対応する必要のある属性を指定します。 より明白な例は、このルールに属性がどのように「属する」かを示すrequired



ルールです。







Valitron(および私たちが検討したその他のソリューション)は、標準エラーメッセージを提供します。 それらを単純に使用すると、各メッセージが対応する属性の名前で始まることがわかります。







標準以外のエラーメッセージが使用されている場合でも、Valitronはメッセージ本文の属性名を置き換えます。 そのため、空の文字列でlabel()メソッドを使用して属性名を削除しました。







 $validator->rule('two_words', 'name')->label('')
      
      





フィードバック



具体的には、検証に関しては、ValitronライブラリAPIは、この記事で既に見たものとほとんど変わりません。 検証を実行するには、 validate()バリデータメソッドを呼び出します。







 $validator->validate();
      
      





検証エラーメッセージは、 getErrors()メソッドを使用して取得できます。







 $validator->errors();
      
      





ここでのメッセージは、Sirius Validationと同じ方法で属性によってグループ化されますが、メッセージ用の個別のクラスはなく、通常の多次元配列を取得します。







 foreach ($validator->errors() as $attribute => $messages) { foreach ($messages as $message) { echo $message . "\n"; } }
      
      





コントロリオ



そして最後に、今日の最後のライブラリはKontrolioと呼ばれる私自身の開発です







ルールを定義する



繰り返しになりますが、5回目は、ユーザー名の検証ルールを作成します。 すべてが比較的シンプルで標準的です:







 namespace MyProject\Validation\Rules; use Kontrolio\Rules\AbstractRule; class TwoWords extends Kontrolio\Rules\AbstractRule { public function isValid($input = null) { return (bool) preg_match('/^[A-Za-z]+\s[A-Za-z]+$/u', $input); } }
      
      





次に、ファクトリを作成し、 extend()メソッドを使用してその中にルールを登録します。







 namespace MyProject; use Kontrolio\Factory; use MyProject\Validation\Rules\TwoWords; $factory = Kontrolio\Factory::getInstance()->extend([TwoWords::class]);
      
      





ルールを登録した後、名前でtwo_words



を含めて使用できます。 バリデーターを作成しましょう:







 $data = [ 'name' => '', //     'login' => '@lbert', // ""  @ 'email' => '-  ', //    e-mail 'password' => '' //     // 'agreed'   ,       ]; $rules = [ 'name' => 'two_words', 'login' => 'sometimes|alphadash', 'email' => 'email', 'password' => 'length:1,64', 'agreed' => 'accepted' ]; $messages = [ 'name' => '      .', 'login' => '    .', 'email' => '       e-mail.', 'password' => '     ?', 'agreed' => ',    .' ]; $validator = $factory->make($data, $rules, $messages);
      
      





より詳細なバージョンを使用することもできますが、Laravelで使用される構文と同様の構文を使用してルールを説明しました。







 $rules = [ 'name' => new TwoWords, 'login' => [new Sometimes, new Alphadash], 'email' => new Email, 'password' => new Length(1, 64), 'agreed' => new Accepted ];
      
      





フィードバック



検証は、同じvalidate()メソッドで開始されます。







 $validator->validate();
      
      





getErrors()またはgetErrorsList()メソッドのいずれかを使用してエラーメッセージを取得できるようになりました。 最初のメソッドはより複雑なエラー出力を可能にし、2番目のメソッドはフラット配列を返します。 getErrors()を使用して、次のようなメッセージを表示できます。







 <ul class="errors"> <?php foreach ($errors as $attribute => $messages): ?> <li class="errors__attribute"> <b><?= $attribute; ?></b> <ul> <?php foreach ($messages as $message): ?> <li><?= $message; ?></li> <?php endforeach; ?> </ul> </li> <?php endforeach; ?> </ul>
      
      





また、 getErrorsList()を使用すると、メッセージのより単純なリストを作成できます。







 <?php $errors = $validator->getErrorsList(); ?> <ul class="errors"> <?php foreach($errors as $error): ?> <li class="errors__error"><?= $error; ?></li> <?php endforeach; ?> </ul>
      
      





まとめ



この記事では、次のライブラリーの使用例を示しました。







  1. Aura.filter

  2. 検証の尊重

  3. シリウス検証

  4. バリトロン

  5. コントロリオ



「実世界の例」は単純すぎるように思えるかもしれません。 確かに、ライブラリの機能の一部は記事に含まれていないため、同意する必要があります。 原則として、それがあなたにとって興味深い場合は、自分でその機能を調べることができます。







各ライブラリは独自のチップを提供し、その暗い側面を持っているので、好みとタスクの問題だと思う-それを選択すること。







読んでくれてありがとう。 正しい選択をしてください。








All Articles