Controlling Online Forms with Builder Objects in PHP 5

Mastering some of the most popular design patterns with PHP 5 can be sometimes an overwhelming process that requires hard work and experience. However, if you want to tackle the challenge and expand your existing background on them, this article might eventually find a place on your quick reference list.

Introduction

This is the second part of the series “How to use builder objects in PHP 5.” Made up of three tutorials, this series introduces the basics of working with directors and builders with PHP, and teaches you how to use them in real-world environments.

One of the most interesting aspects of working with design patterns that fall under the creation category rests on understating the different relationships that can be defined between two or more objects to build a third one. That’s exactly the logic that stands behind using directors and builders. That concept was deeply covered in the first article, when I set up an introductory example for generating basic XML pages.

As an useful reminder, allow me to explain quickly what I mean when I talk about using directors and builders. In short, these two types of objects are used in conjunction to build another one via a well-defined behavior. This behavior is defined as follows: first, the builder is responsible for creating the target object, while the director, as its name implies, establishes what specific parts of the third object should be included in the creation process. Does this definition sound familiar to you? I hope it does.

Okay, once the key concepts surrounding the implementation of the builder pattern with PHP have been properly grasped, it’s time to leap forward and continue learning more hands-on examples. Specifically, in this second article of the series, I’ll go deeper into the topic and show you how to use both directors and builders to construct and control programmatically online forms.

Having established the goals of this article, let’s jump straight into the subject and find out how web forms can be created by using the builder pattern. Let’s get going!

{mospagebreak title=Defining a form element class}

In order to start demonstrating how the builder pattern can be used for constructing online forms, first I need to define a target object that can be “manipulated” by the corresponding director and builder objects.

First I’ll define an abstract “FormElement” class and then I’ll derive a child from it, which will offer a concrete implementation for all its abstract methods. That said, here is the initial definition of the “AbstractFormElement” class:

// define abstract 'AbstractFormElement' class abstract class AbstractFormElement{ abstract function getHTML(); }

 

If you were thinking that creating an abstract form element class with PHP was a hard-to-perform process, then I believe you’ll find that you’re wrong. As usually, the previous class defines the generic structure of a typical form control, and also presents an abstract method called “getHTML(),” which will be responsible for returning to calling code the appropriate (X)HTML markup that corresponds to the online form in question. As you can see, this is nothing unexpected.

Now, let me take one step forward and create a child class from the “AbstractFormElement” class defined earlier. The signature of this new sub class is listed below, thus examine its source code:

// define concrete 'formElement' class class FormElement extends AbstractFormElement{ private $html=''; public function __construct($type='text',$attributes=array
('name'=>'default'),$options=array()){ // check for <input> elements         if(preg_match("/^(text|radio|checkbox|password|
hidden|submit|reset|button|image|file)$/",$type)){           $openTag='<input type="'.$type.'" '; $closeChar=' ';            $closeTag='/>'; } // check for <textarea> and <select> elements else if(preg_match("/^(textarea|select)$/",$type)){           $openTag='<'.$type.' ';           $closeChar='>';             $closeTag='</'.$type.'>'; } else{ throw new Exception('Invalid form element
type'); }        if(!is_array($attributes)||count($attributes)<1){ throw new Exception('Invalid number of
attributes for <'.type.'> element'); } //loop over element attributes $elemAttributes=''; foreach($attributes as $attribute=>$value){ if(!$attribute||!$value){ throw new Exception
('Invalid attribute or value for <'.type.'> element'); }             $elemAttributes.=$attribute.'="'.$value.'" '; } //check for <select> options $selOptions=''; if(count($options)>0){            foreach($options as $value=>$text){                if(!$value||!$text){ throw new Exception
('Invalid value or text for <'.type.'> element' }            $selOptions.
='<option value="'.$value.'">'.$text.'</option>'; } } // build form element(X)HTML output       $this->html.=$openTag.trim($elemAttributes).
$closeChar.$selOptions.$closeTag; } // return overall (X)HTML output public function getHTML(){ return $this->html; } }

 

As illustrated above, now the new child “FormElement” class offers a concrete implementation for each of the methods declared in the base class. Of course, the most important thing to note here concerns all the tasks performed inside the constructor.

As you can appreciate, this method really does all the hard work required for creating the (X)HTML markup that corresponds to each element of a regular online form, based on the pair of arrays supplied as input arguments. Finally, the respective form’s code is retrieved by the tight “getHTML()” method. Simple and powerful!

Well, now that you know how the target object (in this case referenced by the “FormElement” class) has been correctly defined, the next step consists of creating the corresponding builder class, in this way introducing the second component required by the builder pattern (remember that the third one is the director). 

In the next section I’ll be defining the mentioned builder class, therefore I recommend you click on the below link and keep on reading. See you there.

{mospagebreak title=Creating a form builder class}

In the section that you just read, you saw how the “FormElement” class was defined to have at its disposal a target object to work with. Now, it’s time to move forward and see how a second class, that is the one called “builder,” can be created in such a way that it’ll be able to construct different form components.

By using a similar approach to the one utilized for defining the “FormElement” class that was shown before, I’ll first create an abstract form builder class, and then derive a single child from it, which will expose some concrete methods for building online forms.

