Custom input elements

You can create your own custom elements to use in your apps. Although the library's basic elements can display almost any form, there a few reasons to create custom elements.

To be DRY (Don't Repeat Yourself)

The Element class has a getDefaultSpecs() method that you can use to provide defaults. Here's a date picker element which has some default specs that you will not be forced to write everytime you need to add a datepicker to a form.

namespace MyApp\Input\Element;

class DatePicker extends \Sirius\Input\Element\Input\Text
{
    const FORMAT = 'format'; // a custom specification

    function getDefaultSpecs()
    {
        // the specs defined here are merged with the one you
        // provide to the form's add() method
        return array(
            Specs::ATTRIBUTES => array(
                'class' => 'datepicker'
            ),
            self::FORMAT => 'd/m/Y'
        );
    }

    protected function prepareFormFiltration(\Sirius\Forms\Form $form)
    {
        parent::prepareFormFiltration($form);
        $filtrator = $form->getFiltrator();
        // add a custom filter to the form's filtrator to normalize the incoming value
        $filtrator->add($this->getName(), array($this, 'normalizeDate'));
    }

    function normalizeDate($date) {
        // convert a date provided as 'd/m/Y' to 'Y-m-d'
    }
}

The same reason applies if you want to create custom composite elements (fieldsets or collections)

namespace MyApp\Input\Element;

class AddressFieldset extends \Sirius\Input\Element\Fieldset
{
    function init() {
        $this->add('street', $streetFieldSpecs);
        $this->add('city', $cityFieldSpecs);
    }

}

and add it to the form something like so:

// somewhere in your app bootstrap
$formElementFactory->registerElementType('address_fielset', 'MyApp\Forms\Element\AddressFieldset');

// in your app
$form->add('address, array(
    'type' => 'address_fielset'
));

Special data processing

Let's say you have a localized date input called start_date that is localized and your renderer actually renders the field as name="__localized_start_date" which is converted by javascript into a system-formatted date and populated into a hidden field with name="start_date". If the client doesn't have javascript support that will pose a problem (you will not have the start_date populated via JS). So you need to make sure that the transformation is done server-side as well

namespace MyApp\Input\Element;

class LocalizedDate extends \Sirius\Input\Element\Input\Text {

    function convertLocalizedDate($data) {
        // $data here will be the form's data
        $data[$this->getName()] = strptime($data['__localized_' . $this-getName()], 'm/d/y');
        // you have to return the data (see documentation for Sirius\Filtration)
        return $data;
    }

    protected function prepareFormFiltration($form) {
        parent::prepareFormFiltration($form);
        // this adds a callback as a filtration rule
        // to be applied to the entire form data (not an individual item)
        $form->getFiltration()->add('/', array($this, 'convertLocalizedDate'));
    }
}