Validating Incoming Data with the Strategy Design Pattern

If you’ve been doing some research lately on the web about how to implement different design patterns, be it in Java, PHP or Python, you’ll probably have noticed that the Strategy pattern is one of the most popular contenders in the field. It has been covered countless times in all types of media, ranging from books and magazines to e-zines and personal blogs. In this article series, I’ll show you how to use this popular design pattern to accomplish one of the more common tasks a website must perform: validating user-supplied data.

Logically, there’s a reason for the Strategy design pattern’s well-deserved popularity: unlike the Composite and Decorator patterns, which are also important to pattern-driven programming, the logic that stands behind Strategy is much easier to grasp, and its implementation in several languages is fairly straightforward as well. While the aforementioned Composite and Decorator are powerful paradigms that permit you to tackle certain software development problems with elegance and efficiency, the truth is that they’re also pretty confusing to understand, at least at first.

On the other hand, the Strategy pattern not only has a flatter learning curve than its cousins, but it allows you to implement two basic principles of object-oriented programming that you’ve probably heard before: “Favor Composition over Inheritance” and “Encapsulate the concept that varies.” Yes, Strategy is a typical case where the power of Composition permits you to create loosely-coupled classes that can be consumed by client code or other classes through a highly-encapsulated interface, without having to create a redundant hierarchy of objects.

With all these goodies at hand for free, it’s logical to think that implementing the Strategy pattern in PHP is a fairly straightforward process. Well, that’s correct, too. And to demonstrate this, in the course of this article series I’ll be showing how to implement the pattern in a real-world case: validating user supplied data. In doing so, you hopefully will learn the basic concepts that surround the application of the Strategy pattern, in addition to building a highly-modular data validation program, which you’ll be able to tweak and improve at will.

Now, it’s time to get rid of the preliminaries and start taking advantage of the functionality offered by the Strategy pattern in PHP. Let’s go!

{mospagebreak title=Building a basic data validation class with PHP}

Before I start demonstrating how to implement the Strategy design pattern for checking incoming data in PHP, first it would be quite educational to set up an example that performs the same validation process through a single, pretty monolithic class. Once you see the drawbacks of using an approach like this more clearly, it’ll be easier for you to understand how the Strategy pattern can tackle the process more efficiently.

Having clarified that point, here’s the validation class that I plan to use at this initial stage:   

<?php

class Validator {

   

    protected $_errors = array();

   

    // constructor (not implemented)

    public function __construct(){}

   

    // validate integers

    public function checkInteger($value)

    {

        if (!is_int($value))

        {

            $this->_errors[strtolower($value)] = ‘The supplied value must be an integer.';

        }

        return $this;

    }  

   

    // validate floats

    public function checkFloat($value)

    {

        if (!is_float($value))

        {

            $this->_errors[strtolower($value)] = ‘The supplied value must be a float number.';

        }

        return $this;

    }

   

    // validate strings

    public function checkString($value)

    {

        if (!is_string($value))

        {

            $this->_errors[strtolower($value)] = ‘The supplied value must be a string.';

        }

        return $this;

    }

   

    // get validation errors

    public function getErrors()

    {

        return $this->_errors;

    }

   

    // clear validation errors

    public function clearErrors()

    {

        $this->_errors = array();

    }

   

    // validate supplied data   

    public function validate()

    {

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

    }            

}

As you can see above, the example “Validator” class implements a few simple methods which are mere proxies for the native “is_int(),” “is_float()” and “is_string()” PHP functions. Besides that, the class defines an additional “validate()” method for determining whether or not the supplied data is valid. So far, there’s nothing unexpected with the inner workings of this class, right?

Having already explained how the previous “Validator” does its business, it’s time to give it a try and test its real functionality. The script below uses the class’s main methods for checking the validity of some trivial data. Take a look at it, please:

$validator = new Validator;

// validate some basic data

$validator->checkInteger(1234)

          ->checkFloat(‘abcde’)

          ->checkString(12.345);

if (!$validator->validate())

{

    // display validation errors

    $errors = $validator->getErrors();

    foreach ($errors as $value => $error)

    {

        echo ‘The value ‘ . $value . ‘ is incorrect. ‘ . $error . ‘<br />';

    }

    /* displays the following

    The value abcde is incorrect. The supplied value must be a float number.

    The value 12.345 is incorrect. The supplied value must be a string.

    */

}

else

{

    echo ‘Congratulations! Your data is correct!';

}

Well, that worked decently well. Once an instance of the “Validator” class has been spawned, checking for integers, floats and strings is only a matter of chaining the corresponding validation methods and displaying the errors that might have occurred during the verification process. It’s that simple, really.

