PHP Form Wizard processing
Posted: Sat Aug 23, 2008 6:55 am
Hello,
I have a wizard form with 5 steps implemented already but I want to change the whole code to a better OO approach.
So far I got this classes:
And here's the code that uses the classes
My problems with this are:
1) In the Validator class the Validate() method is a very big one Switch statement, that is bothering me and I don't like it.
2) The above validations aren't flexible enough, because some validations need to be done in combining 2 or more fields for example a card number validation is different if the card type is visa or american express and this still needs more business logic behind it to work in this case. So you don't really gaining anything, but maybe this isn't a problem in the end, because this is the place where the higher business logic should go anyway.
3) I would use the Strategy Pattern here for different validators but I would end up with dozens of new subclasses which I reject because I use __autoloading and I want my class directory to be nice and tidy with few classes
Can you point me to a better approach? Am I missing something here?
Also I would want to use a similar approach for handling my wizard step processing, so far I haven't found a nice example of an OO wizard implementation.
I have a wizard form with 5 steps implemented already but I want to change the whole code to a better OO approach.
So far I got this classes:
Code: Select all
class Validator {
protected $fields;
/**
*
*/
function __construct() {
$this->fields = array();
}
/**
* Adds a ValidatorField
*
* @param ValidatorField $ValidatorField
*/
public function addField(ValidatorField $ValidatorField) {
$this->fields[] = $ValidatorField;
}
/**
* Validates the whole objects' data based on the corresponding criteria
*
*/
public function validate() {
/* @var $Errors Errors */
$Errors = Errors::getInstance();
foreach ($this->fields as $ValidatorField) {
/* @var $ValidatorField ValidatorField */
/* @var $ValidatorCriteria ValidatorCriteria */
$ValidatorCriteria = new ValidatorCriteria();
$value = $ValidatorField->getData();
if(strlen($value) == '') {
// it's empty so it's unvalidated
$ValidatorField->makeValid(false);
$Errors->addError($ValidatorField->getHTMLFieldID(), $ValidatorField->getErrorMsg());
} else {
switch ($ValidatorField->getCriteria()) {
case $ValidatorCriteria->POSITIVEINTEGER:
if(// PSEUDO CODE DOVALIDATION) {
$ValidatorField->makeValid(true);
} else {
$ValidatorField->makeValid(false);
$Errors->addError($ValidatorField->getHTMLFieldID(), $ValidatorField->getErrorMsg());
}
break;
// MORE CASES FOR ALL THE VALIDATION CRITERIA
}
}
}
}
/**
* Checks the whole data if they are checked and validated
*
* @return boolean
*/
public function isAllValid() {
$Debug = Debug::getInstance();
$validated = true;
foreach ($this->fields as $ValidatorField) {
/* @var $ValidatorField ValidatorField */
if($ValidatorField->isChecked()) {
if(!$ValidatorField->isValidated()) {
// If even on is not validated then unvalidate all
$validated = false;
$Debug->addMessage('unvalidated field ' . $ValidatorField->getHTMLFieldID());
}
} else {
// If even one is not checked then unvalidate all
$validated = false;
}
}
return $validated;
}
}Code: Select all
<?php
class ValidatorField {
protected $data;
protected $criteria;
protected $validated;
protected $checked;
protected $errorMsg;
protected $HTMLFieldID;
/**
*
*/
function __construct($HTMLFieldID, $data, $criteria, $errorMsg) {
$this->checked = false;
$this->validated = false;
$this->HTMLFieldID = $HTMLFieldID;
$this->data = $data;
$this->criteria = $criteria;
$this->errorMsg = $errorMsg;
}
/**
* @return unknown
*/
public function isChecked() {
return $this->checked;
}
/**
* Is validated?
*
* @return unknown
*/
public function isValidated() {
return $this->validated;
}
/**
* Validates the field
*/
public function makeValid($status) {
$this->checked = true;
if($status) {
$this->validated = true;
} else {
$this->validated = false;
}
}
}
?>
Code: Select all
class ValidatorCriteria {
public $POSITIVEINTEGER = 1;
public $NAME = 2;
public $EMAIL = 3;
public $STRING = 4;
public $CC3DIGITS = 5;
public $CC4DIGITS = 6;
public $CCEXPIREDATE = 7;
public $FULLNAME = 8;
public $ZIP = 9;
public $TELEPHONE = 10;
public $DATE = 11;
public $CCTYPE = 12;
public $CCVISANUMBER = 13;
public $CCMASTERNUMBER = 14;
public $CCAMEXNUMBER = 15;
/**
*
*/
function __construct() {
}
}
And here's the code that uses the classes
Code: Select all
// Create validators
$Validator = new Validator();
$ValidatorCriteria = new ValidatorCriteria();
// Add validation fields
$Validator->addField(new ValidatorField('firstname', $this->getValue('firstname'), $ValidatorCriteria->NAME, $Lexicon->getLexical('FIRSTNAME_IS_WRONG')));
$Validator->addField(new ValidatorField('lastname', $this->getValue('lastname'), $ValidatorCriteria->NAME, $Lexicon->getLexical('LASTNAME_IS_WRONG')));
$Validator->addField(new ValidatorField('customeremail', $this->getValue('customeremail'), $ValidatorCriteria->EMAIL, $Lexicon->getLexical('EMAIL_ADDRESS_IS_WRONG')));
// DOZENS AND DOZENS MORE OF VALIDATORFIELDS HERE
// Validate everything
$Validator->validate();
if(!$Validator->isAllValid()) {
$error = true;
}
1) In the Validator class the Validate() method is a very big one Switch statement, that is bothering me and I don't like it.
2) The above validations aren't flexible enough, because some validations need to be done in combining 2 or more fields for example a card number validation is different if the card type is visa or american express and this still needs more business logic behind it to work in this case. So you don't really gaining anything, but maybe this isn't a problem in the end, because this is the place where the higher business logic should go anyway.
3) I would use the Strategy Pattern here for different validators but I would end up with dozens of new subclasses which I reject because I use __autoloading and I want my class directory to be nice and tidy with few classes
Can you point me to a better approach? Am I missing something here?
Also I would want to use a similar approach for handling my wizard step processing, so far I haven't found a nice example of an OO wizard implementation.