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, usesarraysare arguments (however function set can now receive also named arguments)ValueObjectDKeysValueObjectPKeys
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