Forms

This page documents the APF form support included up to release 1.10. Within release 1.11, the form integration was completely reworked. The new documentation can be found in chapter Forms.
The form taglibs contained in the releases up to 1.10 can be seen on .
The adventure php framework supports the dynamic generation and abstraction of forms out-of-the-box. Owing to the generic tag parser forms can be mapped by XML tags in template files and thus are embedded in the DOM tree of the presentation layer. Thereby it is possible to give "internal intelligence" to form elements. This implies automatic filling with the help of an URL parameter and the validation of user inputs. The behaviour of these features can be influenced by configuring the form elements via tag attributes. It is not necessary to implement functionality of these elements for the current application.


1. Construction of forms

APF forms are simily to the HTML templates discussed under templates. Each form can be seen as a child object of the current DOM node. To get a reference on this object each document controller feature the __getForm() method. The form class has the following API:
  • addFormElement()
    Adds a form element at the end of the current form. This method can be used for dynamic form creation.
  • addFormContent()
    Adds content (HTML or text) to the end of the currend form. This method can be used for dynamic form creation.
  • addFormContentBeforeMarker()
    Adds content (HTML or text) before a marker tag to the current form. This method can be used for dynamic form creation.
  • addFormContentAfterMarker()
    Adds content (HTML or text) after a marker tag to the current form. This method can be used for dynamic form creation.
  • addFormElementBeforeMarker()
    Adds a form element before a marker tag to the current form. This method can be used for dynamic form creation.
  • addFormElementAfterMarker()
    Adds a form element after a marker tag to the current form. This method can be used for dynamic form creation.
  • setPlaceHolder()
    Fills a place holder defined within the form. Please refer to Standard taglibs for more details.
  • setAction()
    Sets the "action" attribute do define the target to POST or GET against.
  • getFormElementByName()
    Returns a reference an any form object defined by a name.
  • getFormElementByID()
    Returns a reference an any form object defined by an id.
  • getFormElementByObjectID()
    Returns a reference an any form object defined by an internal object id.
  • getFormElementsByTagName()
    Returns a list of form element references, that correspond to the given tag name (e.g. form:text).
  • transformForm()
    Creates the HTML output of a form and returns it.
  • transformOnPlace()
    Indicates, that the form will be displayed where it was defined within the template file. Though it is not necessary to transform the form object with transformForm() and assign the content to a place holder.
To use the tag it must be announced using the
APF-Template
<core:addtaglib namespace="tools::form::taglib" prefix="html" class="form" />
directive before using it. After that a login form may be defined like this:
APF-Template
<html:form name="AdminLogin" method="post" action=""> <form:placeholder name="LogInError" /> Username: <form:text name="Username" class="input_feld" style="width: 200px; margin-left: 20px;" validate="true" button="AdminLogin" /> <br /> Password: <form:password name="Password" class="input_feld" style="width: 200px; margin-left: 16px;" validate="true" button="AdminLogin" /> <br /> <br /> <form:button name="AdminLogin" value="Login" class="input_feld" style="margin-left: 227px;"/> </html:form>
In detail: the <html:form /> XML tag possesses the attribute name to be able to get reference on the form and the attribute method to define the send mode. action defines the target to send the form to. This attribute most not be defined due to the fact, that the taglib behind the form tag adds the action automatically if the attribute is not present in the template file.

