form->create($post) ?> // Echoes a
tag and binds the helper to $post * form->text('title') ?> // Echoes an element, pre-filled with $post's title * form->submit('Update') ?> // Echoes a submit button with the title 'Update' * form->end() ?> // Echoes a
tag & unbinds the form * ``` */ class Form extends \lithium\template\Helper { /** * String templates used by this helper. * * @var array */ protected $_strings = [ 'button' => '{:title}', 'checkbox' => '', 'checkbox-multi' => '', 'checkbox-multi-group' => '{:raw}', 'error' => '{:content}', 'errors' => '{:raw}', 'input' => '', 'file' => '', 'form' => '
{:append}', 'form-end' => '
', 'hidden' => '', 'field' => '{:label}{:input}{:datalist}{:error}', 'field-checkbox' => '{:input}{:label}{:error}', 'field-radio' => '{:input}{:label}{:error}', 'label' => '', 'legend' => '{:content}', 'option-group' => '{:raw}', 'password' => '', 'radio' => '', 'select' => '', 'select-empty' => '', 'select-multi' => '', 'select-option' => '', 'submit' => '', 'submit-image' => '', 'text' => '', 'textarea' => '', 'fieldset' => '{:content}{:raw}', 'datalist' => '{:raw}', 'datalist-option' => '' ]; /** * Maps method names to template string names, allowing the default template strings to be set * permanently on a per-method basis. * * For example, if all text input fields should be wrapped in `` tags, you can configure * the template string mappings per the following: * * ``` * $this->form->config(['templates' => [ * 'text' => '' * ]]); * ``` * * Alternatively, you can re-map one type as another. This is useful if, for example, you * include your own helper with custom form template strings which do not match the default * template string names. * * ``` * // Renders all password fields as text fields * $this->form->config(['templates' => ['password' => 'text']]); * ``` * * @var array * @see lithium\template\helper\Form::config() */ protected $_templateMap = [ 'create' => 'form', 'end' => 'form-end' ]; /** * The data object or list of data objects to which the current form is bound. In order to * be a custom data object, a class must implement the following methods: * * - schema(): Returns an array defining the objects fields and their data types. * - data(): Returns an associative array of the data that this object represents. * - errors(): Returns an associate array of validation errors for the current data set, where * the keys match keys from `schema()`, and the values are either strings (in cases * where a field only has one error) or an array (in case of multiple errors), * * For an example of how to implement these methods, see the `lithium\data\Entity` object. * * @see lithium\data\Entity * @see lithium\data\Collection * @see lithium\template\helper\Form::create() * @var mixed A single data object, a `Collection` of multiple data objects, or an array of data * objects/`Collection`s. */ protected $_binding = null; /** * Array of options used to create the form to which `$_binding` is currently bound. * Overwritten when `end()` is called. * * @var array */ protected $_bindingOptions = []; /** * Constructor. * * @param array $config Configuration options. * @return void */ public function __construct(array $config = []) { $defaults = [ 'base' => [], 'text' => [], 'textarea' => [], 'select' => ['multiple' => false], 'attributes' => [ 'id' => function($method, $name, $options) { if (in_array($method, ['create', 'end', 'label', 'error'])) { return; } if (!$name || ($method === 'hidden' && $name === '_method')) { return; } $info = $this->binding($name); $model = $info->class; $id = Inflector::camelize(Inflector::slug($info->name)); return $model ? basename(str_replace('\\', '/', $model)) . $id : $id; }, 'name' => function($method, $name, $options) { if (!strpos($name, '.')) { return $name; } $name = explode('.', $name); $first = array_shift($name); return $first . '[' . join('][', $name) . ']'; } ], 'binding' => function($object, $name = null) { $result = compact('name') + [ 'data' => null, 'errors' => null, 'class' => null ]; if (is_object($object)) { $result = compact('name') + [ 'data' => $object->data($name), 'errors' => $object->errors($name), 'class' => $object->model() ]; } return (object) $result; } ]; parent::__construct(Set::merge($defaults, $config)); } /** * Object initializer. Adds a content handler for the `wrap` key in the `field()` method, which * converts an array of properties to an attribute string. * * @return void */ protected function _init() { parent::_init(); if ($this->_context) { $this->_context->handlers(['wrap' => 'attributes']); } } /** * Allows you to configure a default set of options which are included on a per-method basis, * and configure method template overrides. * * To force all `