I'll show the code from the devshed articles:
example:
Code: Select all
include 'DataValidator.class.php';
include 'FormObserver.class.php';
try{
// instantiate 'FormObserver' object
$formObs=new FormObserver('send');
// instantiate validators and validate fields
$alphaVal=new AlphaValidator($formObs);
$alphaVal->validate('firstname','Enter a valid First Name (only alphabetic characters).');
$alphaVal->validate('lastname','Enter a valid Last Name (only alphabetic characters).');
$intVal=new IntegerValidator($formObs);
$intVal->validate('age','Enter a valid age (0-99).');
$emailVal=new EmailValidatorWin($formObs);
$emailVal->validate('email','Enter a valid email address.');
// check for errors
$formObs->checkNotifications();
}
catch(Exception $e){
echo $e->getMessage();
exit();
}Code: Select all
<?php
/**
* 5-8-06
* Centralizing the Validation of Data with the Observer Pattern in PHP
* http://www.devshed.com/c/a/PHP/Centrali ... rn-in-PHP/
* Alejandro
*/
// class FormObserver
class FormObserver{
private $notifications;
private $formVar;
public function __construct($formVar){
//$this->formVar=$_POST[$formVar];
$this->formVar=!isset($_POST[$formVar])?'':$_POST[$formVar];
$this->notifications=array();
}
public function addNotification($errorMessage){
$this->notifications[]=$errorMessage;
}
public function checkNotifications(){
if(!$this->formVar){
$this->displayForm();
}
else
{
if(count($this->notifications)>0){
// form is not OK
$this->displayErrors();
$this->displayForm();
}
else
{
// form is OK
echo '<p>The form has been submitted successfully!</p>';
}
}
}
// display errors
private function displayErrors(){
$errstr='<p>Please correct the following fields and resubmit the form:</p>';
foreach($this->notifications as $notification){
$errstr.='<p>'.$notification.'</p>';
}
echo $errstr;
}
// display form
public function displayForm(){
$formstr='<form action="'.$_SERVER['PHP_SELF'].'" method="post">';
$formstr.='First Name <input type="text" name="firstname" value="'.$_POST['firstname'].'"/><br />';
$formstr.='Last Name <input type="text" name="lastname" value="'.$_POST['lastname'].'" /><br />';
$formstr.='Email <input type="text" name="email" value="'.$_POST['email'].'" /><br />';
$formstr.='Age <input type="text" size="1" name="age" value="'.$_POST['age'].'" /><br />';
$formstr.='<input type="submit" value="Send" name="send" /></form>';
echo $formstr;
}
}
?>Code: Select all
<?php
/**
* 5-8-06
* Centralizing the Validation of Data with the Observer Pattern in PHP
* http://www.devshed.com/c/a/PHP/Centrali ... rn-in-PHP/
* Alejandro
*/
// define DataValidator class
class DataValidator{
protected $method;
protected $formObserver;
public function __construct(FormObserver $formObserver){
$this->formObserver=$formObserver;
$this->method=$_POST;
}
protected function notifyObserver($errorMessage){
$this->formObserver->addNotification($errorMessage);
}
}
// define StringValidator class
class StringValidator extends DataValidator{
public function __construct($formObserver){
parent::__construct($formObserver);
}
// validate strings
public function validate($field,$errorMessage,$min=4,$max=32)
{
if(!isset($this->method[$field])
|| trim($this->method[$field])==''
|| strlen($this->method[$field])<$min
|| strlen($this->method[$field])>$max)
{
$this->notifyObserver($errorMessage);
}
}
}
// define IntegerValidator class
class IntegerValidator extends DataValidator{
public function __construct($formObserver){
parent::__construct($formObserver);
}
// validate integers
public function validate($field,$errorMessage){
if(!isset($this->method[$field])
|| !is_numeric($this->method[$field])
||intval($this->method[$field])!=$this->method[$field]){
$this->notifyObserver($errorMessage);
}
}
}
// define NumberValidator class
class NumberValidator extends DataValidator{
public function __construct($formObserver){
parent::__construct($formObserver);
}
// validate numbers
public function validate($field,$errorMessage){
if(!isset($this->method[$field])
|| !is_numeric($this->method[$field])){
$this->notifyObserver($errorMessage);
}
}
}
// define RangeValidator class
class RangeValidator extends DataValidator{
public function __construct($formObserver){
parent::__construct($formObserver);
}
// validate ranges
public function validate($field,$errorMessage,$min=1,$max=99){
if(!isset($this->method[$field])
|| $this->method[$field]<$min || $this->method[$field]>$max){
$this->notifyObserver($errorMessage);
}
}
}
// define AlphaValidator class
class AlphaValidator extends DataValidator{
public function __construct($formObserver){
parent::__construct($formObserver);
}
// validate alphabetic field
public function validate($field,$errorMessage){
if(!isset($this->method[$field])
|| !preg_match("/^[a-zA-Z]+$/",$this->method[$field])){
$this->notifyObserver($errorMessage);
}
}
}
// define AlphanumValidator class
class AlphanumValidator extends DataValidator{
public function __construct($formObserver){
parent::__construct($formObserver);
}
// validate alphanumeric data
public function validate($field,$errorMessage){
if(!isset($this->method[$field])
|| !preg_match("/^[a-zA-Z0-9]+$/",$this->method[$field])){
$this->notifyObserver($errorMessage);
}
}
}
// define EmailValidator class
class EmailValidator extends DataValidator{
public function __construct($formObserver){
parent::__construct($formObserver);
}
// validate email
public function validate($field,$errorMessage){
if(!isset($this->method[$field])
|| !preg_match("/.+@.+..+/",$this->method[$field])
||!checkdnsrr(array_pop(explode("@",$this->method[$field])),"MX")){
$this->notifyObserver($errorMessage);
}
}
}
// define EmailValidatorWin class (Windows systems)
class EmailValidatorWin extends DataValidator{
public function __construct($formObserver){
parent::__construct($formObserver);
}
public function validate($field,$errorMessage){
if(!isset($this->method[$field])
|| !preg_match("/.+@.+..+/",$this->method[$field])
|| !$this->windnsrr(array_pop(explode("@",$this->method[$field])),"MX")){
$this->notifyObserver($errorMessage);
}
}
// private method 'windnsrr()' for Windows systems
private function windnsrr($hostName,$recType=''){
if(!empty($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;
}
}
?>- I do like how the validation classes are nicely seperated. Each form of validation has it's own class. So that's ok.
- I don't like the fact that the form is hardcoded in the Observer class in the function displayForm. Suppose you have a whole bunch of forms, how would I refactor the code to seperate those?
As I'm not experienced enough to see other pitfalls I'm asking for your input. Just recently there was a thread about when to use the observer pattern, and form validation was not mentioned. Was that for a reason?
(p.s. if the mods want me to shorten the code I'll do that.)