PHPでパラメータのバリデートユーティリティを作ってみた

コントローラのメソッド上部に並ぶパラメータのバリデーションの塊・・・嫌ですね。
なんとかスッキリさせたいと思い、試行錯誤した結果以下のようなものができました。

# ターゲット
例えばこんなコード。ため息でる。
こんなコードそもそも書かない？それは素晴らしい！

```php
$roomName      = isset($_GET["room_name"]) ? $_GET["room_name"] : null;
$remoconTypeId = isset($_GET["remocon_type_id"]) ? $_GET["remocon_type_id"] : null;
$operationId   = isset($_GET["operation_id"]) ? $_GET["operation_id"] : null;
$startTime     = isset($_GET["start_time"]) ? $_GET["start_time"] : null;
$endTime       = isset($_GET["end_time"]) ? $_GET["end_time"] : null;

// チェック処理
if($roomName == null) {

    echo "ルーム名 が未入力です。";
    return;
}
else if(!in_array($roomName, ['A', 'B', 'C'])) {

    echo "不正な ルーム名 です。";
    return;
}

if($remoconTypeId == null) {

    echo "リモコン種別 が未入力です。";
    return;
}
else if(!is_numeric($remoconTypeId)) {

    echo "不正な リモコン種別 です。";
    return;
}

if($operationId == null) {

    echo "操作種別 が未入力です。";
    return;
}
else if(!is_numeric($remoconTypeId)) {

    echo "不正な 操作種別 です。";
    return;
}

if($startTime != null && $startTime !== date("Y-m-d H:i:s", strtotime($startTime))) {

    echo "不正な 開始日付 です。";
    return;
}

if($endTime != null && $endTime !== date("Y-m-d H:i:s", strtotime($endTime))) {

    echo "不正な 終了日付 です。";
    return;
}
```

# 共通化する
パラメータの存在チェックと、任意のバリデートがかけられるような共通関数を作りました。
オプショナルなパラメータについては、パラメータが存在するときのみバリデートをかけます。
エラーメッセージのバリエーションについては一旦無視します。`$validationList`に`error`とかってキーでエラーメッセージ持たせればできそうですが。

```php
public function validateParams($params, $validationList) {

    foreach ( $validationList as $validation ) {

        // existance
        $key = $validation["key"];
        $optional = isset($validation["optional"]) ? $validation["optional"] : false;
        if ( !$optional && !isset($params[$key]) ) {
            $error = [
                "error" => "missing params",
            ];
            $this->response($error); // レスポンスを返す関数
            exit;
        }

        // other validations
        $validate = $validation["validate"];
        if ( $optional && !isset($params[$key]) ) {
            continue;
        }
        $param = $params[$key];
        if ( !$validate($param) ) {
            $error = [
                "error" => "invalid params",
            ];
            $this->response($error); // レスポンスを返す関数
            exit;
        }
    }
}
```

# 共通関数を呼び出す
第一引数にチェックしたいパラメータ、第二引数にチェックしたい条件をまとめた配列を作って渡します。

```php
$params = $_GET;
$this->validateParams(
    $params,
    [
        [
            "key"      => 'room_name',
            "validate" => function($param) {return in_array($param, ['A', 'B', 'C']);},
        ],
        [
            "key"      => 'remocon_type_id',
            "validate" => function($param) {return is_numeric($param);},
        ],
        [
            "key"      => 'operation_id',
            "validate" => function($param) {return is_numeric($param);},
        ],
        [
            "key"      => 'start_time',
            "validate" => function($param) {return $param === date("Y-m-d H:i:s", strtotime($param));},
            "optional" => true,
        ],
        [
            "key"      => 'end_time',
            "validate" => function($param) {return $param === date("Y-m-d H:i:s", strtotime($param));},
            "optional" => true,
        ],
    ]
);
```

# おわりに
多少良くはなったけど、筋がいい感じはしない。やっぱりフレームワークのバリデート使うのがいいんですかね。
そもそもターゲットのコードがひどすぎると言われたらその通りです。でもこの世には結構存在するんですよ。。。しかも色々な事情でリファクタリングしにくいってのが。。。