othercodes / ddd-value-object
v1.1.0
2020-10-16 13:26 UTC
Requires
- ext-json: *
- konekt/enum: ^3.0
- nesbot/carbon: ^2.40
- ramsey/uuid: ^4.1
Requires (Dev)
- fzaninotto/faker: ^1.9
- mockery/mockery: ^1.4
- phpunit/phpunit: ^9.3
This package is auto-updated.
Last update: 2021-06-16 09:08:00 UTC
README
一个小型库,可轻松管理值对象模式。
安装
使用以下命令通过 composer
进行安装
composer require othercode/ddd-value-object
这将自动获取最新版本并配置 composer.json
文件。
或者,您可以创建以下 composer.json
文件并运行 composer install
以进行安装。
{ "require": { "othercode/ddd-value-object": "*" } }
用法
构建值对象非常简单,您只需扩展 ValueObject
类。接下来,通过使用 initialize
方法在构造函数中初始化值。最后,添加不变规则为受保护方法,使用前缀 invariant
(此前缀可以自定义)并使用 checkInvariants
方法执行它们。
<?php declare(strict_types=1); class Speed extends OtherCode\DDDValueObject\ValueObject { public const KILOMETERS_PER_HOUR = 'km/h'; public const MILES_PER_HOUR = 'm/h'; public function __construct(int $amount, string $magnitude) { $this->initialize([ 'amount' => $amount, 'magnitude' => $magnitude ]); $this->checkInvariants(); } protected function invariantSpeedMustBeGreaterThanZero(): bool { return $this->amount() > 0; } protected function invariantMagnitudeMustBeValid(): bool { return in_array($this->magnitude(), [ self::KILOMETERS_PER_HOUR, self::MILES_PER_HOUR ]); } public function amount(): int { return $this->get('amount'); } public function magnitude(): string { return $this->get('magnitude'); } public function increase(Speed $speed): self { if ($speed->magnitude() !== $this->magnitude()) { throw new InvalidArgumentException('The given magnitude is not valid.'); } return new self($this->amount() + $speed->amount(), $this->magnitude()); } public function __toString(): string { return $this->amount() . $this->magnitude(); } }
相等性
值相等性通过序列化对象并使用 sha256 算法对其进行哈希计算得出。或者,您可以通过重写 equalityHash
来计算对象的适当哈希值。此哈希值用于检查值对象是否相等。
<?php declare(strict_types=1); class Speed extends OtherCode\DDDValueObject\ValueObject { // ... public function equalityHash(): string { return md5(sprintf('$s %s', $this->amount(), $this->magnitude()); } // ... }
不可变性
不可变属性阻止对值的任何修改尝试,这将导致异常
$s = new Speed(120, 'km/h'); $s->amount = 123; // PHP Fatal error: Uncaught OtherCode\DDDValueObject\Exceptions\ImmutableValueException: Illegal attempt to change immutable value.
您可以通过重写 immutabilityException
属性来自定义将被抛出的异常。同样,对于错误消息,您只需要重写 immutabilityMessages
属性。
<?php declare(strict_types=1); class Speed extends OtherCode\DDDValueObject\ValueObject { // ... protected string $immutabilityException = SomeCustomException::class; protected array $immutabilityMessages = [ 'default' => 'You shall not update this value!.', ]; // ... }
不变性
不变性方法必须返回一个布尔值,true
如果成功,否则 false
。如果违反任何不变性,您将获得一个异常
<?php $s = new Speed(-1, 'm/s'); // PHP Fatal error: Uncaught InvalidArgumentException: Unable to create Speed value object due: // invariant speed must be greater than zero // invariant magnitude must be valid
默认情况下,不变性名称会被解析并用作违反不变性时的错误消息,但您可以轻松自定义,只需在不变性中抛出自定义消息的异常而不是返回 false
。
<?php declare(strict_types=1); class Speed extends OtherCode\DDDValueObject\ValueObject { // ... protected function invariantSpeedMustBeGreaterThanZero(): bool { if($this->amount() < 0) { throw new InvalidArgumentException('The given speed value is not valid'); } return true; } // ... } $s = new Speed(-1, 'm/s'); // PHP Fatal error: Uncaught InvalidArgumentException: Unable to create Speed value object due: // The given speed value is not valid // invariant magnitude must be valid
此外,您还可以通过传递一个自定义函数到 checkInvariants
方法来完全自定义如何管理不变性违反。
<?php declare(strict_types=1); class Speed extends OtherCode\DDDValueObject\ValueObject { // ... public function __construct(int $amount, string $magnitude) { $this->initialize([ 'amount' => $amount, 'magnitude' => $magnitude ]); $this->checkInvariants(function (array $violations) { throw new RuntimeException("Epic fail due:\n-" . implode("\n-", $violations) . "\n"); }); } protected function invariantSpeedMustBeGreaterThanZero(): bool { if($this->amount() < 0) { throw new InvalidArgumentException('The given speed value is not valid'); } return true; } // ... } $s = new Speed(-120, 'clicks/s'); // PHP Fatal error: Uncaught RuntimeException: Epic fail due: // - The given speed value is not valid // - invariant magnitude must be valid