help getting base class to recognize extending class values

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

help getting base class to recognize extending class values

Post by s.dot »

This is a form validation class that I'm trying out. It's really nothing fancy, i'm just getting started on it, but already having troubles.

Code: Select all

<?php

/**
 * Form validation base class
 */
class formValidator
{
	//container for rules
	protected $_rules = array();
	
	/**
	 * Method to add rules
	 */
	public function addRule(formValidator $rule)
	{
		$rule->_add();
	}
	
	public function validate()
	{
		//
	}
	
	public function show()
	{
		echo '<pre>';
		print_r($this->_rules);
		echo '</pre>';
	}
}

class formValidatorRequired extends formValidator
{
	private $_field;
	
	public function __construct($field)
	{
		$this->_field = $field;
	}
	
	protected function _add()
	{
		if (is_array($this->_field))
		{
			foreach ($this->_field AS $field)
			{
				$this->_rules['required'][] = $field;
			}
		} else
		{
			$this->_rules['required'][] = $this->_field;
		}
	}
}

class formValidatorLength extends formValidator
{
	private $_field;
	private $_minLength;
	private $_maxLength;
	
	public function __construct($field, $minLength, $maxLength)
	{
		$this->_field = $field;
		$this->_minLength = $minLength;
		$this->_maxLength = $maxLength;
	}
	
	protected function _add()
	{
		$this->_rules['length'][] = array(
			$field => array(
				'minLength' => $this->_minLength,
				'maxLength' => $this->_maxLength
			)
		);
	}
}
And I am calling it like this:

Code: Select all

if (!empty($_POST['action']) && ($_POST['action'] == 'register'))
{
	//form validation object
	require_once 'class/formValidator.php';
	$formValidator = new formValidator();
	
	//add rules
	$formValidator->addRule(
		new formValidatorRequired(array('username', 'password', 'passwordConfirm', 'email', 'emailConfirm'))
	);
	
	$formValidator->show();
}
I added the show() method just to see if the rules had been added to the formValidator object. But it always prints out an empty array. What am I doing wrong here?
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Post by s.dot »

basically, formValidatorRequired::_rules is getting set, but I need formValidator::_rules to be set
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

_add(), which needs to be defined in the base, technically, in the children manipulates only the child class, not the containing class, as they are separate objects.

You need a method (or modify one) to take a formValidator that will be injected with the data, or rethink what formValidator means, versus the children you have built thus far.

You are calling them rules, so are they supposed to be formValidators in their own right, or rules that the formValidator follows?
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Post by s.dot »

Basically I was thinking that since the rule classes extends formValidator, that any reference to $this->_rules would reference the member in the formValidator class, rather than creating a member in the rule classes.

What I want to end up with is a member in class formValidator that looks like:

Code: Select all

