Home > Programming, Wordpress > Creating a String Range Rule with Monkey Wrench

Creating a String Range Rule with Monkey Wrench

January 7th, 2009

In this article, the third in a series of creating a business objects framework for the Wordpress blogging environment, we will discuss the construction of a custom rule class based on the Rule abstract base class from the last article.

The source file for the the entire framework may be downloaded here. We will be covering StringRangeRule.php.

The StringRangeRule Class

Using the abstract base class Rule which we created last time, we will build a class to solve a common validation problem. For the sake of database integrity and business goals, it is common to enforce length restrictions on some of the text properties of an object. Our string range validator can be configured to do the following.

  • Set min and max length values so that the string length must fall within the range.
  • Set min to zero and provide a max so that the string may be any length not exceeding the max.
  • Set max to zero and provide a min so that the string may be any length as long as it is at least min characters in length.

Our class will provide a neat package for handling the tasks on the above list.

Let’s write some code!

 
We begin by using <strong>require_once</strong> to reference the <strong>Rule.php</strong> file containing our base class.  In my setup, the <strong>Rule.php</strong> file is in the same directory as  our new class.  We inherit from <strong>Rule</strong> using the <strong>extends</strong> key word.  We declare the <strong>Min</strong> and <strong>Max</strong> member variables.  These variables are declared as protected so that you could create other classes based on our new class which would have access to the Min and Max member variables.
<pre lang="php">// Public State Methods
 
	/**
	 * Minimum length allowed for string.
	 *
	 * @return number
	 */
	public function GetMin()
	{
		return $this-&gt;m_Min;
	}
 
	/**
	 * Sets minimum allowed length for string.
	 *
	 * @param number $value
	 */
	public function SetMin($value)
	{
		$this-&gt;m_Min = $value;
	}
 
	/**
	 * Maximum length allowed for string.
	 *
	 * @return number
	 */
	public function GetMax()
	{
		return $this-&gt;m_Max;
	}
 
	/**
	 * Sets maximum allowed length for string.
	 *
	 * @param number $value
	 */
	public function SetMax($value)
	{
		$this-&gt;m_Max = $value;
	}

The code above contains “getters and setters” for our member variables. Notice that I am documenting these methods per our discussion about coding style and documentation in the first article.

	// Constructors
 
	/**
	 * Constructor
	 * @param string $_ruleName
	 * @param string $_propertyName
	 * @param string $_min
	 * @param string $_max
	 *
	 */
	public function __construct($_ruleName, $_propertyName, $_min, $_max)
	{
		parent::__construct($_ruleName, $_propertyName, '');
 
		$this-&gt;m_Min = $_min;
		$this-&gt;m_Max = $_max;
 
		// check the max and min values
		$this-&gt;CheckValues();
 
		// set the display text
		$this-&gt;CalculateDisplayText();
 
	}

The constructor above takes in the rule name and property names, as does our base class, and adds two new parameters representing the min and max values for our new class. We call the constructor on the base class in line 70 using the parent::_construct() method and passing along the rule name and property name values. Values for Max and Min are then assigned based on the appropriate parameter values. In lines 76 and 79, we call helper functions in our class to check for proper min and max values and to construct a good user description based on the values for min and max.

// Overrides
 
	public function Validate($_objectToValidate)
	{
		// Check the values again to make sure the rule is set up properly.
 
		$_MethodName = 'Get' . $this-&gt;m_PropertyName;
		$this-&gt;m_PropertyValue = $_objectToValidate-&gt;$_MethodName();
 
		$this-&gt;CheckValues();
 
		$_MinOnly = $this-&gt;m_Min &gt; 0 &amp;&amp; $this-&gt;m_Max == 0;
		$_MaxOnly = $this-&gt;m_Max &gt; 0 &amp;&amp; $this-&gt;m_Min == 0;
		$_MaxAndMin = $this-&gt;m_Min &gt; 0 &amp;&amp; $this-&gt;m_Max &gt; 0 &amp;&amp; $this-&gt;m_Min &lt; $this-&gt;m_Max;
		$_Len = strlen($this-&gt;m_PropertyValue);
 
		if($_MinOnly == true)
		{
			$this-&gt;m_IsValid = $_Len &gt;= $this-&gt;m_Min;
			return;
		}
 
		if($_MaxOnly == true)
		{
			$this-&gt;m_IsValid = $_Len &lt;= $this-&gt;m_Max;
			return;
		}
 
		if($_MaxAndMin == true)
		{
			$this-&gt;m_IsValid = ($_Len &gt;= $this-&gt;m_Min)
			&amp;&amp; ($_Len &lt;= $this-&gt;m_Max);
 
			return;
		}
 
	}

