Checking Email Addresses with the Strategy Design Pattern

In this fourth part of a series on the strategy design pattern, I extend the functionality of the sample validation program by adding another strategy class to it. The new class will check the validity of a supplied email address.

As you may have heard, the Strategy design pattern is a software design paradigm that allows developers to build flexible and modular applications by taking advantage of the functionality offered by Composition, rather than relying heavily on the benefits brought by Inheritance. While this may sound like an obscure and hard-to-grasp concept, the truth is that implementing the Strategy pattern is a straightforward process. It’s even easier to accomplish when using a programming language as friendly as PHP.

Quite possibly, one of the most challenging aspects that surround the implementation of the Strategy pattern in PHP is to demonstrate how to apply it in a “real-world” use case. Many of the tutorials that cover the topic very often appeal to “toy code examples,” which aren’t of great help, especially when trying to solve problems present in real environments.

In an attempt to tackle the subject from a realistic point of view, in this article series you’ll learn in a step-by-step fashion how to use the Strategy pattern to build a scalable PHP application. This application will be able to check different types of incoming data, including integer and float numbers, email addresses and URLs, without having to use a monolithic God class.

In the last tutorial I left off explaining how to use the power of the Strategy pattern to define an easily-customizable class which validates float numbers in a simple manner. Its loosely-coupled nature makes it possible to use the class as a part of a more complex validation strategy in conjunction with other classes, or as a standalone component.

The primary goal of this series of articles is to develop a flexible and scalable program that can validate supplied data via a set of different strategy classes that can be easily assembled at run time. So, in the following lines I’m going to expand the program’s current functionality by adding an entirely new strategy class to it, which will check the validity of a provided email address.

Are you ready to continue learning how to implement the Strategy pattern to validate incoming data? Then begin reading right now!

{mospagebreak title=Review: validating input data with the Strategy design pattern}

Just in case you haven’t read the previous installment of the series, where I added to the sample application a new strategy class that checked float numbers, below I listed for you all of the classes defined so far. This way you can study them in depth and quickly grasp their driving logic.

First, here’s the form helper that accepts through its “addValidator()” method a configurable set of multiple validator objects at run time:

(FormHelper.php)

<?php

 

class FormHelper

{

    protected $_validators = array();

    protected $_errors = array();

   

    // add a validator

    public function addValidator(AbstractValidator $validator)

    {

        $this->_validators[] = $validator;

        return $this;

    }

   

    // get all the validators

    public function getValidators()

    {

        return !empty($this->_validators) ? $this->_validators : null;

    }

     

    // validate inputted data

    public function validate()

    {

        $validators = $this->getValidators();

        if (null !== $validators)

        {

            foreach ($validators as $validator)

            {

                if (!$validator->validate())

                {

                    $this->_errors[] = $validator->getFormattedError();

                }

            } 

        }

        return empty($this->_errors) ? true : false;

    }

   

    // get validation errors as an array

    public function getErrors()

    {

        return $this->_errors;

    }

   

    // get validation errors as a string

    public function getErrorString()

    {

        $errors = $this->getErrors();

        return !empty($errors) ? implode(”, $errors) : ”;

    }

   

    // clear state of the form helper

    public function clear()

    {

        $this->_validators = array();

        $this->_errors = array();

    }  

}

So far, so good. Now that you’ve surely understood how the above “FormHelper” class uses the injected dependencies to build and perform a predefined validation strategy, it’s time to show the definition of the abstract validation class that encapsulates most of the functionality required by the distinct strategy subclasses. Here it is:  

(AbstractValidator.php)

 

<?php

 

abstract class AbstractValidator

{

    protected $_value = ”;

    protected $_filter = ”;

    protected $_options = null;

    protected $_errorMessage = ”;

    protected $_errorPrefix = ‘<p>’;

    protected $_errorSufix = ‘</p>’;

   

    // constructor

    public function __construct($value, array $options = null)

    {

        $this->_value = $value;

        if (null !== $options)

        {

           $this->setOptions($options);

        }

    }

   

    // get supplied value

    public function getValue()

    {

        return $this->_value;

    }

   

    // set validation options

    public function setOptions(array $options)

    {

        if (empty($options))

        {

            throw new ValidatorException(‘Invalid options for the validator.’);

        }

        $this->_options = $options;

    }

   

    // get validation options

    public function getOptions()

    {

        return $this->_options;

    }

     

    // set the validation filter

    public function setFilter($filter)

    {

        if (!is_string($filter))

        {

            throw new ValidatorException(‘Invalid filter for the validator.’); 

        }

        $this->_filter = $filter;

    }

   

    // get the validation filter

    public function getFilter()

    {

        return $this->_filter;

    }

   

    // set the error message

    public function setErrorMessage($errorMessage)

    {

        if (!is_string($errorMessage))

        {

            throw new ValidatorException(‘Invalid error message for the validator.’);    

        }

        $this->_errorMessage = $errorMessage;

    }

   

    // get error message

    public function getErrorMessage()

    {

        return $this->_errorMessage;

    }

             

    // get formatted error string

    public function getFormattedError()

