Laravelでバリューオブジェクトのみを実装する
どうも、くずき(@kzkohashi)です。
今回はDDD
における、バリューオブジェクトをLaravel
でどう表現するかについて書きたいと思います。
なぜバリューオブジェクト?
DDD
を学んでいる中で、実際にどうやったら実装に落とし込めるだろうか?って考えたときに、一番最小構成であるバリューオブジェクトから手をつけたほうがいいんじゃないかという話になった。
(もちろんユビキタス言語などを見つけてからの前提)
実装
Eloquent
から返却される値をすべてバリューオブジェクトにしてたら、時間も手間もかかってしまうので、一部ずつ変えていく。
今回はUser
の1カラムであるEmail
を例に変更してみる。
バリューオブジェクトの生成
<?php class Email implements \JsonSerializable { /** * @var string */ protected $value; /** * @param string $value */ protected function __construct(string $value) { if (is_null($value)) { throw new \InvalidArgumentException("Argument must be set. Passed value is empty"); } // 正しいメールアドレスかのチェック if (preg_match('/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/iD', $value)) { throw new \App\Exceptions\EmailException(); } $this->value = $value; } /** * @return string */ public function value(): string { return $this->value; } /** * @param $string * @return bool */ public function equals(self $string) { return $this->value === $string->value; } /** * @param string $value * @return static */ 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; } }
construct
では、バリューオブジェクトを作成する際のルールなどを書いておく。
JsonSerializable
を継承しておく理由としては、response()->json
などを使用する際に、バリューオブジェクト->値
などになるため入れておいたほうが良さそう。
モデル
<?php class User extends Models { public function toValueObject() { // イミュータブルにするため $replication = $this->replicate(); // すでに作成してあるバリューオブジェクトを入れる $replication->email = new Email($this->email); return $replication; } }
実際の利用方法
<?php // カラムをバリューオブジェクトに変換 $user = User::find(1)->toValueObject(); // バリューオブジェクトの振る舞いを利用 $user->email->xxxx();
こんな形で利用している。
ただ、ロジックが大きくなってしまう仕様や、判定ロジックは外部に切り出したりしている。
ここガッツリ書けなかったので、この方の記事が参考になると思います。
また、バリューオブジェクト=不変性だと思っていたのですが、かとじゅんさんが昔に書いた記事が参考なります。
感想
DDD
が書いてある本などを読んでいると、設計方法はやんわりわかったけど実際動いてるコードはどこから手をつけたらいいかわらかなかった。
今回はバリューオブジェクトから始めることによって、ドメインロジックに集中するって大切さが少しわかってきた。