An open API service indexing awesome lists of open source software.

https://github.com/othercodes/ddd-value-object

Small library to easily apply the Value Object Pattern.
https://github.com/othercodes/ddd-value-object

ddd-architecture ddd-patterns value-object

Last synced: 10 months ago
JSON representation

Small library to easily apply the Value Object Pattern.

Awesome Lists containing this project

README

          

# DDD Value Object

![Tests](https://github.com/othercodes/ddd-value-object/workflows/Tests/badge.svg) [![License](https://poser.pugx.org/othercodes/ddd-value-object/license)](https://packagist.org/packages/othercodes/ddd-value-object) [![codecov](https://codecov.io/gh/othercodes/ddd-value-object/branch/master/graph/badge.svg)](https://codecov.io/gh/othercodes/ddd-value-object)

Small library to easily manage the Value Object Pattern.

## Installation

Use the following command to install with `composer`:

```bash
composer require othercode/ddd-value-object
```

This will automatically get the latest version and configure a `composer.json` file.

Alternatively you can create the following `composer.json` file and run `composer install` to install it.

```bash
{
"require": {
"othercode/ddd-value-object": "*"
}
}
```

## Usage

Build a Value object is quite simple, you just need to extend the `ValueObject` Next, initialize the values in the
constructor by using the `initialize` method. Finally, add invariant rules as protected method, using the prefix
`invariant` (this prefix can be customized) and execute them with the `checkInvariants` method.

```php
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();
}
}
```

### Equality

Value equality is computed by serializing the object and hashing it with the sha256 algorithm. Alternatively, you can
override `equalityHash` to calculate a proper hash for the object. This hash is used to check if the value objects are
equals or not.

```php
amount(), $this->magnitude());
}
// ...
}
```

### Immutability

The immutability property blocks any attempt of value modification, that will end in exception:

```php
$s = new Speed(120, 'km/h');
$s->amount = 123;

// PHP Fatal error: Uncaught OtherCode\DDDValueObject\Exceptions\ImmutableValueException: Illegal attempt to change immutable value.
```

You can customize the exception that will be thrown by overriding the `immutabilityException` property. The same happens
with the error message, you just need to override the `immutabilityMessages` property.

```php
'You shall not update this value!.',
];
// ...
}
```

### Invariants

The invariants methods must return a boolean value, `true` if the invariant is successfully, `false` otherwise. If any
in variant is violated you will get an exception:

```php
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
```

Additionally, you can fully customize how the invariant violation are managed by passing a custom function to the
`checkInvariants` method:

```php
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
```