Entire Object Validation

There are times when an object composed of valid properties, as a whole, can still be deemed invalid. It can be tempting to add this kind of validation to the object itself, but generally this is an anti-pattern. Higher-level validation changes at a rhythm different than that of the object logic itself. Also, it's good practice to separate these responsibilities.

The validation informs the client about any errors that have been found or collects the results to be reviewed later, as sometimes we don't want to stop the execution at the first sign of trouble.

An abstract and reusable Validator could be something like this:

abstract class Validator
{
private $validationHandler;

public function __construct(ValidationHandler $validationHandler)
{
$this->validationHandler = $validationHandler;
}

protected function handleError($error)
{
$this->validationHandler->handleError($error);
}

abstract public function validate();
}

As a concrete example, we want to validate an entire Location object, composed of valid Country, City, and Postcode Value Objects. However, these individual values might be in an invalid state at the time of validation. Maybe the city doesn't form part of the country, or maybe the postcode doesn't follow the city format:

class Location
{
private $country;
private $city;
private $postcode;

public function __construct(
Country $country, City $city, Postcode $postcode
) {
$this->country = $country;
$this->city = $city;
$this->postcode = $postcode;
}

public function country()
{
return $this->country;
}

public function city()
{
return $this->city;
}

public function postcode()
{
return $this->postcode;
}
}

The validator checks the state of the Location object in its entirety, analyzing the meaning of the relationships between properties:

class LocationValidator extends Validator
{
private $location;

public function __construct(
Location $location, ValidationHandler $validationHandler
) {
parent:: __construct($validationHandler);
$this->location = $location;
}

public function validate()
{
if (!$this->location->country()->hasCity(
$this->location->city()
)) {
$this->handleError('City not found');
}

if (!$this->location->city()->isPostcodeValid(
$this->location->postcode()
)) {
$this->handleError('Invalid postcode');
}
}
}

Once all the properties have been set, we're able to validate the Entity, most likely after some described process. On the surface, it looks as if the Location validates itself. However, this isn't the case. The  Location class delegates this validation to a concrete validator instance, splitting these two clear responsibilities:

class Location
{
// ...

public function validate(ValidationHandler $validationHandler)
{
$validator = new LocationValidator($this, $validationHandler);
$validator->validate();
}
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.140.249.104