Decoupling the Validation of Data with Bridge Classes in PHP 5

Are you interested in expanding your existing knowledge of different structural design patterns with PHP 5? Then look no further because you’ve come to the right place. Welcome to the second installment of the series “Using Bridge Classes with PHP 5.” This group of three articles walks you through the basics of how to apply the bridge pattern in PHP-based applications, and it also teaches you how to use bridge objects in real world development environments.

Provided that you already went through the first tutorial of the series, and learned how to create bridge classes with PHP 5, then I’ll assume that the logic that drives the mentioned pattern is quite familiar to you. However, if you’re taking the first steps on this topic, let me give you a brief introduction to how this pattern works, thus the upcoming examples that I plan to include in this article will be much easier to understand.

Essentially, in the bridge design pattern, a specific class and its respective implementation reside on different class hierarchies, which is accomplished without using an abstract class. As you’ll possibly imagine, this model is very convenient for decoupling the generic structure of the class in question from its concrete definition, since the corresponding implementation is achieved by one or more “bridged” classes.

To clarify the previous definition, in the preceding article I developed a concrete example in which a bridge class behaved as an intermediate entity for saving a target object to different storage locations. Even when this example didn’t have an immediate application in real situations, it was really useful for demonstrating how the bridge pattern can be applied in PHP 5.

However, this instructive journey has just started. In the course of this second tutorial, I’m going to show you how to create a bridge class which will come in handy for decoupling the validation of user-supplied data. There will be a class that defines generically how certain data must be verified, while others will implement different validation methods.

Having explained what this article is about, let’s go ahead and continue learning more about this powerful pattern. Let’s go!

{mospagebreak title=Building a bridge validator class}

The first step involved in this new implementation of the bridge pattern will rely on building a specific class in such a way that it can define the generic structure of an expansible data validator. As you’ll recall from the concepts deployed in the first article, this data checking class will behave like a bridge for others, where the validation of specific data will be concretely implemented.

That said, here is the corresponding signature for this new bridge class, which I creatively called “BridgeDataValidator.” Take a look at its source code, please:

// define 'BridgeDataValidator' class class BridgeDataValidator{ private $inputData; private $errorMessage; private $valCommand; private $dataValidator; public function __construct($inputData,$errorMessage,
$valCommand){ if(!$inputData||!$errorMessage||!$valCommand){ throw new Exception
('Invalid validation parameters'); } $this->inputData=$inputData; $this->errorMessage=$errorMessage; if($valCommand=='string'){ $this->dataValidator=new StringValidator(); } elseif($valCommand=='number'){ $this->dataValidator=new NumberValidator(); } elseif($valCommand=='alpha'){ $this->dataValidator=new AlphabeticValidator(); } else{ $this->dataValidator=new EmailValidator(); }         } public function validate(){ $this->dataValidator->validate
($this->inputData,$this->errorMessage); } }

In this concrete case, the above bridge class presents a “validate()” method which defines generically the way that user-supplied data should be validated. With reference to this, you must notice how a $valCommand parameter is passed to the corresponding constructor to determine programmatically which object should be used for checking a particular user entry.

For this class specifically, I defined only four classes that check the validity of specific data, including generic strings, numbers, alphabetic values and email addresses. This feature can be easily modified to aggregate even more classes.

At this stage, it’s clear to see how the previously defined bridge class has been completely decoupled from its implementation, since the validation process is performed by the respective “bridged” objects. Simple and efficient, right?

Now that I have mentioned “bridged” objects, in the following section I’ll show you all the signatures for their corresponding classes. In this way you can understand how the “validate()” method that you learned before is defined concretely by these classes.

To see how the mentioned classes will be coded, click on the link that appears below and keep reading.

{mospagebreak title=Defining a set of bridged classes}

As I mentioned in the previous section, once the already familiar “BridgeDataValidator” class has been appropriately defined, the only thing that remains undone consists of creating the group of “bridged” classes. These classes are tasked with validating different types of user-supplied data. As you may guess, this set of classes will complete the implementation of the bridge pattern in PHP 5.

Having said that, let me show you how these new “bridged” classes look. Here they are:

