Login

Validating URLs with the Strategy Design Pattern

In this penultimate part of the series, I will build a strategy class that validates URLs using the built-in PHP function “filter_var().” This process is similar to defining other strategy classes discussed in previous parts, so you shouldn’t have major difficulties understanding its underlying logic.

As a PHP developer, did you ever think that implementing the Strategy design pattern in a real-word case was a daunting task that would make you suffer premature hair loss? Well, fear not; in this article series you’ll learn how to build a customizable web application which will use a bunch of loosely-coupled strategy classes to validate different types of data, such as integer and float numbers, URLs, email addresses as so forth.

And now that I’ve mentioned strategy classes, it’s time to review the topics covered in the last tutorial. In that installment I went through the development of a simple strategy class, which checked email addresses via the "filter_var()" PHP function that comes bundled with the language’s filters extension.

Even though you’ve probably built a class like this hundreds of times before, the process hopefully demonstrated how easy it is to apply the model imposed by the Strategy design pattern within the context of a real-world application whose primary goal is to check incoming data through a set of isolated validation (or strategy) classes.

In its current state, this example application is capable of validating integers, float numbers and email addresses in a pretty straightforward fashion, which is good for demonstration purposes. However, it’d be useful to extend its existing functionality even further by adding yet another strategy class to it that permits you to validate URLs. With that premise in mind, in this fifth chapter of the series I’m going to define a brand new strategy class, which will perform the aforementioned validation in a few simple steps.

Now, it’s time to continue discovering the numerous benefits of implementing the Strategy design pattern in PHP. Let’s get going!

{mospagebreak title=Review: the source classes defined so far}

As usual, before I start building the additional strategy class mentioned in the introduction, which as you know will be charged with validating URLs, I’m going to spend a few moments showing the source code of all the sample classes developed so far. This way you can quickly recall the role played by each of them in the implementation of the strategy pattern within a "real" web application.

With that being said, here’s the first of these classes. It’s a basic form helper that takes a group of validator objects through its "addValidator()" method. These objects are used for checking the validity of a given set of data:

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

}

}

As you can see, the "FormHelper" class is a simple container that permits you to store different validation objects in an internal array, which is used afterward by the "validate()" method to determine whether or not a supplied value is valid.

Since the logic that drives this form helper has been discussed in past articles of the series, I suggest that you move on and take a look at the following abstract class. It defines the generic structure and metadata of the validator objects just mentioned:

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

Well, if I had to say something relevant about the above "AbstractValidator" class, it would be that the driving force of its "validate()" method is the "filter_var()" PHP function. Obviously, this method, along with the corresponding getters and mutators (nice word, right?) allow you to define the logic and structure of a generic validation component, which must be refined by the pertinent subclasses.

And speaking of refined implementations, below is the list of concrete subclasses derived from the base "AbstractValidator" class. They come in useful for checking integers, float numbers and email addresses:

(IntegerValidator.php)

<?php

class IntegerValidator extends AbstractValidator

{

protected $_filter = FILTER_VALIDATE_INT;

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

}

(FloatValidator.php)

<?php

class FloatValidator extends AbstractValidator

{

protected $_filter = FILTER_VALIDATE_FLOAT;

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

}

(EmailValidator.php)

<?php

class EmailValidator extends AbstractValidator

{

protected $_filter = FILTER_VALIDATE_EMAIL;

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

}

From the previous code samples, it’s clear to see how easy it is to create a concrete subclass that permits you to check a specified type of data. In all cases, defining a specific validation component is reduced to overriding the "$_filter" and "$_errorMessage" properties declared by the parent "AbstractValidator" and nothing else.

All right, at this point I’ve shown you all of the strategy classes developed so far, which are more than enough for building a fully-functional validation web application. As I expressed in the introduction, however, it’d be useful to create yet another class that allows us to determine if a supplied value is a valid URL. Doing this is so simple, that experience is really worthwhile.

In keeping with this, in the following segment I’m going to create a final strategy class to check URLs, whose definition will look very similar to the ones that you saw before.

Now, go ahead and read the next section. It’s only one click away.

{mospagebreak title=Validating URLs with the Strategy design pattern}

As you might have already guessed, building a strategy class capable of determining if an inputted value is a valid URL is a simple process. First, we derive a concrete subclass from the parent "AbstractValidator," and then we override the familiar "$_filter" and "$_errorMessage" protected properties.

This theory needs to be backed up with a functional example. So, the following code block shows the definition of this brand new strategy class, which in a blazing wave of creativity I called "UrlValidator." Here it is:

(UrlValidator.php)

<?php

class UrlValidator extends AbstractValidator

{

protected $_filter = FILTER_VALIDATE_URL;

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

}

If you were expecting to be confronted with a large portion of code, surely at this point you’ll feel disappointed, as the definition of the "UrlValidator" is ridiculously short. Of course, this is somewhat tricky, since the class internally uses the FILTER_VALIDATE_URL constant to check the validity of a supplied URL, not to mention all of the functionality inherited from its abstract parent, which has been discussed in previous chapters of the series.

Having defined a strategy class that validates URLs, the next logical thing to do is to see if it really works as expected. Thus, in the section to come I’m going to build a trivial script that will put the class in action as a standalone component.

Want to see how this will be done? Then click on the link below and read the next few lines.

{mospagebreak title=Testing the UrlValidator class}

In reality, testing the functionality of the "UrlValidator" class defined in the preceding segment is an extremely trivial process. It’s reduced to first spawning an instance of the class in question, and then calling its "validate()" method. Obviously, the best way to understand this is by means of example, so below I coded one for you that checks to see if the string "http://www.devshed.com" is a well-formed URL. Here it is:

// create an instance of the URL validator class

$urlValidator = new UrlValidator(‘http://www.devshed.com’);

// validate the supplied value

if (!$urlValidator->validate())

{

echo $urlValidator->getFormattedError();

}

else

{

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

/*

displays the following

The data that you entered is correct.

*/

}

Well, as one might expect, the above example worked like a charm, as the value passed to the constructor of the URL validator object is really a valid Uniform Resource Locator. However, keep in mind that the FILTER_VALIDATE_URL constant used internally by the "filter_var()" PHP function only verifies if the format of the inputted value is RFC-compliant. If you need to perform a stricter validation, consider implementing this functionality through a method of your own. The experience will be enriching and — why not? — also fun.

Final thoughts

In this penultimate episode of the series, I built yet another strategy class, which in this case was responsible for validating URLs using the "filter_var()" built-in PHP function. This process was pretty similar to defining other previous strategy classes, which means that you shouldn’t have major difficulties understanding its underlying logic.

Now, take a deep breath, relax and think about the scenario created at this point. On one hand there’s a form helper that accepts instances of different strategy classes to validate a decent variety of data, while on the other hand, the strategy classes are capable of performing specific checking tasks as isolated components.

What can we do with all these elements? Yes, you guessed right! By putting them to work together, it’d be possible to assemble different validation strategies at runtime with extreme ease and without having lots of code duplication. The only requirement to achieve this would be to create client code that consumes the interfaces exposed by the involved classes.

That’s exactly what I plan to cover in the last article, so don’t miss it!