Chapter 4. Form

Table of Contents

Creating a form
Form fields
Using fields
Adding fields to a form
Field's accessors
Validating field's value
Rendering forms
Templates
Handling form data
Creating forms using classes
Sub forms
Creating custom fields

Note

This component is still in development. The API can change in the futur.

The Atomik_Form component provide facilities to create and handle forms.

The forms is made of fields. Each fields render itself and handle its data. The whole form is rendered using two templates: one for fields and one for the form tag. This way you can only render fields if needed.

Creating a form

Creating forms is pretty straightforward. Everything is done using the Atomik_Form class.

Example 4.1. Creating a form

				
$form = new Atomik_Form();
			

Forms can have a name. Naming your forms is not very important for most use but can become very useful when dealing with sub forms...

Note that if a form has a name, all its data will be stored in an array named like the form.

You can specify attributes of the form tag using setAttributes() or setAttribute(). There are also some shortcut accessors for common attributes like the id, method, action and enctype.

Form fields

Fields are defined as classes which must implement Atomik_Form_Field_Interface. A bunch of fields are built-in under the Atomik_Form_Field_ namespace.

Using fields

You must specify a name for each fields as the first argument of the constructor.

Example 4.2. Instanciating a field

					
$field = new Atomik_Form_Field_Input('name');
				

You can create fields using Atomik_Form_Field_Factory::factory(). This method takes as first argument a built-in field name or a full class name. The built-in field name is the part after the last underscore in the class name (eg. Input can be used for Atomik_Form_Field_Input). The second and third arguments are the same as the first and second arguments of fields constructor.

Example 4.3. Instanciating a field using the factory

					
$field = Atomik_Form_Field_Factory::factory('Input', 'name');
				

Adding fields to a form

You can use the addField() method of the form object to add some fields. It takes as first argument a field object and optionally the label string as second argument.

Example 4.4. Adding a field to a form

					
$field = Atomik_Form_Field_Factory::factory('Input', 'name');
$form->addField($field, 'Name');
				

You can also set the label later using the setLabel() method of the form object.

Example 4.5. Setting a field's label

					
$form->setLabel($field, 'Name');
				

There are also methods to remove, reset and get all fields.

Field's accessors

First of all you can set or get the name of the field using setName() and getName().

The value of the field can be defined using setValue() and retrieve using getValue(). Beware that the value passed to the setter can be different than the one retrieved.

Fields subclassing Atomik_Form_Field_Abstract (should be most of them, all built-in ones at least) also provide some methods to handle options. They all come from Atomik_Options as the abstract class inherit from that one.

Options can be specified as an array in the second argument of the constructor.

Each type of field can have custom options. However, they all share common ones to define validation logic. Validation is covered in the next section.

Example 4.6. Field's accessors

					
$field = new Atomik_Form_Field_Input('name');

$field->setName('username');
echo $field->getName();

$field->setValue('peter');
echo $field->getValue();

$field->setOption('name', 'value');
echo $field->getOptions();
				

Validating field's value

Note

This is only available for fields sublclassing Atomik_Form_Field_Abstract.

Validating fields is one of the most (if not the most) important part of the whole form process! PHP's filter extension is used for that purpose.

Some fields are said to be required, ie. they must be defined. To specify a field as such, simply set the required option to true.

The validate option allow you to use a regexp or a PHP's filter name which will be used to validate the field. Regexp must be specified between slashes. Modifiers can also be used.

Note

See http://php.net/manual/filter.constants.php for a complete list of filters.

Example 4.7. Specifying fields validation options

					
$field = new Atomik_Form_Field_Input('name', array(
	'required' => 'true',
	'validate' => 'validate_email' // ie. FILTER_VALIDATE_EMAIL
));
				

If you prefer using a custom function to handle validation you can use the validate_with options which takes a callback string as value. The callback must take the field's value as argument and return either true or false.

Example 4.8. Using a custom validator

					
function my_validator($value) {
	return !empty($value);
}

$field = new Atomik_Form_Field_Input('name', array(
	'validate-with' => 'my_validator'
));
				

Rendering forms

Atomik_Form allows you to render the whole form (fields and the form tag) or only the fields. The last way can be achieved by calling renderFields().

To render the whole form, you'll need to call renderForm() or simply echoing the object.