Within forms many form elements can bedefined: place holders to display hints or legends, text or password fields or buttons. Please refer to Standard taglibs to find a detailed description of the available tag libs. To use the previously defined form the following code can be used:
PHP-Code
$Form__AdminLogin = &$this->getForm('AdminLogin');
The variable $Form__AdminLogin now contains a reference on the form object. Further the place holder's content of the previously defined form can be filled by
PHP-Code
$Form__AdminLogin->setPlaceHolder('...','Login failed!');
The form object internally stores the current status of the form. To gather the information whether a form was sent or filled correctly concerning the defined validation methods the subsequent lines of code help to achieve this:
PHP-Code
if($Form__AdminLogin->get('isValid') && $Form__AdminLogin->get('isSent')){ // Do something that should be done if the form is sent and valid ... }
In order to display a form you have two possibilities: assigning the content to any place holder defined within the template file of make use of the transformOnPlace() function:
PHP-Code
public function transformContent(){ ... // Transform and output form by assigning the content to any placeholder ... $this->setPlaceHolder('...',$Form__AdminLogin->transformForm()); // ... display the form in place $Form__AdminLogin->tranformOnPlace(); ... }

2. Validation

As mentioned above validation of form elements can be configured out-of-the-box. For this purpose the attributes
  • validate
  • validator
  • button
must be added to a form element. For details please refer to the XML tag definition under Standard taglibs, chapter 2.3. In order to validate the fields of the above defined form the text field must be adjusted as performed afterwards:
APF-Template
<form:text name="Username" validate="true" button="AdminLogin" />
Please note that for correct validation the name of the button must be present. If the attribute button is not set the taglib implementation raises an error. In order to format a form element with CSS attributes, the attributes "style" or "class" can be used as desired.
APF-Template
<form:text name="Username" class="eingabe_feld" style="width: 200px; margin-left: 20px;" validate="true" button="AdminLogin" />
If the attribute "validator" is not set the standard validator (validateText) is used instead. This method checks, whether the value of the field is at least 3 signs long.

If there is the need to display a user note in addition to the red border of the input elements, you can place a <form:genericval /> tag before or after the desired form control. This tag displays a message defined in the body of the tag in case the input field could not be validated sucessfully.


3. Manipulation of form elements

Die Implementierung der Formular-TagLibs des Frameworks bringt einige Möglichkeiten zur Manipulation von Formularelementen oder deren Werte mit. Die folgenden Kapitel zeigen häufig auftretende Anwendungsbeispiele.


3.1. Prefilling of forms

In order to prefill forms (e.g. in edit dialoges) the methods getFormElementByID(), getFormElementByID() or getFormElementByObjectID() can be used to get a reference on the desired form element. Subsequently, the standard methods get() and getAttribute() and set() and setAttribute() respectivly are avaliable for data manipulation of an form element.

The following box defines an example form, that will be filled by the PHP code printed below:
APF-Template
<core:addtaglib namespace="tools::form::taglib" prefix="html" class="form" /> <html:form name="UserEdit" method="post"> <strong>FirstName</strong>: <form:text name="FirstName" validate="true" button="Edit" /> <br /> <strong>LastName</strong>: <form:text name="LastName" validate="true" button="Edit" /> <br /> <br /> <form:button name="Edit" value="Save" /> <form:hidden name="userid" /> </html:form>
PHP-Code
// get the form object $Form__Edit = &$this->getForm('UserEdit'); // get the hidden field object and fill the value $UserID = &$Form__Edit->getFormElementByName('userid'); $UserID->setAttribute('value','...'); // get the FirstName field and fill the value $FirstName = &$Form__Edit->getFormElementByName('FirstName'); $FirstName->setAttribute('value','...'); // get the LastName field and fill the value $LastName = &$Form__Edit->getFormElementByName('LastName'); $LastName->setAttribute('value','...');

3.2. Prefilling of select fields

Dealing with select or multiselect fields is a little bit different to "normal" form elements. But the framework provides common methods to fill these types of fields as well. The following form contains two select fields in addition to the four "normal" form elements:
APF-Template
<core:addtaglib namespace="tools::form::taglib" prefix="html" class="form" /> <html:form name="UserCreate" method="post"> <strong>Salutation</strong>: <form:select name="Salutation" /> <br /> <strong>FirstName</strong>: <form:text name="FirstName" validate="true" button="Edit" /> <br /> <strong>LastName</strong>: <form:text name="LastName" validate="true" button="Edit" /> <br /> <br /> <strong>Salutation</strong>: <br /> <form:multiselect name="Group[]" validate="true" button="Edit" /> <br /> <br /> <form:button name="Edit" value="Save" /> <form:hidden name="userid" /> </html:form>
As the tag definition of the Groups[] fiels shows, the name of a multiselect field must contain brackets. If the template developer forgets to put them in, a error message will be displayed.

In order to fill the select fields, the following PHP code can be used: Der folgende PHP-Code befüllt das Formular:
PHP-Code
// get the form object $Form__Create = &$this->getForm('UserCreate'); ... // get the Salutation field and add some options $Salutation = &$Form__Create->getFormElementByName('Salutation'); for($i = 0; $i < count($Salutations); $i++){ $Salutation->addOption($Salutations[$i]['Value'],$Salutations[$i]['DisplayName']); } // get the Groups[] field and add some options $Group = &$Form__Create->getFormElementByName('Groups[]'); for($i = 0; $i < count($Groups); $i++){ $Group->addOption($Groups[$i]['Value'],$Groups[$i]['DisplayName']); } ...
Note: If several options should be preselected using multi select fields, the setOption2Selected() method could be used. The following code depicts how to prefill a permission list and afterwards preselect the desired options. This example is taken from the usermanagement module delivered with the APF release.
PHP-Code
// reference the form $form = &$this->getForm('PermissionSetEdit'); // load permissions and fill the select field $allPermissions = $uM->loadPermissionList(); $permField = &$form->getFormElementByName('Permission[]'); for($i = 0; $i < count($allPermissions); $i++){ $permField->addOption($allPermissions[$i]->getProperty('DisplayName'),$allPermissions[$i]->getProperty('PermissionID')); } // preselect the options $selectedPermissions = $uM->loadPermissionsOfPermissionSet($permSet); for($i = 0; $i < count($selectedPermissions); $i++){ $permField->setOption2Selected($selectedPermissions[$i]->getProperty('PermissionID')); }

3.3. Readout form element values

Readout of form elements is similar to the filling of form elements. In both situations, the getFormElementByName() method can be used to obtain a reference on any form element. Please note, that select and multiselect fields are here also treated a little bit different. The next few lines describe, how to gather values of form elements:
PHP-Code
// get the form object $Form__Edit = &$this->getForm('UserEdit'); // get the value of the hidden field $UserID = &$Form__Edit->getFormElementByName('userid'); echo $UserID->getAttribute('value'); // read the content of the FirstName field $FirstName = &$Form__Edit->getFormElementByName('FirstName'); echo $FirstName->getAttribute('value'); // read the content of the LastName field $LastName = &$Form__Edit->getFormElementByName('LastName'); echo $LastName->getAttribute('value');
To read the content of select or multiselect fields the getSelectedOption() and getSelectedOptions() function can be used:
PHP-Code
// get the form object $Form__Create = &$this->getForm('UserCreate'); // prefill the Salutation field $Salutation = &$Form__Create->getFormElementByName('Salutation'); for($i = 0; $i < count($Salutations); $i++){ $Salutation->addOption($Salutations[$i]['Value'],$Salutations[$i]['DisplayName']); } // get the selected option of the Salutation field and print it to screen $Option = &$Salutation->getSelectedOption(); echo $Option->getAttribute('value').', '.$Option->getContent(); // prefill the Group field $Group = &$Form__Create->getFormElementByName('Groups[]'); for($i = 0; $i < count($Groups); $i++){ $Group->addOption($Groups[$i]['Value'],$Groups[$i]['DisplayName']); } // get the selected options of the Groups[] field and print them to screen $SelectedGroups = &$Group->getSelectedOptions(); for($i = 0; $i < count($SelectedGroups); $i++){ echo $SelectedGroups[$i]->getAttribute('value').', '.$SelectedGroups[$i]->getContent(); }


4. Dynamic Forms

In some cases it is necessary to generate forms dynamically. For this reason, the form taglib (html_taglib_form) features the methods
  • addFormElement()
  • addFormContent()
and as of release 1.7
  • addFormContentBeforeMarker()
  • addFormContentAfterMarker()
  • addFormElementBeforeMarker()
  • addFormElementAfterMarker()
The first two functions can be used to add content (i.e. plain text or html) or form elements at the end of the form. The latter ones are intended to add content or form at certain positions. For this reason, the <form:marker /> tag was introduced. The tag itself does not generate any output, but can be used for positioning purposes along with the "addForm*[Before|After]Marker()" methods.

The following chapters describe, how a dynamic form can be generated displaying form coordinate fields (triangle, square, ...). Depending on the type, the corresponding fields are displayed. If the type is set to "square", four fields are displayed ...

APF - dynamische Form generation; selection of the 'square' type

... in case of "triangle" three fields are presented:

APF - dynamische Form generation; selection of the 'triangle' type


4.1. Form definition

As already mentioned, the dynamic definition can be done in two flavours. While using addFormElement() and/or addFormContent(), no marker is needed. Instead, the following example uses marker, because the form already contains structural elements (e.g. table).

The following code box shows the form definition needed to display the form denoted above. To keep things simple, no CSS was added. Taking a closer look at the definition, you can see, that the form consists of a static select field, that defines the types available and a marker tag for positioning. Further, a document controller is specified, to add the desired form elements in front of the marker:
APF-Template
<@controller namespace="..." [file="..."] class="select_controller" @> <core:addtaglib namespace="tools::form::taglib" prefix="html" class="form" /> <html:form name="type" method="post"> <table> <tr> <td> Please choose the desired form type: <form:select name="type"> <select:option value="triangle">triangle</select:option> <select:option value="square">square</select:option> </form:select> </td> <td> <form:button name="submit" value="send" /> </td> </tr> <tr> <td> <form:marker name="fields" /> </td> </tr> </table> </html:form>

4.2. Controller

The document controller is responsible for generating the form field, that depends on the type of the geometrical shape. For this reason, the constructor contains a definition of the form fields that should be displayed for a concrete type. Afterwards, the typ is read from the select field and the form is enhanced with additional content and fields. The following code box presents the implementation of the document controller needed for this functionality:
PHP-Code
class select_controller extends base_controller { // specify form element container var $__FormElements = array(); function select_controller(){ // define form elements for the triangle $this->__FormElements['triangle'][] = array('label' => 'coord 1','name' => 'coordone'); $this->__FormElements['triangle'][] = array('label' => 'coord 2','name' => 'coordtwo'); $this->__FormElements['triangle'][] = array('label' => 'coord 3','name' => 'coordthree'); // define form elements for the square $this->__FormElements['square'][] = array('label' => 'coord 1','name' => 'coordone'); $this->__FormElements['square'][] = array('label' => 'coord 2','name' => 'coordtwo'); $this->__FormElements['square'][] = array('label' => 'coord 3','name' => 'coordthree'); $this->__FormElements['square'][] = array('label' => 'coord 4','name' => 'coordfour'); } function transformContent(){ // get form reference $Form = &$this->getForm('type'); // get current decision $Select = &$Form->getFormElementByName('type'); $Option = &$Select->getSelectedOption(); if($Option === null){ $CurrentType = 'triangle'; } else{ $CurrentType = $Option->getAttribute('value'); } // add form elements for($i = 0; $i < count($this->__FormElements[$CurrentType]); $i++){ // add label $Form->addFormContentBeforeMarker('fields',$this->__FormElements[$CurrentType][$i]['label'].': '); // add text field (name attribute is present to enable validation and presetting!) $CurrentElementID = $Form->addFormElementBeforeMarker( 'fields', 'form:text', array('name' => $this->__FormElements[$CurrentType][$i]['name']) ); // configure further form element attributes $CurrentElement = &$Form->getFormElementByObjectID($CurrentElementID); $CurrentElement->setAttribute('style','width: 200px;'); // add a line break $Form->addFormContentBeforeMarker('fields','<br />'); } // display form $Form->transformOnPlace(); } }

4.3. Notes

A APF form element does need information about the name of itself already at creation time. If the element doesn't know it's own name, presetting and validation cannot be enabled. In order to use presetting and validation in combination with dynamic form elements, the addFormElement(), addFormElementBeforeMarker() and addFormElementBeforeMarker() functions possess a third parameter. This parameter expects an associative list of tag attributes, that are applied to the form object on creation time. Creating dynamic form elements, it is thus recommended to at least apply the name of the tag to the third argument:
APF-Template
array( 'name' => 'currentname' )
Please note, that the tag attributes are also interesting for addressing the form objects after appending them to the form via the getFormElementByName() or getFormElementByID() methods.


5. Usage of form filters

Since the 1.9 branch, the form elements support filtering. The form filters are based on the APF filter from the core namespace. Details on the design and the usage of filters can be read about in the filter chapter.

The form filters are aimed to enhance the generic input filter (see configuration of filters) to only accept dedicated user input within user input fields. A typical application sample is the filtering of an email field, that only allows characters, that match the regular expression "[a-z0-9-_@.]".


5.1. Built-in filters

To ease working with user input in forms, a set of default filters is included in the release. The following filter tasks are presented by the filter class FormFilter from the tools::form::filter namespace (filter instructions):
  • string2Lower: Changes all capital letters to lower letters.
  • string2Upper: Changes all lower letters to capital letters.
  • stripTags: Trips HTML or script tags.
  • noSpecialCharacters: Filters special characters.
  • onlyNumbers: Only supports digits.
  • onlyInteger: Only supports integer values.
  • onlyLetters: Only supports letters.
  • onlyHTMLEntities: Encodes all HTML signs.

5.2. Usage

The application of filters is similar to validators. If the attribute filter is present, the filter described by the value is applied to the content of the form element. By default, the built-in filter is used as described in chapter 5.1.

The code box below shows you how to apply a form filter:
APF-Template
<html:form name="get_phone_number"> Your phone number: <form:text name="phone" filter="onlyNumbers" /> <br /> <form:button name="send" value="send" /> </html:form>
On parse time of the form, the content of the phone field is filtered with the onlyNumbers filter instruction. If you retrieve the content of the text field, you can be sure, that it contains no not allowed characters. Due to the fact, that filtering is done before validation, the validator is not able to give positiv response due to wrong user input.

Important:
  • Please note, that filters are only available for text input fields at the moment!
  • To apply more that one filter, please have a look at chapter 5.4. Filter chaining.

5.3. Enhancement

If the built-in filters do not satisfy your requirements, the filterclass attribute can be used to specify another filter. The definition (=value) must have the following look:
APF-Template
filterclass="path::to::my::filter::class|MyFilterClassName"
The first part corresponds to the namespace of the filter, the second part ist the name of the class or the file, respectivly. The filter attribute does also contain the filter instruction.

As described in chapter design and function of filters, each filter class must inherit (directly or via other subclasses) from the AbstractFilter definition and must implement the filter() function. The next code box points out, how a filter replacing all occurrences from "cm^2" to "cm²" must be implemented:
PHP-Code
class DefinitionFilter extends AbstractFormFilter { function filter($input){ return str_replace('cm^2','cm²',$input); } }
In case of "normal" filters (input and output filter) your custom filter must derive from the AbstractFilter class. To ease implementation of separate form filters, a new base class is introduced to handle the filter instructions, that are applied to the filter using the form field attribute filter. The value of this attribute is injeced into the internal variable $this->__Instruction, that can be used executing the filter() method.

As you can take from the example, the filter instruction must not be used within simple application cases. In this case, you have to ensure, that the filter attribute contains a non-empty (dummy) value.

In order to make a filter reusable, it is well to group similar filter instructions into one filter. The following example demonstrates a filter, that filters body quantities:
PHP-Code
class MeasureFilter extends AbstractFormFilter { function filter($input){ switch($this->__Instruction){ case 'weight': $output = preg_replace('/[^0-9,.]/i','',$input); case 'size': $output = preg_replace('/[^0-9]/i','',$input); default: $output = $input; } return $output; } }
In order to apply the filter, the form must be adapted as follows:
APF-Template
<html:form name="test" method="post"> Name: <form:text name="name" filter="noSpecialCharacters" /> <br /> Weight: <form:text name="weight" filterclass="my::special::filter|MeasureFilter" filter="weight" /> kg <br /> Body size: <form:area name="bodysize" filterclass="my::special::filter|MeasureFilter" filter="size" /> cm <br /> </html:form>

5.4. Filter chaining

Filter chaining can be done by an extra filter class. In order to apply more than one filter, the MultiplexFormFilter class (also included in the release) can be used:
PHP-Code
class MultiplexFormFilter extends FormFilter { function filter($input){ $instructionSet = explode('|',$this->__Instruction); $output = $input; foreach($instructionSet as $filterInstruction){ $output = $this->{'__'.trim($filterInstruction)}($output); } return $output; } }
In order to apply the a filter chain, the form must be adapted as follows:
APF-Template
<html:form name="get_phone_number"> Your phone number: <form:text name="specialfield" filterclass="tools::form::filter|MultiplexFormFilter" filter="noSpecialCharacters|string2Upper" /> <br /> <form:button name="send" value="send" /> </html:form>

Comments

Do you want to add a comment to the article above, or do you want to post additional hints? So please click here. Comments already posted can be found below.
« 1   »
Entries/Page: | 5 | 10 | 15 | 20 |
1
uk replica watches 13.05.2013, 09:44:54
Hello, i actually quite the story very much, looking forward to your. uk replica watches