// define 'StringValidator' class class StringValidator{ const MIN=8; const MAX=64; // implement concretely 'validate()' method public function validate($inputData,$errorMessage){ if(!$inputData||!is_string($inputData)||strlen
($inputData)<self::MIN||strlen($inputData)>self::MAX){ throw new Exception($errorMessage); } } } // define 'NumberValidator' class class NumberValidator{ const MIN=-1000000; const MAX=1000000; // implement concretely 'validate()' method public function validate($inputData,$errorMessage){ if(!$inputData||!is_numeric
($inputData)||$inputData<self::MIN||$inputData>self::MAX){ throw new Exception($errorMessage); } }           } // define 'AlphabeticValidator' class class AlphabeticValidator{ const MIN=8; const MAX=64; // implement concretely 'validate()' method public function validate($inputData,$errorMessage){ if(!$inputData||!!preg_match
<self::MIN||strlen($inputData)>self::MAX){ throw new Exception($errorMessage); } } } // define 'EmailValidator' class class EmailValidator{ // implement concretely 'validate()' method public function validate($inputData,$errorMessage){ if(!$inputData||!$this->windnsrr($inputData)){ throw new Exception($errorMessage); } } // dnsrr() function for Windows systems private function windnsrr($hostName,$recType=''){       if($hostName){             if($recType=='')$recType="MX";             exec("nslookup -type=$recType $hostName",$result);            foreach($result as $line){                 if(preg_match("/^$hostName/",$line)){                   return true;                }            }             return false;         }         return false; } }

For this example, I defined only four “bridged” classes, which come in really handy for checking different types of data, such as simple strings, numbers, alphabetic values, and finally email addresses.

In addition to the previous explanation, you should notice how each of the classes offers a concrete implementation for its “validate()” method, in order to fit the validation requirements for a particular type of data. As you can see, this group of classes now reside on a different hierarchy level, something that perfectly follows the definition of the bridge pattern. After all, creating bridge classes with PHP 5 isn’t a difficult task at all, is it?

So far, so good. Now that you hopefully learned how the four “bridged” classes that were listed previously do their business, it would be very instructive to develop a hands-on example that demonstrates how the bridge pattern can be used for performing validation on different user-supplied data.

With reference to the practical example in question, over the course of the following section I’m going to code some simple scripts which will integrate not only the relevant “BridgeDataValidator” class that was shown previously, but all the corresponding independent classes that you learned a few lines before.

In order to see how this final example will be properly developed, please click on the link shown below and keep reading.

{mospagebreak title=Putting all the classes to work}

As you’ll recall from the section that you just read, in this final part of this article I’m going to set up a practical example that shows how to use all the classes that were previously created to validate different types of user-supplied data.

Indeed, this sounds really interesting and hopefully the code samples that you’ll see in a moment will help you grasp more easily how the bridge pattern can be implemented with a few simple PHP 5 classes.

Having said that, here is the corresponding set of try-catch blocks, which demonstrate the correct usage of each of the data validation classes that were built in previous sections, and the “BridgeDataValidator” class as well. Have a look at these examples, please:

// example to validate strings try{ // instantiate 'BridgeDataValidator' object $bdatVal=new BridgeDataValidator(array(1,2,3,4),
'The supplied input data must be a string!','string'); // validate string data $bdatVal->validate(); /* displays the following: The supplied input data must be a string! */ } catch(Exception $e){ echo $e->getMessage(); exit(); } // example to validate numbers try{ // instantiate 'BridgeDataValidator' object $bdatVal=new BridgeDataValidator('This is not a number',
'The supplied input data must be a number!','number'); // validate numeric data $bdatVal->validate(); /* displays the following: The supplied input data must be a number! */ } catch(Exception $e){             echo $e->getMessage();             exit(); } // example to validate alphabetic values try{ // instantiate 'BridgeDataValidator' object $bdatVal=new BridgeDataValidator(1234,'The supplied input data

must be an alphabetic value!','alpha'); // validate alphabetic data $bdatVal->validate(); /* displays the following: The supplied input data must be an alphabetic value! */ } catch(Exception $e){ echo $e->getMessage(); exit(); } // example to validate an email address try{ // instantiate 'BridgeDataValidator' object $bdatVal=new BridgeDataValidator('',
'The supplied input data must be a valid email address!','email'); // validate email address $bdatVal->validate(); /* displays the following: The supplied input data must be a valid email address! */ } catch(Exception $e){ echo $e->getMessage(); exit(); }

All right, I think that the group of code samples that were shown above are more than enough for demonstrating the correct implementation of the bridge design pattern in PHP 5. In addition, you should notice how in each case I provided the “BridgeDataValidator” object with an invalid input parameter, a condition that obviously throws the corresponding exception and also makes the script display the respective error message.

As I have said with many other articles that I wrote for the prestigious Developer Shed network, don’t hesitate to introduce your own modifications to all the sample classes that were shown here. This will help you to acquire a more intimate knowledge of how the bridge pattern works. It’s a really educational experience, trust me!

 Final thoughts

Unfortunately, we’ve come to the end of this article. However, I hope this tutorial has been instructive for you, specifically with reference to applying the bridge pattern as part of a more complex data validation application. As you saw, the process is really straightforward and also educational.

However, this journey is not over yet. In the last part of the series, I’m going to teach you how to use the mentioned pattern to build an abstraction layer for working with MySQL. See you in the final article!

Google+ Comments

Google+ Comments