Value Object (versions 0.x)
Base Information about this particular implementation
Each value object uses Key:Value store (associative array) to store its data. Because on its low level the ValueObject class implements ArrayAccess interface these values can be accessed as:
$valueObject[$valueKey];
// or
$valueObject->offsetGet($valueKey);
Getters (which use is probably much “cleaner”) require to be declared explicitly, e.g.:
class ExampleVO extends ValueObject
{
public const NAME = 'name';
...
public function name(): string
{
return $this->offsetGet(self::NAME);
}
}
Currently there are defined Tree “main” Value Object’s types:
ValueObject
- base type, usesarrays
are arguments (however function set can now receive also named arguments)ValueObjectDKeys
ValueObjectPKeys
Examples
Value Object with dynamically created keys
You can define the ValueObject like this:
$valueObject = new ValueObjectDKeys(name: "Foo", age: 30);
It is totally fine!
$valueObject2 = $valueObject->set(age: 25);
$result = $valueObject->isEqual($valueObject2); // false
$valueObject3 = $valueObject2->set(age: 30);
$result = $valueObject->isEqual($valueObject3); // true
$valueObject4 = new ValueObjectDKeys(name: "Foo", age: 30, city: "NY");
$result = $valueObject->isEqual($valueObject4); // false
It is quite simple and fast but there is no Invariants / Validators used / defined - so, there is also no rules regarding the values types etc… e.g.:
$valueObject5 = new ValueObjectDKeys(name: "Foo", age: "30");
$result = $valueObject->isEqual($valueObject5); // false
Should $valueObject5
be at all considered as a Valid one?
Invariants
Invariants are a “new” way (in the context of this library) to define the rules that new created Value Object should pass to be considered as a Valid one (and to be at all created).
class ValueObjectFive extends ValueObjectDKeys
{
public const NAME = 'name';
public const AGE = 'age';
#[Invariant]
protected function validateName(): void
{
assertIsString($this->offsetGet(self::NAME));
}
#[Invariant]
protected function validateAge(): void
{
$age = $this->offsetGet(self::AGE);
assertIsInt($age);
assertGreaterThanOrEqual(0, $age);
}
}
Base class Example (with use of validators)
“Validators” (the same that are used in ValueObjectPKeys
) allows only to check the allowed keys and their
existence.
Validators
Currently Validators can be defined as an array of strings - fully qualified names of classes that implement the interface \Sushi\ValidatorInterface.
Available validators can be found in https://github.com/lbacik/value-object/tree/master/src/Sushi/Validator
For the time being (however I don’t think that there is something missing ;)) the list is as follow:
KeysValidator
- checks whether all keys from key:value table passed to the VO object during its initialization are legal keys of this VO (have been declared in its “keys” table). Without turned on this validator each “key:value” table can be passed to the VO constructor what means you don’t control the VO internal storage.InitializeValidator
- it require all keys declared in VO’s “keys” table being initialize in initial “key:value” table (passed to constructor).
Keys
This table can be defined as a regular (flat) or associative one. In fact this “base” library does not utilize the “values” in case of associative array used here - the meaning of this table is as follow:
- flat array - values, as in the above example, means the VO keys.
- associative array - keys means VO keys, values can be use by custom validators, take a look at value-object-illuminate-validation