0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【CakePHP】バリデーションをCakePHPらしく書いてみる

Posted at

あけましておめでとうございます!🎍(遅くなってしまいましたね)
今回はCakePHPらしいバリデーションを実装してみました。

前回の記事

前回から機能を少し追加して、このようになりました。(画像は入力せずにボタンを押した状態)

image.png

追加した点としては
・項目の追加
・リセットボタンの追加
・バリデーションの追加
です。

ということで、バックエンドのAPIを見てみましょう。

ApiController.php(抜粋)
public function echoMessage()
    {
        // POSTリクエストのみを許可
        $this->request->allowMethod(['post']);
        // クライアントから送られてきた 'message''item' を取得
        $message = $this->request->getData('message');
        $item = $this->request->getData('item');
        $data = $this->request->getData();
        $errors = [];

        // バリデーション
        if (empty($data['message'])) {
            $errors['message'] = 'message は必須です';
        }
        if (empty($data['item'])) {
            $errors['item'] = 'item は必須です';
        }

        // エラーがあれば即返す
        if (!empty($errors)) {
            return $this->response
                ->withStatus(422)
                ->withType('application/json')
                ->withStringBody(json_encode([
                    'errors' => $errors,
                ], JSON_UNESCAPED_UNICODE));
        }

        // JSONレスポンスを返す(中に文字が入れられてる正常な時)
        return $this->response
            ->withStatus(200)
            ->withType('application/json') // JSONフォーマットであることを明示
            ->withStringBody(json_encode([
                'message' => $message,
                'item'=>$item,
            ],JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); // レスポンスボディにメッセージを詰める
    }

バリデーションをControllerに直接書いています。もう少し改善できそうな気がします。
CakePHPのバリデーションを使えば、すっきり書けそうです。
そこで、これをリファクタリングしたいと思います。
今回はバリデーションをValidatorクラスに書く→呼び出すということをしていきます。

ここから本編

CakePHPにはバリデーションのクラスとメソッドがあります↓
https://book.cakephp.org/5/ja/core-libraries/validation.html
これを使って書き直していきます。

分離するメリットとしては以下の通りです。

  • バリデーションルールが複雑になった時のControllerの肥大化を避けられる
  • バリデーションルールをクラス化すれば、他メソッドやControllerで簡単に呼び出せる(再利用性
  • バリデーションを追加したときに変更が1箇所で済む。Controllerの役割の明確化。(保守性
    ...などの理由から、今回は分離して書いていきます。

Validatorクラスを作成

src/Validation/ディレクトリを作成し、EchoMessageValidator.phpを作成します。

src/Validation/EchoMessageValidator.php
<?php
declare(strict_types=1);

namespace App\Validation;
use Cake\Validation\Validator;

class EchoMessageValidator
{
    public static function getValidator(): Validator
    {
        $validator = new Validator();
        $validator
            ->requirePresence('message', true, 'message は必須です') // フィールドが存在しない場合のエラー
            ->notEmptyString('message', 'message は必須です'); // 空文字列ではないかチェック
        $validator
            ->requirePresence('item', true, 'item は必須です')
            ->notEmptyString('item', 'item は必須です');

        return $validator;
    }
}

requirePresenceではフィールドがリクエストに存在するか、
notEmptyStringではフィールドが空でないか、チェックしています。
エラー文言は必要に応じて変更できます。

Controllerで呼び出す

echoMessageメソッドの中で呼び出します。
が、その前にファイル冒頭部分でインポートします。

src/Controller/ApiController.php
// 省略
use App\Validation\EchoMessageValidator; // 追加

class ApiController extends Controller
{  
    // 省略

次に、echoMessageメソッド内でValidatorの取得とバリデーション実行のための以下のコードを追加します。

src/Controller/ApiController.php
$validator = EchoMessageValidator::getValidator();
$errors = $validator->validate($data);

これでValidatorクラスを取得でき、バリデーションを効かせることができました。
echoMessage()メソッド全体は以下のようになりました。

src/Controller/ApiController.php
    public function echoMessage()
    {
        // POSTリクエストのみを許可
        $this->request->allowMethod(['post']);
        // クライアントから送られてきた 'message''item' を取得
        $message = $this->request->getData('message');
        $item = $this->request->getData('item');
        $data = $this->request->getData();

        // Validatorクラスを使ってバリデーションを実行
        $validator = EchoMessageValidator::getValidator();  // 追加。Validatorを取得
        $errors = $validator->validate($data);             // 追加。バリデーションを実行

        // エラーがあれば即返す
        if (!empty($errors)) {
            return $this->response
                ->withStatus(422)
                ->withType('application/json')
                ->withStringBody(json_encode([
                    'errors' => $errors,
                ], JSON_UNESCAPED_UNICODE));
        }

        // JSONレスポンスを返す(中に文字が入れられてる正常な時)
        return $this->response
            ->withStatus(200)
            ->withType('application/json')
            ->withStringBody(json_encode([
                'message' => $message,
                'item'=>$item,
            ],JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
    }

バリデーション部分を2行で収めることができました。
このように分けることで、今後バリデーションを増やした場合のControllerの肥大化を防ぐことができます。また、同じバリデーションを別のメソッドで使用するときに呼び出すことができます。

あとがき

これのフロント側についてはまた別記事でまとめたいと思っています。
最後までお読みいただきありがとうございました!
アドバイス・質問等あればコメントにお願いします。
また次回の記事でお会いしましょう!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?