Array
(
    required => Array(
        [0] => field1
        [1] => field2
        [2] => field3
    )

    length => Array
    (
         username => Array
         (
            minlength => 3,
            maxlength => 25
         )
         password => Array
         (
             minlength => 6,
             maxlength => false
         )
)
So that my validate() method can iterate through the array and perform necessary checks.

How that translates into what you just said, I don't know. Basically I didn't understand:
You need a method (or modify one) to take a formValidator that will be injected with the data, or rethink what formValidator means, versus the children you have built thus far.
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Post by s.dot »

o0o I got it.

The method addRule() needs to add onto the member

Code: Select all

public function addRule(formValidator $rule)
{
    $this->_rules = array_merge($this->_rules, $rule->_add());
}
And the $rule->_add() methods need to return data (an array).
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Post by s.dot »

Okay, so this is what I have so far. My question now is if my logic and the way I set up the objects is good? This isn't really critique, because I don't know if what I have is right. The only thing I can think of is that I'm expecting the form to be posted via $_POST.

Is there anything I should be doing differently?

Code: Select all

<?php

require_once 'class/formvalidator/rule/length.php';
require_once 'class/formvalidator/rule/required.php';
require_once 'class/formvalidator/rule/regex.php';

/**
 * Form validation base class
 */
class formValidator
{
	//container for rules
	protected $_rules = array();
	
	/**
	 * Method to add rules
	 */
	public function addRule(formValidator $rule)
	{
		$this->_rules = array_merge_recursive($this->_rules, $rule->_add());
	}
	
	public function validate()
	{
		if ($this->_validateRequired() && $this->_validateLength() && $this->_validateRegex())
		{
			return true;
		}
		
		return false;
	}
	
	private function _validateRequired()
	{
		//required rules
		if (!empty($this->_rules['required']))
		{
			foreach ($this->_rules['required'] AS $required)
			{
				if (empty($_POST[$required]) || (trim($_POST[$required]) == ''))
				{
					return false;
				}
			}
		}
		
		return true;
	}
	
	private function _validateLength()
	{	
		//length rules
		if (!empty($this->_rules['length']))
		{
			foreach ($this->_rules['length'] AS $field => $length)
			{
				$strlen = strlen($_POST[$field]);
				if (($strlen < $length['minLength']))
				{
					return false;
				}
				
				if ($length['maxLength'] && ($strlen > $length['maxLength']))
				{
					return false;
				}
			}
		}
		
		return true;
	}
	
	private function _validateRegex()
	{	
		//regex rules
		if (!empty($this->_rules['regex']))
		{
			foreach ($this->_rules['regex'] AS $field => $pattern)
			{
				if (!preg_match($pattern, $_POST[$field]))
				{
					return false;
				}
			}
		}
		
		return true;
	}
	
	public function show()
	{
		echo '<pre>';
		print_r($this->_rules);
		echo '</pre>';
	}
}

Code: Select all

<?php

class formValidator_Rule_Required extends formValidator
{
	private $_field;
	
	public function __construct($field)
	{
		$this->_field = $field;
	}
	
	protected function _add()
	{
		$ret = array();
		if (is_array($this->_field))
		{
			foreach ($this->_field AS $field)
			{
				$ret['required'][] = $field;
			}
		} else
		{
			$ret['required'] = $this->_field;
		}
		return $ret;
	}
}

Code: Select all

<?php

class formValidator_Rule_Length extends formValidator
{
	private $_field;
	private $_minLength;
	private $_maxLength;
	
	public function __construct($field, $minLength=false, $maxLength=false)
	{
		$this->_field = $field;
		$this->_minLength = $minLength;
		$this->_maxLength = $maxLength;
	}
	
	protected function _add()
	{
		$ret = array();
		$ret['length'] = array(
			$this->_field => array(
				'minLength' => $this->_minLength,
				'maxLength' => $this->_maxLength
			)
		);
		
		return $ret;
	}
}

Code: Select all

<?php

class formValidator_Rule_Regex extends formValidator
{
	private $_field;
	private $_regex;
	
	public function __construct($field, $regex)
	{
		$this->_field = $field;
		$this->_regex = $regex;
	}
	
	protected function _add()
	{
		$ret = array();
		$ret['regex'] = array($this->_field => $this->_regex);
		
		return $ret;
	}
}
And I'm calling it like this:

Code: Select all

//form validation object
require_once 'class/formvalidator/formvalidator.php';
$fv = new formValidator();

//add rules
$fv->addRule(new formValidator_Rule_Required(array('username', 'password', 'passwordConfirm', 'email', 'emailConfirm')));
$fv->addRule(new formValidator_Rule_Length('username', 3, 25));
$fv->addRule(new formValidator_Rule_Length('password', 6));
$fv->addRule(new formValidator_Rule_Regex('username', '/[\w]+/'));

var_dump($fv->validate());
$fv->show();
Basically I'm second-guessing everything I'm doing. =/ I think it's because whenever I bring up an OO subject, there's so many different ways of doing things that I lose interest halfway through the topic because I'm completely lost. I'm learning slowly but surely.

So far the validator is working good. I should implement some tests (note to maugrim ;)).
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

Personally, I would actually shift the validation routines to the rules themselves. Allowing the formValidator to simply facilitate the connection between data and validator. This allows you to use custom or "odd" forms of validation that the now base doesn't support. The reason why I don't like it now is that the formValidator knows too much about the children it seems, and the children know too much about the parent.

I think they should be entirely separate classes (no inheritance between them.)
User avatar
stereofrog
Forum Contributor
Posts: 386
Joined: Mon Dec 04, 2006 6:10 am

Post by stereofrog »

class formValidator_Rule_Regex extends formValidator
doesn't feel right to me. Validator is what manages and applies Rules (which in turn know nothing about Validator).
Post Reply