We arrive at our only override from the Rule base class in line 84. We declared this method to be abstract in the Rule base class, so we are required to implement the method in our new class. In line 91, we set out to get the value of the correct property from the object which has been passed in. Since we are using a convention of “getters and setters”, we can construct the proper “get” call to grab the value from the object. For example, if our rule is set to validate the LastName of a Person object at runtime, the call to get that value would be GetLastName(). Another call is placed to CheckValues() to make sure that the values are still good. We do this because the object could have been edited with the interface methods since the initial call to the constructor. Lines 96 to 99 create member variables representing how the object has been configured based on the min and max values. The length of the property value is recorded for comparison to the min and max values. Lines 101 to 119 set the m_IsValid variable for the correct configuration scenario.

	// Helper Methods
 
	/**
	 * Figures out how to display the rule text to the user based on the
	 * values of Min and Max.
	 *
	 */
	private function CalculateDisplayText()
	{
		if($this-&gt;m_Min == 0 &amp;&amp; $this-&gt;m_Max &gt; 0)	// we have a rule where only the max has been set
		{
			$this-&gt;m_DisplayText = $this-&gt;m_PropertyName . ' may be no longer than ' . $this-&gt;m_Max . ' characters in length.';
		}
 
		if($this-&gt;m_Min &gt; 0 &amp;&amp; $this-&gt;m_Max == 0)	// we have a rule where only the min has been set
		{
			$this-&gt;m_DisplayText = $this-&gt;m_PropertyName . ' must be at least ' . $this-&gt;m_Min . ' characters in length.';
		}
 
		if($this-&gt;m_Min &gt; 0 &amp;&amp; $this-&gt;m_Max &gt; 0 &amp;&amp; $this-&gt;m_Min &lt; $this-&gt;m_Max)	// we have a rule where min and max have been set
		{
			$this-&gt;m_DisplayText = $this-&gt;m_PropertyName . ' must be between ' . $this-&gt;m_Min . ' and ' . $this-&gt;m_Max . ' characters in length.';
		}
	}
 
	/**
	 * Checks values for min and max set by the programmer.
	 * Min must be less than max if max is greater than zero.
	 * Max must be greater than min if min is greater than zero.
	 * Neither may be a negative number.
	 * Both values may not be equal to zero at the same time.
	 *
	 */
	private function CheckValues()
	{
		// check for negative values
		if($this-&gt;m_Min &lt; 0 || $this-&gt;m_Max &lt; 0)
		{
			throw new Exception('Min or Max values may not be less than zero.');
		}
 
		// check for double zeros.
		if($this-&gt;m_Min == 0 &amp;&amp; $this-&gt;m_Max == 0)
		{
			throw new Exception('Min or Max values may not both be set to zero.');
		}
 
		// check for min less than max when max is set
		if($this-&gt;m_Max &gt; 0 &amp;&amp; $this-&gt;m_Min &gt;= $this-&gt;m_Max)
		{
			throw new Exception('If Max is set to a non zero number, Min must be less than Max.');
		}
 
		// check for max greater than min when min is set
		if($this-&gt;m_Min &gt; 0 &amp;&amp; $this-&gt;m_Max &lt;= $this-&gt;m_Min &amp;&amp; $this-&gt;m_Max != 0)
		{
			throw new Exception('If Min is set to a non zero number, Max must be greater than Min.');
		}
 
	}
 
}
?&gt;

CalculateDisplayText() creates a message for the user based on how the min and max values are set. You can see that CheckValues() is throwing an exception if there are crazy values set up for an object of our class. These kinds of errors would be the result of improper coding while using the class. Their audience is the developer. I feel that it is important to provide this kind of feedback for others.

Conclusion

We now have a base class and a product of that class to use going forward with our framework. Hopefully, you’re thinking of a few other classes you might create to handle some common validation situations that you run in to. Feel free to send in your code. I will add them to the framework and discuss the new classes on the blog. In the next article, we are going to build another abstract base class which makes use of the validation classes we have created so far. I know it’s a long road, but we’ll have some really cool development tools as we move forward.

Also Available in This Series

Did you like this? If so, please bookmark it,
tell a friend
about it, and subscribe to the blog RSS feed.

Programming, Wordpress , ,

  1. No comments yet.
  1. No trackbacks yet.