Example 4.9. Rendering form fields

				
<form action="handler.php" method="post">
	<?= $form->renderFields() ?>
	<input type="submit" value="Send" />
</form>
			

Example 4.10. Rendering the whole form

				
<?= $form ?>
			

Templates

Forms use templates to render themselves. There are two kind of templates: for the fields and for the form. The first one is used to wrap the field in a more prettier form (commonly to display the associated label). The second one is used to render the form tag and form buttons.

Using these two kind of templates allows you to either render the whole form or only the fields. When using the second approach, you can customize the form when including it in your view.

You can set the form template using setFormTemplate() and the field template using setFieldTemplate(). There are also two static methods to define the default templates for all forms: Atomik_Form::setDefaultFormTemplate() and Atomik_Form::setDefaultFieldTemplate(). Each of these methods takes a filename as argument.

The component comes with three templates: one using p, another using ul and one using dl. They're available under Atomik/Form/Template. The default template is Dl.

Example 4.11. Setting a form template

					
$form1->setFormTemplate('Atomik/Form/Template/P.php');
$form1->setFieldTemplate('Atomik/Form/Template/Field/P.php');

$form2->setFormTemplate('Atomik/Form/Template/Li.php');
$form2->setFieldTemplate('Atomik/Form/Template/Field/Li.php');

$form3->setFormTemplate('Atomik/Form/Template/Dl.php');
$form3->setFieldTemplate('Atomik/Form/Template/Field/Dtdd.php');
				

Handling form data

You can check if a form has data (ie. the form has been submitted) using hasData(). Once you know there are data, you should validate them. This is done using isValid(). If the validation fails, you can retreive an array of error messages using getValidationMessages(). Finally, you can retreive the data using getData().

Example 4.12. Handling form data

				
if ($form->hasData()) {
	if (!$form->isValid()) {
		$messages = $form->getValidationMessages();
		// do something with $messages
	} else {
		$data = $form->getData();
		// do something with the data
	}
}
			

Creating forms using classes

It is pretty painful to define forms using all these objects and method calls. Atomik Form provides a nice way to do that using classes and doc comments.

To do so, create a class that extend Atomik_Form_Class. The class public properties will be used as form fields. You can specify field's options using doc comment tags. You can also specify form's attributes using the class doc comment.

Example 4.13. Defining a form using a class

				
/**
 * @action user/login
 * @method POST
 */
class MyForm extends Atomik_Form_Class
{
	/**
	 * @label Username
	 * @required
	 */
	public $username;
	
	/**
	 * @label Password
	 * @required
	 */
	public $password;
}
			

When there are some data available, you can access them through the public properties.

Example 4.14. Using a form class

				
$form = new MyForm();

if ($form->hasData() && $form->isValid()) {
	echo $form->username . ' ' . $form->password;
}

echo $form->renderForm();
			

Note

It is also possible to create forms using any classes with Atomik_Form_Class::create(). This method takes as first argument a class name and optionally as second a prefix for doc comment tags name.

Sub forms

It is sometimes needed to create multipage forms or to embed a form into another. Atomik_Form makes it easy to do such things as you can add a form to another like any field.

Note that to do that, it is greatly advice to name forms. Doing so avoids confusion between data of the different forms.

Example 4.15. Adding a form to another

				
$mainForm = new Atomik_Form();
$subForm1 = new Atomik_Form('sub1');
$subForm2 = new Atomik_Form('sub2');

$mainForm->addField($subForm1);
$mainForm->addField($subForm2);

echo $mainForm->renderForm();
			

You can then choose to render the main form (as shown in the example) or each forms independently. You can also validate them in the same way.

Creating custom fields

As said before, fields are defined as classes. To create a custom one, you must implement the Atomik_Form_Field_Interface. The easiest way is two subclass Atomik_Form_Field_Abstract which already implements nearly all methods from the interface. You'll only need to write the render() method.

You must use getFullname() to get the field's name.

Example 4.16. Creating a custom field

				
class MyField extends Atomik_Form_Field_Abstract
{
	public function render()
	{
		return sprintf('<input type="text" maxlength="10" name="%s" %s />',
			$this->getFullname(),
			$this->getOptionsAsAttributeString()
		);
	}
}
			

You could also override the setValue() and getValue() methods to handle the data in a specific way.