3
\$\begingroup\$

It is nice to be able to set your data in a domain object like so:

$order->setId($id);
$order->setCustomer($customer);
$order->setItems($items);

And then be able to do

if( !$order->validate() ) {
    // Invalid data
}

Which will validate all the set data and tell you if it was valid or not. I have an implementation of this I came up with but it is sort of messy and limited to only certain common validation rules like checking the type, length/range and format of the data.

I have been doing a lot of Javascript lately and I like the idea of the anonymous functions and I just found out you can do them in PHP 5.3+ and you can use the $this keyword from PHP 5.4.

abstract class AbstractEntity {

    private $id = 0;
    private $validations = array();

    public function setId($id) {
        $this->id = $id;

        // A function to validate the Id
        $this->addValidation( function() {
            return ( $this->id > 0 );
        });
    }

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

    public function validate() {
        foreach($this->validations as $validation) {
            if( $validation() === false ) {
                return false;
            }
        }

        return true;
    }

    protected function addValidation($function) {
        $this->validations[] = $function;
    }

}

The Order class:

class Order extends AbstractEntity {

    private $customer;
    private $items = array();
    private $status;

    public function setCustomer(Customer $customer) {
        $this->customer = $customer;

        // Make sure the customers account is active
        $this->addValidation( function() {
            return ( $this->customer->isActive() );
        });
        // Do as many complex validations as needed
    }

    public function setStatus($status) {
        $this->status = $status;

        // The status has to be 'Pending' or 'Complete'.
        $this->addValidation( function() {
            return ( ($this->status === 'Pending') || ($this->status === 'Complete') );
        });

}

Doing it this way validations of all different levels of complexity can be done. I was thinking of adding in another parameter to the addValidation() method so you can group validation rules together so they execute in a certain order.

It needs extra functionality like setting error messages but that should not be too hard to implement.

I was also thinking of maybe making the addValidation() method public so you can add validations outside of the class that will execute when the validate() method is called. This could be handy in some scenarios.

Is this a good or bad idea? I would like to see some opinions before I go and change all my code to using this sort of implementation.

\$\endgroup\$
1
\$\begingroup\$

my two cents :

  • I think tying validation activation to setters is not really good. What if you never set any value on your object ? It will be considered valid ! And what happens if you set the property more than once ?
  • Some implementations use external validator objects, which allow more flexibility (validation rules often vary, according to which user requests saving for instance). When you call validate(), you either pass a validator instance or let the object use a default validator. As a side note, coming from Rails / ActiveRecord, I can tell that complex projects often do not turn well when your domain object's lifecycle is so tightly tied to a single validation scheme !
  • Speaking DDD lingo, some of your problems might be efficiently solved using Value objects. For instance, your Id property could be a value object that has a isValid() method (it would be responsible for its own validation). Wether or not this is a good idea depends on your domain.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.