コンテンツに移動 ナビゲーションに移動

IT全般に関する雑記や技術ブログ。wordpressやPHP LaravelたまにPython

南の島のSE エンジニアブログ

PHP
  1. HOME
  2. PHP
  3. Laravel8 ログイン機能実装4 値オブジェクトを用いたバリデーション
2020年9月15日 / 最終更新日 : 2022年5月9日 syun03 PHP

Laravel8 ログイン機能実装4 値オブジェクトを用いたバリデーション

前回はlaravelを使って会員サイトの基本機能を構築しました。

しかし、これから機能を拡張していくことを考えると

内部構造を少し改良して、拡張性を高める必要があります。

そこで今回は「ドメイン駆動設計」の考え方を考慮しながら、機能拡張をしていきます。

目次
  • 1. ドメイン駆動設計(DDD)とは
  • 2. 手順
  • 2.1. 値オブジェクトの作成
  • 2.1.1. で、どうやるの
  • 2.2. クラスの説明
  • 2.2.1. コンストラクタ
  • 2.2.2. rules
  • 2.2.3. 値オブジェクトで表現できないルールについて
  • 2.2.4. value
  • 2.2.5. equals
  • 2.3. フォームリクエストの作成
  • 2.3.1. authorize
  • 2.3.2. rules
  • 2.3.3. messages
  • 2.4. フォームリクエストからメッセージを受け取る
  • 3. ログイン機能連載一覧

ドメイン駆動設計(DDD)とは

「ドメインモデリング」です。本稿では詳細は割愛しますが、

値オブジェクト(value object)とは、氏名や価格などの情報をドメインとしてとらえ

オブジェクトとして定義しようというものです。

ドメイン駆動設計を理解する上でもきっかけ重要な考え方です。

詳細に下記ご参考まで。

手順

ドメイン駆動設計を意識しながら、バリデーションロジックを拡張し

システムが大きくなってもメンテンナンス性が落ちないようなコードに修正していきます。

手順は下記の通りです。

  1. 値オブジェクトの作成
  2. フォームリクエストを作成
  3. フォームリクエストからメッセージを受け取る

値オブジェクトの作成

「電話番号」や「メールアドレス」「住所」など、同じ『文字列』ですが

それぞれ数字であったり@マークが必須だったり、変数としてのルールがあります。

この『ルールに従った入力のみ許す』ように制御するのが、バリデーションです。

ただ、前回構築したバリデーションロジックには課題があります。

下記が会員登録画面のコントローラーです。

    protected function validator(array $data)
    {
        Log::debug('validator');
        return Validator::make($data, [
            'login_id' => ['required', new alpha_num_check(), 'max:20','unique:users'],
            'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
            'password' => ['required','confirmed'],
            'zip-code' => ['required', 'string', 'max:7'],
            'prefecture' => ['required', 'string', 'max:5'],
            'city' => ['required', 'string', 'max:20'],
            'address1' => ['required', 'string', 'max:20'],
            'address2' => ['required', 'string', 'max:20'],
            'tel' => ['required', 'string', 'max:9'],
        ]);
    }

コントローラーにバリデーションロジックを記載しています。

では、今後会員情報の変更ページを作成した場合にバリデーション機能はどうなるでしょう。

    protected function validator(array $data)
    {
        Log::debug('validator');
        return Validator::make($data, [
            'login_id' => ['required', new alpha_num_check(), 'max:20','unique:users'],
            'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
            'password' => ['required','confirmed'],
            'zip-code' => ['required', 'string', 'max:7'],
            'prefecture' => ['required', 'string', 'max:5'],
            'city' => ['required', 'string', 'max:20'],
            'address1' => ['required', 'string', 'max:20'],
            'address2' => ['required', 'string', 'max:20'],
            'tel' => ['required', 'string', 'max:9'],
        ]);
    }

どこかで見たコードを書くことになりますね。

このように

同じ「ログインID」に対する登録機能があるたびに、バリデーションロジックを記載する必要が出てきてしまいます。

このようなコードを書いていると、画面によってバリデーションロジックが異なったりしてバグの温床になりかねません。

そこで、値をオブジェクトとして捉え、それぞれのオブジェクトに対してのルールはまとめて「コード自体がルールを表現する」ようにします。

で、どうやるの

サンプルコードです。氏名についての値オブジェクトとして記述しています。

namespace App\ValueObjects;

class Name implements ValueObject
{
    protected $value;

