Question

I've got a question that relates to loosely-coupled OOP design. Consider we have a simple value object like Email

final class Email 
{
    private $_email;

    public function __construct($email)
    {
        self::isValid($email);
        $this->_email = $email;
    }

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

    public static function isValid($email)
    {
    // some validation logic goes here  
        return true;
    }

}

Everything is simple and plain until I want to actually implement isValid method. I’ve got 2 options here:

1) Implement my own validation logic that could be terribly ugly something like this:

public static function isValid($email)
{
    $v = preg_match(
        '/^[-a-z0-9!#$%&\'*+\/\=?^_`{|}~]+(?:\.[-a-z0-9!#$%&\'*+\/\=?^_`{|}~]+)*@(?:[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?\.)*(?:aero|arpa|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel|pro|[a-z][a-z])$/',
        $email
    );

   return $v > 0;
}

2) Use some build-in framework validators

 public static function isValid($email)
 {
        $validator = new Zend_Validate_Email(); // tight-coupling detected!
        return $validator->isValid($email);
 }

I don’t really want to follow the 1st way because I don’t want to re-invent the wheel neither do I want to repeat the code, so I’m sticking to the 2nd way.

If I follow the 2nd way I’ve got a problem – my class is getting depended on another framework class.

My actual question is whether or not it’s acceptable to use low-level infrastructure classes in Entities/Value objects directly without using Dependency Injection in simple cases?

If I were to implement this example "properly" the code would get much more complicated just for the purpose of being loosely-coupled. I would have to create an EmailFactory which would provide my Value Object (Email) class with an instance of pre-configured EmailValidator that would be used in isValid function…

Was it helpful?

Solution

As long as the validation function does not need an external resource I would reuse the dependency directly and avoid it's injection.

A domain object encapsulates domain rules and should contain all necessary information to ensure these rules. It is designed more around high cohesion than low coupling (the concept of aggregates itself serves as a means for reducing interdependencies).

The Email class in your example should be the single point of failure for email address validation. If all domain objects validate emails via that class, then reusing existing framework (or even third party) functionality is an implementation detail and becomes less of a problem regarding loose coupling. If the validation rules change you would have to reimplement the function anyway - using Zend_Validate_Email or some custom code.

Injecting the validation logic into entities or value objects would bring a lot of problems with it:

  • logic that belongs in the domain object would be moved to another class
  • injecting services into entities is generally not advised
  • introducing an interface only for the EmailValidator class violates the Reused Abstractions Principle
  • calling a static isValid method on EMail would be impossible

Only in the rare case where the validation logic needs an external resource I would tend to use a factory with an injected service that validates on creation of the domain object -- but only after rethinking the design of the domain model.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top