    {

        return $this->_errorPrefix . ‘The value ‘ . $this->getValue() . ‘ is incorrect. ‘ . $this->getErrorMessage() . $this->_errorSufix;

    }

   

    // validate the supplied value 

    public function validate()

    {

        return filter_var($this->getValue(), $this->getFilter(), $this->getOptions());  

    }

}

(ValidatorException.php)

<?php

class ValidatorException extends Exception{}

As shown above, the “AbstractValidator” class is nothing but a simple a component that defines the generic behavior and metadata of concrete validation child classes. This obviously permits it to validate more specific types of data, including integer and float numbers, URLs and so forth. This is actually Inheritance 101, so I suggest that you pay attention to the following specific validator, which is charged with determining whether or not a supplied value is an integer:   

(IntegerValidator.php)

 

<?php

class IntegerValidator extends AbstractValidator

{

    protected $_filter = FILTER_VALIDATE_INT;

    protected $_errorMessage = ‘Please enter an integer value.’;

}

Definitely, the definition of the “IntegerValidator” subclass shows in a nutshell how easy it is to create refined implementations of its abstract parent to validate specific data types. Naturally, if you found it simple to grasp how this concrete class does its business, then understanding how the following one works will be a breeze. Take a look at it, please:  

(FloatValidator.php)

<?php

class FloatValidator extends AbstractValidator

{

    protected $_filter = FILTER_VALIDATE_FLOAT; 

    protected $_errorMessage = ‘Please enter a float value.’;

}

     

Mission accomplished, at least for now. At this stage, thanks to implementation of a couple of strategy classes, it’s possible to provide the previous form helper (remember that one, right?) with the ability to validate integer and float numbers in a relatively simple fashion.

But wait a minute! If creating specific implementations of the base “AbstractValidator” class required us only to write a few lines of code, then it’d be really easy to take advantage of this situation and build yet another class that validates email addresses.

Well, that’s exactly what I’m going to do in the following section. Therefore, to learn the full details regarding the definition of this brand new strategy class, click on the link below and read the lines to come.

{mospagebreak title=Building a strategy class for validating email addresses}

As you may have guessed, defining a new strategy class that validates email addresses is very similar to creating components that check for integer and float numbers. The entire process is reduced to deriving a concrete subclass from the parent “AbstractValidator” and overriding its “$_filter” and “$_errorMessage” properties respectively. It’s that simple, really.

The following code fragment shows the definition of the aforementioned subclass, not surprisingly called “EmailValidator”:

(EmailValidator.php)

<?php

class EmailValidator extends AbstractValidator

{

    protected $_filter = FILTER_VALIDATE_EMAIL; 

    protected $_errorMessage = ‘Please enter a valid email address.’;

}

What can I say about the above “EmailValidator” class that hasn’t already been said? Well, not much really, except for the fact that in this case it uses the FILTER_VALIDATE_EMAIL constant to determine whether or not a given email address is properly formatted. Since this PHP filter doe not also check to see if the domain part of the address is a valid host, or if it has an associated MX record in the DNS, adding this functionality is up to you. You’ve been warned.

Okay, having already defined a new strategy class that can be used for checking email addresses, the next logical step is to test it as a standalone component, so you can see for yourself how easy it is to put it in action.

But guess what? This will be done in the section to come. To get there, click on the link below and keep reading.

{mospagebreak title=The EmailValidator class as a standalone component}

As one might expect, using the email validator defined in the previous section as a standalone component is a straightforward process that can be tackled with minor efforts. In reality, checking the validity of a supplied email address via this concrete strategy class is reduced to coding a script similar to the one shown below:

// create an instance of the email validator class

$emailValidator = new EmailValidator(‘alejandrodomain.com’);

// validate the supplied value

if (!$emailValidator->validate())

{

    echo $emailValidator->getFormattedError();

    /*

    displays the following

    The value alejandrodomain.com is incorrect. Please enter a valid email address..

      */

}

else

{

    echo ‘ The data that you entered is correct.’;

}

There you have it. If you’ve ever built an object-oriented application that checks user-supplied email addresses, then the earlier code fragment should be pretty familiar to you. At the risk of being repetitive, keep in mind that the FILTER_VALIDATE_EMAIL constant used internally by the “filter_var()” PHP function only verifies whether or not the format of an email address is correct. So, if you need to implement more advanced features, such as looking for MX records in the DNS and checking to see if the supplied host is actually a working email server, you should consider adding this functionality on your own.

And with this final example, we’ve come to the end of this tutorial. As you saw before, utilizing the “EmailValidator” class in an isolated fashion is a breeze. However, things will become really interesting when I show you how to use it as part of a more complex validation strategy. This topic will be discussed in the next article.  

Final thoughts

In this fourth chapter of the series, I extended the functionality of the previous sample validation program by adding yet another strategy class to it. This new class was tasked with checking the validity of a supplied email address. With the incorporation of this modular component to the ones defined in preceding articles, you should now have a clear idea of how to inject them into the corresponding form helper class to assemble different validation strategies on the fly. But before I get to that point, it’d be useful to define at least one more strategy class that allows us to validate URLs in a simple way.

This will be the topic that I plan to discuss in the upcoming tutorial of the series, so stay tuned for more!

Google+ Comments

Google+ Comments