Table of Contents
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 forms is pretty straightforward. Everything is done using the Atomik_Form
class.
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.
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.
You must specify a name for each fields as the first argument of the constructor.
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');
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.
There are also methods to remove, reset and get all fields.
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();
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.
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'
));
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>
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');
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
}
}
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();
Atomik_Form_Class::create().
This method takes as first argument a class name and optionally as second a prefix for doc comment tags name.
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.
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.