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.
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();
...
}
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.
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.
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','...');
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'));
}
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();
}
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 ...
... in case of "triangle" three fields are presented:
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>
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();
}
}
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.
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-_@.]".
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.
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.
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>
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>
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
uk replica watches
13.05.2013, 09:44:54
Hello, i actually quite the story very much, looking forward to your.
uk replica watches