【Laravel x DDD】 完全コンストラクタで生成ルールを定義する

Laravel とDDDで実現するDomainModelの完全コンストラクタ

DomainModelを生成時に、値をvalidateして内容を担保していく方法を書いていきます。

流れは下記になります

validate → new DomainModel()

しかし、validate()をせずにインスタンス生成してしまうことも可能ですよね

$publicArticle = new PublicArticle($title, $body)
// validateしなくてもインスタンス生成可能

そこで、インスタンス生成時にvalidate()処理を必須化させて、値を担保していきたいと思います。

目次

DomainModelでvalidate()を必須化させる。

インスタンス生成処理をprivateにする。

まずインスタンス生成処理をpublicではなくprivateメソッドにします。

phpのインスタンス生成メソッド__construct()ですが、通常だとpublicで定義されています。

    public function __construct(
        string $title,
        string $body,
    )
    {
        $this->title = $title;
        $this->body = $body;
    }

public()だとどこでもnew DomainModel()でインスタンスを生成できてしまいます。

$publicArticle = new PublicArticle($title, $body)
// validateしなくてもインスタンス生成可能


なので、__construct()privateメソッドにして、制限します。

    private function __construct(
        string $title,
        string $body,
    )
    {
        $this->title = $title;
        $this->body = $body;
    }

これにより、DomainModel内のメソッドでしかインスタンスを生成できません

new PublicArticle($title, $body)
//エラー Call to private Domain\DomainModel\PublicArticel::__construct()

では続いて、代わりにインスタンスを生成するメソッドを作ります。

validate()が必須とするmake()を追加

ここでは、インスタンス生成処理をmake()に限定させます。

make()処理内でvalidate()させてから、new self()を実行させます。

    /**
     * インスタンス生成処理
     *
     * @param string $title タイトル
     * @param string $body 本文
     * @return self $this
     */
    public static function make(string $title, string $body): self
    {
        $validated = self::validate($title, $body); // バリーでションした値を取得

        // validationした値を元にインスタンスを生成
        return new self(
            $validated['title'],
            $validated['body'],
        );
    }

これでインスタンス生成時は、必ずvalidate()していることになります。

複数ある入り口を一つ絞ったので、当然validate()されているという考え方です。

validate()の中身を書いていく

では続いてvalidate()を作成していきましょう

    /**
     * バリデーション
     *
     * @param string $title タイトル
     * @param string $body 本文
     * @return array
     */
    private static function validate (string $title, string $body): array
    {
        $values = [
            'title'           => $title,
            'body'            => $body,
        ];

        $rules = [
            'title'             => ['required', 'string', 'max:50'],
            'body'              => ['required', 'string'],
        ];
        
        $validator = Validator::make($values, $rules);

        if ($validator->fails()) {
            throw new Exception('お知らせ公開に必要な情報が不足しています。');
        }

        return $validator->validated();
    }

これでvalidate()された値を渡されて安心ですね

全体像

下記3点をそろいました。

  • privateでインスタンス生成:__construct()
  • コンストラクトを実行してインスタンスを生成:make()
  • バリデーション実施メソッド: validate()

このメソッドを使ってvalidate()をさせた値で無事にDomainModelを生成できましたね。

それでは最後に全体像を見ていきましょう!

<?php

namespace App\Packages\Article\Domain\DomainModel;

use Illuminate\Support\Facades\Validator;

/**
 * 公開する記事
 */
class PublicArticle
{

    /**
     * タイトル
     *
     * @var string
     */
    public string $title;

    /**
     * お知らせの本文
     *
     * @var string
     */
    public string $body;

    /**
     * 公開日時
     *
     * @var CarbonImmutable
     */
    public CarbonImmutable $published_at;

    private function __construct(
        string $title,
        string $body,
        CarbonImmutable $published_at,
    )
    {
        $this->title = $title;
        $this->body = $body;
        $this->published_at = CarbonImmutable::now();
    }

    /**
     * インスタンス生成処理
     *
     * @param string $title タイトル
     * @param string $body 本文
     * @return self $this
     */
    public static function make(string $title, string $body): self
    {
        $validated = self::validate($title, $body);
        
        return new self(
            $validated['title'],
            $validated['body'],
        );
    }

    /**
     * バリデーション
     *
     * @param string $title タイトル
     * @param string $body 本文
     * @return array
     */
    private static function validate (string $title, string $body): array
    {
        $values = [
            'title' => $title,
            'body'  => $body,
        ];

        $rules = [
            'title' => ['required', 'string', 'max:50'],
            'body'  => ['required', 'string'],
        ];
        
        $validator = Validator::make($values, $rules);

        if ($validator->fails()) {
            throw new Exception('お知らせ公開に必要な情報が不足しています。');
        }

        return $validator->validated();
    }
}

今回はvalidate()だけになりますが、もっと複雑なルールを取り入れてもいいと思います。

これで以上となります

最後まで読んでいただき、ありがとうございます😄

ぎゅう
WEBエンジニア
渋谷でWEBエンジニアとして働く。
LaravelとVue.jsをよく取り扱い、誰でも仕様が伝わるコードを書くことを得意とする。
先輩だろうがプルリクにコメントをして、リファクタしまくる仕様伝わるコード書くマン
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次
閉じる