#native_company# #native_desc#
#native_cta#

PHP Form Validation System: An Object-Oriented Approach Page 2

By Mike Weiner
on April 18, 2008

The Code

ValidationSet: 
Since all of our classes have been diagrammed, an experienced object-oriented PHP programmer will breeze through this step. Although we will try to focus on the code of the more complicated object methods, let??s take a quick look at the simpler methods of the ValidationSet class:

function ValidationSet($a_obj_DBConn = null)
	{
		$this->arr_validators = array();
		$this->arr_validationErrors = array();
		$this->obj_DBConn = $a_obj_DBConn;
		$this->bool_hasErrors = false;
	}

	
	function setDBConn($a_obj_DBConn)
	{
		$this->obj_DBConn = $a_obj_DBConn;
	}

	function getDBConn()
	{
		return $this->obj_DBConn;
	}
	
	
	function addValidator($a_obj_validator)
	{
		$a_obj_validator->setValidationSet(&$this);
		array_push($this->arr_validators, $a_obj_validator);
	}
	
	function addValidationError($a_obj_validationError)
	{
		array_push($this->arr_validationErrors, $a_obj_validationError);
		$this->setHasErrors(true);
	}

	function hasErrors()
	{
		return $this->bool_hasErrors;
	}
	
	
	function setHasErrors($a_bool_hasErrors)
	{
		$this->bool_hasErrors = $a_bool_hasErrors;
	}

Next we will look at the getErrors method. This method will essentially return an array of ValidationError objects. The complexity increases however, when we allow a parameter to dictate if each field should return multiple errors or just a single error. If we want to return just a single error for each field, we will use a for loop to search through each ValidationError. An IF statement will make sure we only add the error to the returned array if the field name is unique. Here??s the code:

	function getErrors($a_bool_allowMultipleErrors = false)
	{
		$arr_returnedErrors = array();
		$arr_fieldNames = array();
		
		if($a_bool_allowMultipleErrors)
		{
			$arr_returnedErrors = $this->arr_validationErrors;
		}
		else
		{
			for($i = 0; $i arr_validationErrors); $i++)
			{
				if(!in_array($this->arr_validationErrors[$i]->getFieldName(), $arr_fieldNames))
				{
					array_push($arr_fieldNames, $this->arr_validationErrors[$i]->getFieldName());
					array_push($arr_returnedErrors, $this->arr_validationErrors[$i]);
				}
			}
		}
		return $arr_returnedErrors;
	}

Our getErrorByFieldName method will also use a for loop to search through each ValidationError. We will check each ValidationError??s field name. If this field name matches the one passed as the parameter, the ValidationError is returned.

	function getErrorByFieldName($a_str_fieldName)
	{
		for($i = 0; $i arr_validationErrors); $i++)
		{
			if($this->arr_validationErrors[$i]->getFieldName() == $a_str_fieldName)
			{
				return $this->arr_validationErrors[$i]->getErrorMessage();
			}
		}
	}

The final method, validate, will loop through each of the stored validators. Inside this loop, we will call the validate method on each specific Validator object. Each of the specific validators will send back ValidationErrors accordingly.

	function validate()
	{
		for($i = 0; $i arr_validators); $i++)
		{
			$obj_validator = $this->arr_validators[$i];
			$obj_validator->validate();
		}
	}

Validator

The setValidationSet method can be written in one line. The most important thing to note here is that the ValidationSet parameter is passed by reference, and not by value. This method will allow each specific validator to access the ValidationSet??s methods. This will be important when we want to send a ValidationError back to the ValidationSet.

	function setValidationSet(&$a_obj_validationSet)
	{
		$this->obj_validationSet =& $a_obj_validationSet;
	}

Our second method, getValueByFieldName will use a foreach loop to search through all GET/POST variables. It will return the value of the variable that has the same name as what was passed as a parameter to the method.

	function getValueByFieldName($a_str_fieldName)
	{
		foreach($_REQUEST as $key => $value)
		{
		   if(strtolower($key) == strtolower($a_str_fieldName))
		   {
		   	return $value;
		   }
		}
	}

EmailValidator
Let??s take a look at the constructor here, as it will be a bit more complex than the other classes?? constructors. An IF statement will check and see if a field value was passed as a parameter, If it wasn??t, we are essentially telling the class to go ahead and search through all the GET/POST variables and find it automatically. Another IF statement will allow the class to have a default error message return if one wasn??t passed as a parameter. Here??s the code:
	function EmailValidator($a_str_fieldName, $a_str_errorMessage = null, $a_str_fieldValue = null)
	{
		$this->str_fieldName = $a_str_fieldName;
		$this->str_fieldValue = $a_str_fieldValue;
		
		if($this->str_fieldValue == null)
		{
			$this->str_fieldValue = $this->getValueByFieldName($this->str_fieldName);
		}

		if($a_str_errorMessage == null)
		{
			$this->str_errorMessage = "Invalid e-mail address";
		}
		else
		{
			$this->str_errorMessage = $a_str_errorMessage;
		}
	}
The validate method for this class will use RegEx to check for a valid email address. We should also take into consideration that we probably shouldn??t validate the email address if it is blank (a different type of Validator should check for this).

	function validate()
	{
		if(strlen($this->str_fieldValue) != 0)
		{
			if (!eregi('^[A-Z0-9._%-]+@[A-Z0-9._%-]+.[A-Z]{2,6}$', $this->str_fieldValue))
			{
				$this->obj_validationSet->addValidationError(new ValidationError($this->str_fieldName, $this->str_errorMessage));
			}
		}
	}

ValidationError

	function ValidationError($a_str_fieldName, $a_str_errorMessage)
	{
		$this->str_fieldName = $a_str_fieldName;
		$this->str_errorMessage = $a_str_errorMessage;
	}
	
	function getFieldName()
	{
		return $this->str_fieldName;	
	}
	
	
	function getErrorMessage()
	{
		return $this->str_errorMessage;	
	}

Implementation

Implementation of the system is fairly easy. We will begin with our PHP code which will precede our HTML. We will instantiate a ValidationSet, and check if the HTML form has been submitted. If submission has occurred, we will attach and run our Validator. If no errors are found, we will then be permitted to store the form data. Here??s an example using the EmailValidator:

	require_once('_includes/classes/validation/ValidationSet.php');
	
	$obj_validationSet = new ValidationSet();
	
	if($_POST['submitted'] == 'yes')
	{
		$obj_validationSet->addValidator(new EmailValidator('email'));
		$obj_validationSet->validate();
		
		if(!$obj_validationSet->hasErrors())
		{
			// store form data here
			// exit the page
		}
	}

The example HTML form will be simple as well. We will have one field called ??email?? that will submit as a POST variable. Should this field contain an error; the user will be notified by the getErrorByFieldName output.

	<html>
	<body>
	<form action="index.php" method="POST">
		<input type="hidden" name="submitted" value="yes" />
		<input type="text" name="email" value="<?=$_POST['email']?>" /><?=$obj_validationSet->getErrorByFieldName('email')?><br /><br />
		<input type="submit" value="submit" />
	</form>
	</body>
	</html>

Conclusion

Forms represent the primary means of enabling a user to send data to an application. Valid data will aid in the creation of streamlined, error-free applications. As a result, the need for a stable and modular form validation system is on the rise.
This system was designed the way it is, so that everyone can develop their own validators without affecting the core of the application. To save all of you some time however, I have made available a fully-documented open-source version of this system, you may download it here. I hope all of you have found this article informative, and have a newly grown respect for object-oriented development. Happy coding!