Skip to content

Instantly share code, notes, and snippets.

@hakomo
Created July 19, 2014 21:03
Show Gist options
  • Save hakomo/595a31fbddba345d7604 to your computer and use it in GitHub Desktop.
Save hakomo/595a31fbddba345d7604 to your computer and use it in GitHub Desktop.
Mylight Framework Validator class

愚直なバリデーションが、

<?php
$isError = false;
if(!$isError && !isset($_GET['id']))
    $_GET['id'] = 0;
if(!$isError && !is_numeric($_GET['id'])) {
    $isError = true;
    $error = 'ユーザ ID は整数です';
}
if(!$isError)
    $_GET['id'] = intval($_GET['id']);
if(!$isError && !($_GET['id'] < 100)) {
    $isError = true;
    $error = 'ユーザ ID は100未満の整数です';
}
if(!$isError) {
    $id = $_GET['id'];
    // バリデーションに成功するときの処理
} else {
    // バリデーションに失敗するときの処理
}

バリデータクラスだとこうなります。重複したり本質的ではないコードが減って、見通しが良くなります

<?php
$v = (new Validator)
    ->setDefault(0, 'set')
    ->setError('##は整数です', 'integer')
    ->set('intval')
    ->setError('##は100未満の整数です', '<', 100);
if($v->validate('get', 'id', 'ユーザ ID ')) {
    $id = $v->get();
    // バリデーションに成功するときの処理
} else {
    $error = $v->getError();
    // バリデーションに失敗するときの処理
}

Validator::setDefault, Validator::setErrorの第2引数には関数を渡すこともでき、複雑なバリデーションも可能です

<?php
$v = (new Validator)
    ->setError('##は奇数です', function($value) {
        return $value % 2 === 1;
    });

要検討

保守的に設計しましたが、保守的であることが初心者向けであるとは限らないので、意見をお伺いしたいです

Pythonはインスタンスを作るのにnewが入りません。PHPでまねするとこうなります

<?php
class Validator {
    public set() {}
}

function Validator {
    return new Validator;
}

// ださい
(new Validator)->set();

// スマート
Validator()->set();

メソッド名のset, getはいらないでしょうか?
Validator::setErrorよりもValidator::errorのほうが打ちやすいですしすっきりしますが、私は可読性が下がっている気がします

set, integer, <, emailAddressなどのバリデーション案を共有しましょう!

@foresta
Copy link

foresta commented Jul 21, 2014

全体的に使いやすそうだなーと感じました。
特にメソッドチェーンでかけるのは、記述量も減るしいいと思います!
以下に、質問項目と、バリデート項目を列挙したんで暇なときにでも目をお通しください。

質問

setErrorメソッドでバリデートをかけてるんですか?
ぱっと見な印象としては、ちょっとメソッドの役割がわかりづらいかなーと感じました。
'set', 'interger' , 'intval', などの文字列がどういった意味をもつのかがわからなかったです。

バリデート項目

  • 整数
  • メールアドレス
  • 電話番号
  • 郵便番号
  • < , > , <= , >=
  • 間(between)
  • 空チェック

くらいしか思い浮かばないです。

@hakomo
Copy link
Author

hakomo commented Jul 21, 2014

setErrorメソッドでバリデートをかけてるんですか?

はい、バリデートをして駄目だったらエラーメッセージをセットしています
ただし、実際にバリデートが行われるのはVaridator::validate呼び出し時です

メソッドの役割がわかりずらい

Validator::setErrorはバリデートをして駄目だったらエラーメッセージをセット
Validator::setDefaultはバリデートをして駄目だったらデフォルト値を代入と
一度に二つのことをしているのでわかりやすいメソッド名があったら教えてください!

set, integerなどの文字列の意味がわからない

set値がsetされている(空ではない)
integer値が整数型である
emailAddress値がEmail Addressに即している

空を許さなければset、整数じゃないと駄目ならintegerみたいな イメージです
これも自由に変えられるのでいい命名があったら教えてください!

バリデート項目ありがとうございます!

@foresta
Copy link

foresta commented Jul 21, 2014

提案

案1

validatorクラスに下記のようなバリデーションメソッドを持たせる。

<?php
class Validator {
    public function isNumber(){} // 整数チェック
    public function isMailAddress(){} // メールアドレスチェック
    public function isNotEmpty(){} // 空チェック
} 

案2

バリデートルールをセットしバリデートを行う。
バリデートルールはValidatorクラスに標準なものを用意して、拡張したときだけ
ユーザがルールを追加するという仕様です。
下記はメールアドレスとパスワードにバリデートをかける例です。

<?php

$email = Request::getPost("email_address");
$pass = Request::getPost("pass");

// ユーザが独自にバリデートルールを作成する方法
$emailRule = array(
        'required' => true,    // 必須項目(空を許可しない)
        'format' => 'email_address' // メールアドレスの形式チェック
        'error_message' => 'メールアドレスの形式が違います'
    );
// バリデートをかけて内部でエラーならば内部でエラーメッセージ生成
Validator()->setRule($emailRule)->validate($email);

// Validatorクラス標準のバリデートルールを使う方法
Validator()->validate($email, 'email_address');

// ユーザが独自にバリデートルールを作成する方法
$passRule = array(
        'required' => true,
        'format' => 'pass'    // 内部で半角英数と記号しか受けないバリデートをかける
        'min_length' => 8, // 最低文字数
        'max_length' => 12, // 最大文字数
    );
Validator()->setRule($passRule)->validate($pass);

// Validatorクラス標準のバリデートルールを使う方法
Validator()->setRule($passRule)->validate($pass, 'pass');

if (Validator()->isError()){
    $error = Validator()->getErrors();
    exit(); // エラー終了的ななにか
}

// ------- 以降エラーがなかったときの処理 ---------

とりあえず内部の実装は考えてないですが、こんな風につかえたらいいと思ってます。
※空を許さないときは「required」とするといいと思います。

@hakomo
Copy link
Author

hakomo commented Jul 21, 2014

案1

全体の流れでどのように使われるかが想像できないです!

案2

アリだと思います!

空だったとき、Email Adreessに即していないとき、長すぎるとき、デタベで重複しているとき
などでエラーメッセージは分けれないという認識で大丈夫でしょうか

@foresta
Copy link

foresta commented Jul 21, 2014

案1は忘れてください笑

案2はユーザがエラーメッセージを指定した場合は、そのエラーメッセージをだして、
指定しなかったら、内部でうまいことやってエラーに即したエラーメッセージがだせればいいかなー
と思ってます。ざっくりとですみません。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment