Skip to content

Commit

Permalink
ValueObjects improvements
Browse files Browse the repository at this point in the history
- all value object traits now doesn't perform validations when the method `fromSafeNative()` is called, only assertions are performed
- added trait `AppendOnlyValueObjectSetTrait`
- removed trait `NativeFactoryMethodTrait`
  • Loading branch information
tg666 committed Oct 30, 2023
1 parent bb3266a commit 0038fbf
Show file tree
Hide file tree
Showing 10 changed files with 258 additions and 56 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
<?php

declare(strict_types=1);

namespace SixtyEightPublishers\ArchitectureBundle\Domain\ValueObject;

use SixtyEightPublishers\ArchitectureBundle\Domain\Exception\InvalidNativeValueTypeException;
use SixtyEightPublishers\ArchitectureBundle\Domain\Exception\ValueObjectSetException;
use function assert;
use function count;
use function is_array;
use function is_subclass_of;
use function sprintf;

trait AppendOnlyValueObjectSetTrait
{
/**
* @param array<ValueObjectInterface> $items
*/
protected function __construct(
protected readonly array $items,
) {
}

public static function empty(): static
{
return new static([]);
}

public static function fromNative(mixed $native): static
{
$itemClassname = self::getValidItemClassname();

if (!is_array($native)) {
throw InvalidNativeValueTypeException::fromNativeValue(
$native,
sprintf('array<%s>', $itemClassname),
static::class,
);
}

$items = [];

foreach ($native as $item) {
$items[] = ([$itemClassname, 'fromNative'])($item);
}

return new static($items);
}

public static function fromSafeNative(mixed $native): static
{
$itemClassname = self::getValidItemClassname();
assert(is_array($native));

$items = [];

foreach ($native as $item) {
$items[] = ([$itemClassname, 'fromSafeNative'])($item);
}

return new static($items);
}

/**
* @param array<ValueObjectInterface> $items
*/
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);
}
}

return new static($items);
}

/**
* @return array<int, mixed>
*/
public function toNative(): array
{
$values = [];

foreach ($this->all() as $item) {
$values[] = $item->toNative();
}

return $values;
}

public function equals(ValueObjectInterface $object): bool
{
if (!$object instanceof static || $object->count() !== $this->count()) {
return false;
}

foreach ($object->all() as $index => $item) {
if (!isset($this->items[$index]) || !$this->items[$index]->equals($item)) {
return false;
}
}

return true;
}

public function append(ValueObjectInterface $item): static
{
$items = $this->all();
$items[] = $item;

return self::fromItems($items);
}

/**
* @return array<ValueObjectInterface>
*/
public function all(): array
{
return $this->items;
}

public function count(): int
{
return count($this->all());
}

/**
* @return class-string<ValueObjectInterface>
*/
abstract protected static function getItemClassname(): string;

/**
* @return class-string<ValueObjectInterface>
*/
private static function getValidItemClassname(): string
{
/** @var class-string $itemClassname */
$itemClassname = static::getItemClassname();

if (empty($itemClassname)) {
throw ValueObjectSetException::undeclaredItemType(static::class);
}

if (!is_subclass_of($itemClassname, ValueObjectInterface::class, true)) {
throw ValueObjectSetException::declaredItemTypeMustBeValueObjectImplementor(static::class, $itemClassname);
}

return $itemClassname;
}
}
20 changes: 17 additions & 3 deletions src/ArchitectureBundle/Domain/ValueObject/ArrayValueTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@
use SixtyEightPublishers\ArchitectureBundle\Domain\Exception\InvalidNativeValueTypeException;
use function array_key_exists;
use function array_merge;
use function assert;
use function count;
use function get_class;
use function is_array;
use function sprintf;

trait ArrayValueTrait
{
use NativeFactoryMethodTrait;

/**
* @param array<mixed> $values
*/
Expand All @@ -25,12 +24,23 @@ protected function __construct(
) {
}

public static function fromSafeNative(mixed $native): static
public static function fromNative(mixed $native): static
{
if (!is_array($native)) {
throw InvalidNativeValueTypeException::fromNativeValue($native, 'array', static::class);
}

$valueObject = new static($native);

$valueObject->validate();

return $valueObject;
}

public static function fromSafeNative(mixed $native): static
{
assert(is_array($native));

return new static($native);
}

Expand Down Expand Up @@ -105,4 +115,8 @@ public function count(): int
{
return count($this->all());
}

protected function validate(): void
{
}
}
20 changes: 17 additions & 3 deletions src/ArchitectureBundle/Domain/ValueObject/BooleanValueTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@
namespace SixtyEightPublishers\ArchitectureBundle\Domain\ValueObject;

use SixtyEightPublishers\ArchitectureBundle\Domain\Exception\InvalidNativeValueTypeException;
use function assert;

trait BooleanValueTrait
{
use NativeFactoryMethodTrait;

protected function __construct(
protected readonly bool $value,
) {
Expand All @@ -25,12 +24,23 @@ public static function false(): static
return new static(false);
}

public static function fromSafeNative(mixed $native): static
public static function fromNative(mixed $native): static
{
if (!is_bool($native)) {
throw InvalidNativeValueTypeException::fromNativeValue($native, 'bool', static::class);
}

$valueObject = new static($native);

$valueObject->validate();

return $valueObject;
}

public static function fromSafeNative(mixed $native): static
{
assert(\is_bool($native));

return new static($native);
}

Expand All @@ -53,4 +63,8 @@ public function isFalse(): bool
{
return !$this->toNative();
}

protected function validate(): void
{
}
}
20 changes: 17 additions & 3 deletions src/ArchitectureBundle/Domain/ValueObject/FloatValueTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,33 @@
namespace SixtyEightPublishers\ArchitectureBundle\Domain\ValueObject;

use SixtyEightPublishers\ArchitectureBundle\Domain\Exception\InvalidNativeValueTypeException;
use function assert;
use function is_float;

trait FloatValueTrait
{
use NativeFactoryMethodTrait;

protected function __construct(
protected readonly float $value,
) {
}

public static function fromSafeNative(mixed $native): static
public static function fromNative(mixed $native): static
{
if (!is_float($native)) {
throw InvalidNativeValueTypeException::fromNativeValue($native, 'float', static::class);
}

$valueObject = new self($native);

$valueObject->validate();

return $valueObject;
}

public static function fromSafeNative(mixed $native): static
{
assert(is_float($native));

return new static($native);
}

Expand All @@ -34,4 +44,8 @@ public function equals(ValueObjectInterface $object): bool
{
return $object instanceof static && $object->toNative() === $this->toNative();
}

protected function validate(): void
{
}
}
20 changes: 17 additions & 3 deletions src/ArchitectureBundle/Domain/ValueObject/IntegerValueTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,33 @@
namespace SixtyEightPublishers\ArchitectureBundle\Domain\ValueObject;

use SixtyEightPublishers\ArchitectureBundle\Domain\Exception\InvalidNativeValueTypeException;
use function assert;
use function is_int;

trait IntegerValueTrait
{
use NativeFactoryMethodTrait;

protected function __construct(
protected readonly int $value,
) {
}

public static function fromSafeNative(mixed $native): static
public static function fromNative(mixed $native): static
{
if (!is_int($native)) {
throw InvalidNativeValueTypeException::fromNativeValue($native, 'int', static::class);
}

$valueObject = new static($native);

$valueObject->validate();

return $valueObject;
}

public static function fromSafeNative(mixed $native): static
{
assert(is_int($native));

return new static($native);
}

Expand All @@ -34,4 +44,8 @@ public function equals(ValueObjectInterface $object): bool
{
return $object instanceof static && $object->toNative() === $this->toNative();
}

protected function validate(): void
{
}
}

This file was deleted.

Loading

0 comments on commit 0038fbf

Please sign in to comment.