At this point, you may be wondering what could be wrong with the “Validator” class if it yields such good results (at least for example purposes). First off, the model is not very flexible; the only way to extend the class’s functionality is via Inheritance. And last, but not least, I have to say that “Validator” looks somewhat like a god class because it attempts to validate every type of data through a set of discrete methods.

It becomes evident that a class like this should be used as a helper only in simple use cases. However, as an application grows in complexity, it’s necessary to implement a more modular, powerful and flexible solution. And here’s exactly where the Strategy pattern comes into play, since it permits you to easily apply the two “great commandments” of the object-oriented paradigm mentioned in the introduction. In simple terms, the pattern uses Composition to inject an instance of a class that encapsulates certain functionality into another one, which allows you to perform a task according to a predefined strategy.

If this explanation sounds somewhat confusing to you, let me elaborate this concept a bit further with the example that you just saw. Instead of defining a class that tries to validate everything via a bunch of concrete methods, it’d be more effective to split it up in a group of smaller classes, where each one would be responsible for checking only one type of data. This would encapsulate the concept that varies, in this case the validation process itself.

Finally, each of these validation classes would be injected into a helper class, which would make it possible to check incoming data according to a certain validation strategy (i.e. an integer validation strategy, a float validation strategy and so forth). Got the point? I hope so.

Of course, by far the best way to understand how the Strategy pattern can be used to validate input data is by showing some functional code. In keeping with this, in the next section I’m going to define the bare bones structure of a whole new helper class, which will accept via Composition the set of discrete validation classes mentioned before.

To see how this helper class will be created, read the lines to come.

{mospagebreak title=Implementing the Strategy design pattern to validate incoming data}

As I said, it’s feasible to build a modular and flexible data validation application by taking advantage of the functionality offered by the Strategy pattern. To do so, I’ll start by defining a simple web form helper. It will take as an input argument a validator object (the strategy), whose originating class will be shown in upcoming articles of this series.

For the moment, however, focus your attention on the definition of the helper, which looks like this:

(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;

    }

As you can see, the above “FormHelper” class implements for now three concrete methods. The first one, called “addValidator(),” permits you to inject a set of independent validation objects, which are stored on the protected $_validators” property. This method is actually the “heart and soul” of the Strategy pattern, as it uses the power of Composition to inject a predefined validation strategy inside the helper class.

On the other hand, the “validate()” method first iterates over all the inputted validator objects, uses them to check if the supplied data is valid, and finally stores the corresponding error messages by calling the “getFormattedError()” method defined by the objects in question. Naturally, you’ll understand the implementation of this method better when I show you the definition of each validation class, but keep in mind that this is a work in progress, so for the moment keep your attention focused on how the helper class does its thing.

Even though at this point the helper class looks pretty skeletal, it’s clear to see that it can use a specific strategy, that is one or multiple validator objects, to check incoming data. Now, are you starting to see how useful the Strategy pattern can be when building flexible applications? I guess you do!

However, in its current state the helper still isn’t capable of retrieving and removing the error messages stored during the entire validation process. Fortunately, this can be solved by adding a couple of additional methods to it. Their definitions will be shown in the next section.

Now, to see how these extra methods will be defined, click on the link below and keep reading.

{mospagebreak title=Finish defining the form helper class}

As I said in previous segment, the final touch that I plan to give to the sample form helper class defined before is to provide it with the ability to retrieve and delete the array of errors that might have been stored during the entire validation process. These tasks will be performed by two brand new methods called “getErrors()” and “clear(),” and their respective definitions have been included in the following code fragment:

(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();

    }  

}

Mission accomplished. Now, the form helper class includes the convenient methods mentioned before, along with one more called “getErrorString().” As its name suggests, this method can be used for fetching all the stored errors in the form of a string.

With the form helper already set, the next step required to implement the Strategy pattern is to define the different validation classes that will be injected into the helper via its “addValidator()” method. The first of these classes will be discussed in the upcoming part of the series; it will be responsible for validating integers, or expressed in more technical terms, will implement an integer validation strategy. 

Final thoughts

That’s all for now. In this first part of the series, I provided you with a quick introduction to validating incoming data via the Strategy design pattern. Since my goal here is to develop a modular application that permits you to check input data using different strategies represented by multiple validator objects, in the following article I’m going to start creating the originating classes of those objects, which will come in handy for validating typical data types, including integers and float numbers, email addresses and URLs as well.  

Now that you know the topics that will be covered in the next tutorial, you don’t have any excuses to miss it!

[gp-comments width="770" linklove="off" ]

chat