    /**
     * name constructor.
     * @param $value
     * @throws \Exception
     */
    public function __construct($value)
    {
        if(empty($value)){
            throw new \Exception(NAME.'は必須入力です');
        }

        if(!preg_match('%\D+%',$value)) {
            throw new \Exception(NAME.'を正しく入力してください');
        }

        if(mb_strlen($value) >; 21){
            throw new \Exception(NAME.'は20文字以内で入力してください');
        }

        $this->value = $value;
    }

    public static function rules(){
        return 'required|max:20|regex:%\D+%';
    }

      public function value()
      {
          return $this->value;
      }

      public function equals($string):bool
      {
          return $this->value === $string->value;
      }

    /**
     * @param string $value
     * @return static
     * @throws \Exception
     */
    public static function of(string $value)
    {
        return new static($value);
    }

    /**
     * @return string
     */
    public function __toString()
    {
        return (string)$this->value;
    }

    /**
     * @return mixed|string
     */
    public function jsonSerialize()
    {
        return $this->value;
    }

クラスの説明

コンストラクタ

登録機能以外にも氏名を扱う場面はありますので、その際にコンストラクタとして氏名を格納します。

セキュリティ観点でも、コンストラクタとして値を受け取った際のチェックロジックは必要です。

今回は「必須入力」「日本語」「20文字以内」というルールを表現しています。

rules

値オブジェクトのバリデーションルールを記述します。

登録画面や編集画面からこのクラスを呼び出すことで、システム全体でバリデーションロジックが統一できます。

複数のルールを記述する際には「|」で挟んでいきます。

記載可能なバリデーションルールはLaravelのマニュアルをご覧ください

https://readouble.com/laravel/8.x/ja/validation.html

値オブジェクトで表現できないルールについて

例えば、「パスワードは再入力項目と一致している事」などは会員登録画面に限定したロジックになります。

この場合は、登録画面のコントローラーにてバリデーションルールを追加します

    protected function validator(array $data)
    {
        Log::debug('validator');
        return Validator::make($data, [
            'password' => ['confirmed'],
        ]);
    }

value

コンストラクタから値を取り出すときに使います。

equals

コンストラクタの値との比較を行います。

その他クラスの説明は割愛します。

これを値オブジェクト分作成していきます。

フォームリクエストの作成

laravelのコマンドを使います。

php artisan make:request CustomerRegister

コマンド実行後、自動でファイルが作成されます。

app/Http/Requests/CustomerRegister.php

class CustomerRegister extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
	//① trueに変更する
        return false;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
	//② バリデーションルールを記載する
        return [
        ];
    }

    public function messages()
    {
	//③ バリデーションエラーメッセージを記載する
        return [
        ];
    }
}

authorize

認可の設定です。デフォルトではfalseになっていますが、trueに変更する必要があります。

falseのままだと下記の画面になります。

認可されていないというエラーです。画面は修正したいところですが、今後の対応とします。

rules

フォームに対してのバリデーションルールを記述します。

作成済みの値オブジェクトを利用すると下記のように記述できます。

    public function rules()
    {
        return [
            'address1' => Address1::rules(),
            'address2' => Address2::rules(),
            'city' => City::rules(),
            'email' => Email::rules(),
            'login_id' => Login_id::rules(),
            'password' => Password::rules(),
            'prefecture' => Prefecture::rules(),
            'tel' => Tel::rules(),
            'zip-code' => Zipcode::rules()
        ];
    }

すっきりしましたね。

messages

最後に、エラーメッセージをカスタマイズします。

    public function messages()
    {
        return [
            'required' => ':attribute の入力は必須です。'
        ];
    }

フォームリクエストからメッセージを受け取る

リクエストデータを登録機能に引き渡す処理にリクエストフォームのデータを引数として追加します。

Laravelの会員機能はトレイトを使っているため、下記が修正箇所になります。

src/Illuminate/Foundation/Auth/RegistersUsers.php

    public function register(CustomerRegister $request)
    {
        Log::debug('register');
        $this->validator($request->all())->validate();

        event(new Registered($user = $this->create($request->all())));

        $this->guard()->login($user);

        return $this->registered($request, $user)
                        ?: redirect($this->redirectPath());
    }

引数を今回作成したフォームリクエストに修正しています。

public function register(request $request)

↓

public function register(CustomerRegister $request)

これでドメイン駆動設計を意識したバリデーションロジックの完成です。