In accordance with the concepts expressed above, here is the definition of the first abstract class, which I called obviously “AbstractFormBuilder.” Please, have a quick look at its simple signature:

// define abstract 'AbstractFormBuilder' class abstract class AbstractFormBuilder{ abstract function getForm(); }

As you can see, there’s not much to be said about the above class. The only thing worth highlighting is the declaration of the “getForm()” method, which when concretely implemented will return the corresponding (X)HTML markup of the online form being constructed.

After showing the signature of the base “AbstractFormBuilder” class, pay attention to the next one, which offers a concrete implementation for the method defined previously:

// define concrete 'FormBuilder' class class FormBuilder extends AbstractFormBuilder{ private $html=array(); private $action; private $method; public function __construct($action='',$method='post'){ // setup form attributes        $this->action=!$action?$_SERVER['PHP_SELF']:$action;      $this->method=$method!='post'||$method!
='get'?'post':$method; } // add form element public function addElement($type='text',$attributes=array
('name'=>'default'),$options=array()){

if(!$elem=new FormElement($type,$attributes,$options)){ throw new Exception
('Failed to instantiate '.$type.' object'); }      $this->html[]=$elem->getHTML(); } // add form part public function addFormPart($formPart='<br />'){       $this->html[]=trim($formPart)==''?'<br />':$formPart; } // get web form public function getForm(){        $formOutput='<form action="'.
$this->action.'" method="'.$this->method.'">';       foreach($this->html as $html){             $formOutput.=$html; }        $formOutput.='</form>'; return $formOutput; } }

 

If you take some time and analyze the source code of the above class, then you’ll understand in a snap what it does. Basically, this sub class is capable of building a typical online form, based on a few input parameters, such the $method and $action variables, as well as the set of arguments passed to its “addElement()” method.

As you’ll possibly realize, this method acts like a true form element factory (notice the instantiation of “FormElement” objects from inside the method’s scope), and uses the advantages of polymorphism, in order to generate the (X)HTML markup that corresponds to each form element being created.

Lastly, the functionality of the “getForm()” method is limited simply to returning to calling code the form’s complete output. Due to its extreme simplicity, I won’t stop long on this one, therefore let me recapitulate for a moment, and show you what I have accomplished up until now.

At this point I created the two first components required for getting the builder pattern working, that is the target object to be created (in this case represented by the “FormElement” class), and the respective form builder. Indeed, it looks like I’m very close to implementing correctly the pattern in question.

However, before doing that, I’d like to show you a short and comprehensive example, aimed at demonstrating how the set of classes that I wrote earlier are really functional when building web forms.

To see how this will be done, please go ahead and read the following section.

{mospagebreak title=Constructing a basic online form}

Basically, the example that I am just about to provide to you will illustrate the way that the form builder works, based on the class definition that you saw in the previous section. But what’s the point of doing this, after all? Well, before I proceed to work directly with directors and builders, I want to demonstrate that all the objects involved in the creation process are fully functional.

Al right, assuming that all the classes have been placed inside the “classes” directory, a basic contact form might be programmatically built like this:

// generate sample online form try{ // include class files   require_once('classes/form_element_class.php'); require_once('classes/form_builder_class.php'); // instantiate form builder object $fb=new FormBuilder(); // add some form parts and elements $fb->addFormPart('<table>');   $fb->addFormPart('<tr><td>First Name</td><td>');    $fb->addElement('text',array('name'=>'fname'));    $fb->addFormPart('</tr>');     $fb->addFormPart('<tr><td>Last Name</td><td>');     $fb->addElement('text',array('name'=>'lname'));    $fb->addFormPart('</tr>'); $fb->addFormPart('<tr><td>Email</td><td>'); $fb->addElement('text',array('name'=>'email'));     $fb->addFormPart('</tr>');    $fb->addFormPart('<tr><td>Comments</td><td>');     $fb->addElement('textarea',array('name'=>'comments',
'rows'=>'10','cols'=>'20'));     $fb->addFormPart('</tr>');     $fb->addFormPart('<tr><td>&nbsp;</td><td>'); $fb->addElement('submit',array('name'=>'send','value'=>
'Send Data'));    $fb->addFormPart('</tr></table>'); // display online form echo $fb->getForm(); } catch(Exception $e){ echo $e->getMessage(); exit(); }

In this case, the example listed above shows in a nutshell how the proper combination of only one form builder and some form element objects is good enough to create a sample contact form, which is composed of the following typical input boxes: First Name, Last Name, Email and Comments respectively.

After running the previous script, it neatly displays the form depicted below:

As you can see, the above screen shot demonstrates the excellent functionality provided by the form builder class, as well as by the respective form element objects, particularly when used in tandem.

At this stage, and after proving that the two first components required by the builder pattern work pretty well, the only thing that remains undone is logically creating the respective director class to construct online forms based on its directives.

However, I saved the best for the last, since this procedure will be covered in the last tutorial. In the meantime, have fun tweaking the code of all the classes shown here!

To wrap up

In this second part of the series, I showed you how to use the builder pattern in a more useful fashion: building online forms. Nevertheless, as I said before, the development process is still incomplete, since the corresponding director class hasn’t been defined yet.

That’s an excellent reason to catch the last part. See you then!

[gp-comments width="770" linklove="off" ]

chat