diff --git a/src/ArchitectureBundle/Domain/ValueObject/AppendOnlyValueObjectSetTrait.php b/src/ArchitectureBundle/Domain/ValueObject/AppendOnlyValueObjectSetTrait.php index 7c6f0ff..4915e27 100644 --- a/src/ArchitectureBundle/Domain/ValueObject/AppendOnlyValueObjectSetTrait.php +++ b/src/ArchitectureBundle/Domain/ValueObject/AppendOnlyValueObjectSetTrait.php @@ -6,6 +6,7 @@ use SixtyEightPublishers\ArchitectureBundle\Domain\Exception\InvalidNativeValueTypeException; use SixtyEightPublishers\ArchitectureBundle\Domain\Exception\ValueObjectSetException; +use function array_merge; use function assert; use function count; use function is_array; @@ -14,6 +15,9 @@ trait AppendOnlyValueObjectSetTrait { + /** @var class-string|null */ + private static ?string $validItemClassname = null; + /** * @param array $items */ @@ -67,12 +71,8 @@ public static function fromSafeNative(mixed $native): static */ public static function fromItems(array $items): static { - $itemClassname = self::getValidItemClassname(); - foreach ($items as $item) { - if (!$item instanceof $itemClassname) { - throw ValueObjectSetException::invalidItemPassed(static::class, $itemClassname, $item); - } + self::validateItem($item); } return new static($items); @@ -109,10 +109,36 @@ public function equals(ValueObjectInterface $object): bool public function append(ValueObjectInterface $item): static { + self::validateItem($item); + $items = $this->all(); $items[] = $item; - return self::fromItems($items); + return new static($items); + } + + /** + * @param array $items + */ + public function appendAll(array $items): static + { + $allItems = $this->all(); + + foreach ($items as $item) { + self::validateItem($item); + + $allItems[] = $item; + } + + return new static($allItems); + } + + public function merge(self $valueObject): static + { + return new static(array_merge( + $this->all(), + $valueObject->all(), + )); } /** @@ -138,6 +164,10 @@ abstract protected static function getItemClassname(): string; */ private static function getValidItemClassname(): string { + if (null !== self::$validItemClassname) { + return self::$validItemClassname; + } + /** @var class-string $itemClassname */ $itemClassname = static::getItemClassname(); @@ -149,6 +179,15 @@ private static function getValidItemClassname(): string throw ValueObjectSetException::declaredItemTypeMustBeValueObjectImplementor(static::class, $itemClassname); } - return $itemClassname; + return self::$validItemClassname = $itemClassname; + } + + private static function validateItem(ValueObjectInterface $item): void + { + $itemClassname = self::getValidItemClassname(); + + if (!$item instanceof $itemClassname) { + throw ValueObjectSetException::invalidItemPassed(static::class, $itemClassname, $item); + } } } diff --git a/src/ArchitectureBundle/Domain/ValueObject/ValueObjectSetTrait.php b/src/ArchitectureBundle/Domain/ValueObject/ValueObjectSetTrait.php index 8088fcb..304f77f 100644 --- a/src/ArchitectureBundle/Domain/ValueObject/ValueObjectSetTrait.php +++ b/src/ArchitectureBundle/Domain/ValueObject/ValueObjectSetTrait.php @@ -13,6 +13,9 @@ trait ValueObjectSetTrait { + /** @var class-string|null */ + private static ?string $validItemClassname = null; + /** * @param array $items */ @@ -66,12 +69,8 @@ public static function fromSafeNative(mixed $native): static */ public static function fromItems(array $items): static { - $itemClassname = self::getValidItemClassname(); - foreach ($items as $item) { - if (!$item instanceof $itemClassname) { - throw ValueObjectSetException::invalidItemPassed(static::class, $itemClassname, $item); - } + self::validateItem($item); } return new static($items); @@ -111,10 +110,12 @@ public function with(ValueObjectInterface $item): static $items = $this->all(); if (!$this->has($item)) { + self::validateItem($item); + $items[] = $item; } - return self::fromItems($items); + return new static($items); } public function without(ValueObjectInterface $item): static @@ -166,6 +167,10 @@ abstract protected static function getItemClassname(): string; */ private static function getValidItemClassname(): string { + if (null !== self::$validItemClassname) { + return self::$validItemClassname; + } + /** @var class-string $itemClassname */ $itemClassname = static::getItemClassname(); @@ -177,6 +182,15 @@ private static function getValidItemClassname(): string throw ValueObjectSetException::declaredItemTypeMustBeValueObjectImplementor(static::class, $itemClassname); } - return $itemClassname; + return self::$validItemClassname = $itemClassname; + } + + private static function validateItem(ValueObjectInterface $item): void + { + $itemClassname = self::getValidItemClassname(); + + if (!$item instanceof $itemClassname) { + throw ValueObjectSetException::invalidItemPassed(static::class, $itemClassname, $item); + } } }