Laravelログイン機能連載一覧

  • Laravel 8でログイン機能実装1 基本機能
  • Laravel 8でログイン機能実装2 ログインIDの導入 
  • Laravel 8でログイン機能実装3 会員登録時の入力項目追加 
  • Laravel8でログイン機能実装4 ValueObjectとバリデーション ← いまここ
  • Laravel 8でログイン機能実装5 会員情報変更

  • クリックして Twitter で共有 (新しいウィンドウで開きます)
  • Facebook で共有するにはクリックしてください (新しいウィンドウで開きます)

関連記事

Laravel8でログイン機能実装2
Laravel 8でログイン機能実装2 ログインID導入
 2020年8月12日
Laravel8でログイン機能実装1
Laravel8でログイン機能実装1 基本機能導入編
 2020年8月7日
カテゴリー
PHP、Laravel
タグ
loginドメイン駆動設計

“Laravel8 ログイン機能実装4 値オブジェクトを用いたバリデーション”へ2件のコメント

  1. 匿名 より:
    2022年4月1日 6:31 PM

    分かりやすく助かっております。
    もしよろしければ以下を教えていただけないでしょうか?
    「で、どうやるの」の章の「class Name implements ValueObject
    {~~~」コードは、どのファイルに記述すべきでしょうか?
    新しくファイルを作成するべきでしょうか?

    返信
    1. syun03 より:
      2022年4月2日 3:19 PM

      こちらは新しくclassファイルを作成しています。
      ValueObjectごとにファイルを作成していっております。

      返信

コメントを残す コメントをキャンセル

wordpress
タグ一覧にカテゴリ表記追加

前の記事

wordpress タグ一覧にカテゴリ情報表示
2020年9月9日
PHP
Laravel8でログイン機能実装5 会員情報更新

次の記事

Laravel 8で会員サイト構築5 会員情報更新機能
2020年9月19日

検索

自己紹介

auther

南の島を愛するエンジニア
他にはない一歩踏み込んだ内容を心がけています。PHP/Phtyonでの開発やwordpressのカスタマイズ
【IPA資格マニア】
ITストラテジスト/ ITアーキテクト/ 情報セキュリティスペシャリスト

ココナラで活動中 お仕事のご依頼はこちら
ランサーズはこちら お仕事承ります

人気記事

カテゴリー

  • Python (4)
    • Django (4)
  • システム構築 (6)
  • PHP (16)
    • Laravel (16)
  • wordpress (31)
    • WooCommerce (5)
    • welcart (2)
  • ライフスタイル (1)
    • 副業 (1)
  • セキュリティ (1)
  • 資格 (23)
    • プロジェクトマネージャ (3)
    • システムアーキテクト (3)
    • ITストラテジスト (4)
    • 情報処理安全確保支援士 (12)
  • その他 (6)

タグ

AWS (1) laravel-admin (4) login (3) SalonBookingSystem (5) simple-membership (3) stripe (5) subscription (1) wp-members (10) ドメイン駆動設計 (1) 会員サイト (1)

目次

  • 1 ドメイン駆動設計(DDD)とは
  • 2 手順
    • 2.1 値オブジェクトの作成
    • 2.2 クラスの説明
    • 2.3 フォームリクエストの作成
    • 2.4 フォームリクエストからメッセージを受け取る
  • 3 Laravelログイン機能連載一覧

当サイトについて

TOP |
プライバシーポリシー |
お問合せ

カテゴリー

  • Python
    • Django
  • システム構築
  • PHP
    • Laravel
  • wordpress
    • WooCommerce
    • welcart
  • ライフスタイル
    • 副業
  • セキュリティ
  • 資格
    • プロジェクトマネージャ
    • システムアーキテクト
    • ITストラテジスト
    • 情報処理安全確保支援士
  • その他

タグ

  • laravel
  • login
  • wp-members
  • 会員サイト
  • ドメイン駆動設計
  • simple-membership
  • stripe
  • SalonBookingSystem
  • laravel-admin
  • subscription
  • AWS

最近の投稿

【試験対策】基本情報技術者試験 新方式解説
2022年6月26日
Stripe Apps Stripe APIで会員情報取得
Stripe AppsからStripe API実行【Stripe Appsで決済ワークフロー自動化3】
2022年6月21日
Stripe Appsで決済フロー自動化2
Stripe AppsのUIデザイン【Stripe Appsで決済ワークフロー自動化2】
2022年6月13日
Stripe Appsでワークフロー自動化
Stripe Appsの概要【Stripe Appsで決済ワークフロー自動化1】
2022年6月11日
Stripeロゴ
Stripeセッション2022と最新アップデート
2022年6月4日

Copyright © 南の島のSE エンジニアブログ All Rights Reserved.

MENU
  • HOME