Blame | Last modification | View Log | RSS feed
<?php/*** CakePHP(tm) : Rapid Development Framework (http://cakephp.org)* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)** Licensed under The MIT License* For full copyright and license information, please see the LICENSE.txt* Redistributions of files must retain the above copyright notice.** @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)* @link http://cakephp.org CakePHP(tm) Project* @package Cake.View.Helper* @since CakePHP(tm) v 0.10.0.1076* @license http://www.opensource.org/licenses/mit-license.php MIT License*/App::uses('ClassRegistry', 'Utility');App::uses('AppHelper', 'View/Helper');App::uses('Hash', 'Utility');/*** Form helper library.** Automatic generation of HTML FORMs from given data.** @package Cake.View.Helper* @property HtmlHelper $Html* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html*/class FormHelper extends AppHelper {/*** Other helpers used by FormHelper** @var array*/public $helpers = array('Html');/*** Options used by DateTime fields** @var array*/protected $_options = array('day' => array(), 'minute' => array(), 'hour' => array(),'month' => array(), 'year' => array(), 'meridian' => array());/*** List of fields created, used with secure forms.** @var array*/public $fields = array();/*** Constant used internally to skip the securing process,* and neither add the field to the hash or to the unlocked fields.** @var string*/const SECURE_SKIP = 'skip';/*** Defines the type of form being created. Set by FormHelper::create().** @var string*/public $requestType = null;/*** The default model being used for the current form.** @var string*/public $defaultModel = null;/*** Persistent default options used by input(). Set by FormHelper::create().** @var array*/protected $_inputDefaults = array();/*** An array of field names that have been excluded from* the Token hash used by SecurityComponent's validatePost method** @see FormHelper::_secure()* @see SecurityComponent::validatePost()* @var array*/protected $_unlockedFields = array();/*** Holds the model references already loaded by this helper* product of trying to inspect them out of field names** @var array*/protected $_models = array();/*** Holds all the validation errors for models loaded and inspected* it can also be set manually to be able to display custom error messages* in the any of the input fields generated by this helper** @var array*/public $validationErrors = array();/*** Copies the validationErrors variable from the View object into this instance** @param View $View The View this helper is being attached to.* @param array $settings Configuration settings for the helper.*/public function __construct(View $View, $settings = array()) {parent::__construct($View, $settings);$this->validationErrors =& $View->validationErrors;}/*** Guess the location for a model based on its name and tries to create a new instance* or get an already created instance of the model** @param string $model* @return Model model instance*/protected function _getModel($model) {$object = null;if (!$model || $model === 'Model') {return $object;}if (array_key_exists($model, $this->_models)) {return $this->_models[$model];}if (ClassRegistry::isKeySet($model)) {$object = ClassRegistry::getObject($model);} elseif (isset($this->request->params['models'][$model])) {$plugin = $this->request->params['models'][$model]['plugin'];$plugin .= ($plugin) ? '.' : null;$object = ClassRegistry::init(array('class' => $plugin . $this->request->params['models'][$model]['className'],'alias' => $model));} elseif (ClassRegistry::isKeySet($this->defaultModel)) {$defaultObject = ClassRegistry::getObject($this->defaultModel);if ($defaultObject && in_array($model, array_keys($defaultObject->getAssociated()), true) && isset($defaultObject->{$model})) {$object = $defaultObject->{$model};}} else {$object = ClassRegistry::init($model, true);}$this->_models[$model] = $object;if (!$object) {return null;}$this->fieldset[$model] = array('fields' => null, 'key' => $object->primaryKey, 'validates' => null);return $object;}/*** Inspects the model properties to extract information from them.* Currently it can extract information from the the fields, the primary key and required fields** The $key parameter accepts the following list of values:** - key: Returns the name of the primary key for the model* - fields: Returns the model schema* - validates: returns the list of fields that are required* - errors: returns the list of validation errors** If the $field parameter is passed if will return the information for that sole field.** `$this->_introspectModel('Post', 'fields', 'title');` will return the schema information for title column** @param string $model name of the model to extract information from* @param string $key name of the special information key to obtain (key, fields, validates, errors)* @param string $field name of the model field to get information from* @return mixed information extracted for the special key and field in a model*/protected function _introspectModel($model, $key, $field = null) {$object = $this->_getModel($model);if (!$object) {return;}if ($key === 'key') {return $this->fieldset[$model]['key'] = $object->primaryKey;}if ($key === 'fields') {if (!isset($this->fieldset[$model]['fields'])) {$this->fieldset[$model]['fields'] = $object->schema();foreach ($object->hasAndBelongsToMany as $alias => $assocData) {$this->fieldset[$object->alias]['fields'][$alias] = array('type' => 'multiple');}}if ($field === null || $field === false) {return $this->fieldset[$model]['fields'];} elseif (isset($this->fieldset[$model]['fields'][$field])) {return $this->fieldset[$model]['fields'][$field];}return isset($object->hasAndBelongsToMany[$field]) ? array('type' => 'multiple') : null;}if ($key === 'errors' && !isset($this->validationErrors[$model])) {$this->validationErrors[$model] =& $object->validationErrors;return $this->validationErrors[$model];} elseif ($key === 'errors' && isset($this->validationErrors[$model])) {return $this->validationErrors[$model];}if ($key === 'validates' && !isset($this->fieldset[$model]['validates'])) {$validates = array();foreach ($object->validator() as $validateField => $validateProperties) {if ($this->_isRequiredField($validateProperties)) {$validates[$validateField] = true;}}$this->fieldset[$model]['validates'] = $validates;}if ($key === 'validates') {if (empty($field)) {return $this->fieldset[$model]['validates'];}return isset($this->fieldset[$model]['validates'][$field]) ?$this->fieldset[$model]['validates'] : null;}}/*** Returns if a field is required to be filled based on validation properties from the validating object.** @param CakeValidationSet $validationRules* @return boolean true if field is required to be filled, false otherwise*/protected function _isRequiredField($validationRules) {if (empty($validationRules) || count($validationRules) === 0) {return false;}$isUpdate = $this->requestType === 'put';foreach ($validationRules as $rule) {$rule->isUpdate($isUpdate);if ($rule->skip()) {continue;}return !$rule->allowEmpty;}return false;}/*** Returns false if given form field described by the current entity has no errors.* Otherwise it returns the validation message** @return mixed Either false when there are no errors, or an array of error* strings. An error string could be ''.* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::tagIsInvalid*/public function tagIsInvalid() {$entity = $this->entity();$model = array_shift($entity);// 0.Model.field. Fudge entity pathif (empty($model) || is_numeric($model)) {array_splice($entity, 1, 0, $model);$model = array_shift($entity);}$errors = array();if (!empty($entity) && isset($this->validationErrors[$model])) {$errors = $this->validationErrors[$model];}if (!empty($entity) && empty($errors)) {$errors = $this->_introspectModel($model, 'errors');}if (empty($errors)) {return false;}$errors = Hash::get($errors, implode('.', $entity));return $errors === null ? false : $errors;}/*** Returns an HTML FORM element.** ### Options:** - `type` Form method defaults to POST* - `action` The controller action the form submits to, (optional).* - `url` The URL the form submits to. Can be a string or a URL array. If you use 'url'* you should leave 'action' undefined.* - `default` Allows for the creation of Ajax forms. Set this to false to prevent the default event handler.* Will create an onsubmit attribute if it doesn't not exist. If it does, default action suppression* will be appended.* - `onsubmit` Used in conjunction with 'default' to create ajax forms.* - `inputDefaults` set the default $options for FormHelper::input(). Any options that would* be set when using FormHelper::input() can be set here. Options set with `inputDefaults`* can be overridden when calling input()* - `encoding` Set the accept-charset encoding for the form. Defaults to `Configure::read('App.encoding')`** @param mixed $model The model name for which the form is being defined. Should* include the plugin name for plugin models. e.g. `ContactManager.Contact`.* If an array is passed and $options argument is empty, the array will be used as options.* If `false` no model is used.* @param array $options An array of html attributes and options.* @return string An formatted opening FORM tag.* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#options-for-create*/public function create($model = null, $options = array()) {$created = $id = false;$append = '';if (is_array($model) && empty($options)) {$options = $model;$model = null;}if (empty($model) && $model !== false && !empty($this->request->params['models'])) {$model = key($this->request->params['models']);} elseif (empty($model) && empty($this->request->params['models'])) {$model = false;}$this->defaultModel = $model;$key = null;if ($model !== false) {list($plugin, $model) = pluginSplit($model, true);$key = $this->_introspectModel($plugin . $model, 'key');$this->setEntity($model, true);}if ($model !== false && $key) {$recordExists = (isset($this->request->data[$model]) &&!empty($this->request->data[$model][$key]) &&!is_array($this->request->data[$model][$key]));if ($recordExists) {$created = true;$id = $this->request->data[$model][$key];}}$options = array_merge(array('type' => ($created && empty($options['action'])) ? 'put' : 'post','action' => null,'url' => null,'default' => true,'encoding' => strtolower(Configure::read('App.encoding')),'inputDefaults' => array()),$options);$this->inputDefaults($options['inputDefaults']);unset($options['inputDefaults']);if (!isset($options['id'])) {$domId = isset($options['action']) ? $options['action'] : $this->request['action'];$options['id'] = $this->domId($domId . 'Form');}if ($options['action'] === null && $options['url'] === null) {$options['action'] = $this->request->here(false);} elseif (empty($options['url']) || is_array($options['url'])) {if (empty($options['url']['controller'])) {if (!empty($model)) {$options['url']['controller'] = Inflector::underscore(Inflector::pluralize($model));} elseif (!empty($this->request->params['controller'])) {$options['url']['controller'] = Inflector::underscore($this->request->params['controller']);}}if (empty($options['action'])) {$options['action'] = $this->request->params['action'];}$plugin = null;if ($this->plugin) {$plugin = Inflector::underscore($this->plugin);}$actionDefaults = array('plugin' => $plugin,'controller' => $this->_View->viewPath,'action' => $options['action'],);$options['action'] = array_merge($actionDefaults, (array)$options['url']);if (empty($options['action'][0]) && !empty($id)) {$options['action'][0] = $id;}} elseif (is_string($options['url'])) {$options['action'] = $options['url'];}unset($options['url']);switch (strtolower($options['type'])) {case 'get':$htmlAttributes['method'] = 'get';break;case 'file':$htmlAttributes['enctype'] = 'multipart/form-data';$options['type'] = ($created) ? 'put' : 'post';case 'post':case 'put':case 'delete':$append .= $this->hidden('_method', array('name' => '_method', 'value' => strtoupper($options['type']), 'id' => null,'secure' => self::SECURE_SKIP));default:$htmlAttributes['method'] = 'post';}$this->requestType = strtolower($options['type']);$action = $this->url($options['action']);unset($options['type'], $options['action']);if (!$options['default']) {if (!isset($options['onsubmit'])) {$options['onsubmit'] = '';}$htmlAttributes['onsubmit'] = $options['onsubmit'] . 'event.returnValue = false; return false;';}unset($options['default']);if (!empty($options['encoding'])) {$htmlAttributes['accept-charset'] = $options['encoding'];unset($options['encoding']);}$htmlAttributes = array_merge($options, $htmlAttributes);$this->fields = array();if ($this->requestType !== 'get') {$append .= $this->_csrfField();}if (!empty($append)) {$append = $this->Html->useTag('hiddenblock', $append);}if ($model !== false) {$this->setEntity($model, true);$this->_introspectModel($model, 'fields');}return $this->Html->useTag('form', $action, $htmlAttributes) . $append;}/*** Return a CSRF input if the _Token is present.* Used to secure forms in conjunction with SecurityComponent** @return string*/protected function _csrfField() {if (empty($this->request->params['_Token'])) {return '';}if (!empty($this->request['_Token']['unlockedFields'])) {foreach ((array)$this->request['_Token']['unlockedFields'] as $unlocked) {$this->_unlockedFields[] = $unlocked;}}return $this->hidden('_Token.key', array('value' => $this->request->params['_Token']['key'], 'id' => 'Token' . mt_rand(),'secure' => self::SECURE_SKIP));}/*** Closes an HTML form, cleans up values set by FormHelper::create(), and writes hidden* input fields where appropriate.** If $options is set a form submit button will be created. Options can be either a string or an array.** {{{* array usage:** array('label' => 'save'); value="save"* array('label' => 'save', 'name' => 'Whatever'); value="save" name="Whatever"* array('name' => 'Whatever'); value="Submit" name="Whatever"* array('label' => 'save', 'name' => 'Whatever', 'div' => 'good') <div class="good"> value="save" name="Whatever"* array('label' => 'save', 'name' => 'Whatever', 'div' => array('class' => 'good')); <div class="good"> value="save" name="Whatever"* }}}** @param string|array $options as a string will use $options as the value of button,* @return string a closing FORM tag optional submit button.* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#closing-the-form*/public function end($options = null) {$out = null;$submit = null;if ($options !== null) {$submitOptions = array();if (is_string($options)) {$submit = $options;} else {if (isset($options['label'])) {$submit = $options['label'];unset($options['label']);}$submitOptions = $options;}$out .= $this->submit($submit, $submitOptions);}if ($this->requestType !== 'get' &&isset($this->request['_Token']) &&!empty($this->request['_Token'])) {$out .= $this->secure($this->fields);$this->fields = array();}$this->setEntity(null);$out .= $this->Html->useTag('formend');$this->_View->modelScope = false;$this->requestType = null;return $out;}/*** Generates a hidden field with a security hash based on the fields used in the form.** @param array $fields The list of fields to use when generating the hash* @return string A hidden input field with a security hash* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::secure*/public function secure($fields = array()) {if (!isset($this->request['_Token']) || empty($this->request['_Token'])) {return;}$locked = array();$unlockedFields = $this->_unlockedFields;foreach ($fields as $key => $value) {if (!is_int($key)) {$locked[$key] = $value;unset($fields[$key]);}}sort($unlockedFields, SORT_STRING);sort($fields, SORT_STRING);ksort($locked, SORT_STRING);$fields += $locked;$locked = implode(array_keys($locked), '|');$unlocked = implode($unlockedFields, '|');$fields = Security::hash(serialize($fields) . $unlocked . Configure::read('Security.salt'), 'sha1');$out = $this->hidden('_Token.fields', array('value' => urlencode($fields . ':' . $locked),'id' => 'TokenFields' . mt_rand()));$out .= $this->hidden('_Token.unlocked', array('value' => urlencode($unlocked),'id' => 'TokenUnlocked' . mt_rand()));return $this->Html->useTag('hiddenblock', $out);}/*** Add to or get the list of fields that are currently unlocked.* Unlocked fields are not included in the field hash used by SecurityComponent* unlocking a field once its been added to the list of secured fields will remove* it from the list of fields.** @param string $name The dot separated name for the field.* @return mixed Either null, or the list of fields.* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::unlockField*/public function unlockField($name = null) {if ($name === null) {return $this->_unlockedFields;}if (!in_array($name, $this->_unlockedFields)) {$this->_unlockedFields[] = $name;}$index = array_search($name, $this->fields);if ($index !== false) {unset($this->fields[$index]);}unset($this->fields[$name]);}/*** Determine which fields of a form should be used for hash.* Populates $this->fields** @param boolean $lock Whether this field should be part of the validation* or excluded as part of the unlockedFields.* @param string $field Reference to field to be secured. Should be dot separated to indicate nesting.* @param mixed $value Field value, if value should not be tampered with.* @return mixed|null Not used yet*/protected function _secure($lock, $field = null, $value = null) {if (!$field) {$field = $this->entity();} elseif (is_string($field)) {$field = Hash::filter(explode('.', $field));}foreach ($this->_unlockedFields as $unlockField) {$unlockParts = explode('.', $unlockField);if (array_values(array_intersect($field, $unlockParts)) === $unlockParts) {return;}}$field = implode('.', $field);$field = preg_replace('/(\.\d+)+$/', '', $field);if ($lock) {if (!in_array($field, $this->fields)) {if ($value !== null) {return $this->fields[$field] = $value;}$this->fields[] = $field;}} else {$this->unlockField($field);}}/*** Returns true if there is an error for the given field, otherwise false** @param string $field This should be "Modelname.fieldname"* @return boolean If there are errors this method returns true, else false.* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::isFieldError*/public function isFieldError($field) {$this->setEntity($field);return (bool)$this->tagIsInvalid();}/*** Returns a formatted error message for given FORM field, NULL if no errors.** ### Options:** - `escape` boolean - Whether or not to html escape the contents of the error.* - `wrap` mixed - Whether or not the error message should be wrapped in a div. If a* string, will be used as the HTML tag to use.* - `class` string - The class name for the error message** @param string $field A field name, like "Modelname.fieldname"* @param string|array $text Error message as string or array of messages.* If array contains `attributes` key it will be used as options for error container* @param array $options Rendering options for <div /> wrapper tag* @return string If there are errors this method returns an error message, otherwise null.* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::error*/public function error($field, $text = null, $options = array()) {$defaults = array('wrap' => true, 'class' => 'error-message', 'escape' => true);$options = array_merge($defaults, $options);$this->setEntity($field);$error = $this->tagIsInvalid();if ($error === false) {return null;}if (is_array($text)) {if (isset($text['attributes']) && is_array($text['attributes'])) {$options = array_merge($options, $text['attributes']);unset($text['attributes']);}$tmp = array();foreach ($error as &$e) {if (isset($text[$e])) {$tmp[] = $text[$e];} else {$tmp[] = $e;}}$text = $tmp;}if ($text !== null) {$error = $text;}if (is_array($error)) {foreach ($error as &$e) {if (is_numeric($e)) {$e = __d('cake', 'Error in field %s', Inflector::humanize($this->field()));}}}if ($options['escape']) {$error = h($error);unset($options['escape']);}if (is_array($error)) {if (count($error) > 1) {$listParams = array();if (isset($options['listOptions'])) {if (is_string($options['listOptions'])) {$listParams[] = $options['listOptions'];} else {if (isset($options['listOptions']['itemOptions'])) {$listParams[] = $options['listOptions']['itemOptions'];unset($options['listOptions']['itemOptions']);} else {$listParams[] = array();}if (isset($options['listOptions']['tag'])) {$listParams[] = $options['listOptions']['tag'];unset($options['listOptions']['tag']);}array_unshift($listParams, $options['listOptions']);}unset($options['listOptions']);}array_unshift($listParams, $error);$error = call_user_func_array(array($this->Html, 'nestedList'), $listParams);} else {$error = array_pop($error);}}if ($options['wrap']) {$tag = is_string($options['wrap']) ? $options['wrap'] : 'div';unset($options['wrap']);return $this->Html->tag($tag, $error, $options);}return $error;}/*** Returns a formatted LABEL element for HTML FORMs. Will automatically generate* a `for` attribute if one is not provided.** ### Options** - `for` - Set the for attribute, if its not defined the for attribute* will be generated from the $fieldName parameter using* FormHelper::domId().** Examples:** The text and for attribute are generated off of the fieldname** {{{* echo $this->Form->label('Post.published');* <label for="PostPublished">Published</label>* }}}** Custom text:** {{{* echo $this->Form->label('Post.published', 'Publish');* <label for="PostPublished">Publish</label>* }}}** Custom class name:** {{{* echo $this->Form->label('Post.published', 'Publish', 'required');* <label for="PostPublished" class="required">Publish</label>* }}}** Custom attributes:** {{{* echo $this->Form->label('Post.published', 'Publish', array(* 'for' => 'post-publish'* ));* <label for="post-publish">Publish</label>* }}}** @param string $fieldName This should be "Modelname.fieldname"* @param string $text Text that will appear in the label field. If* $text is left undefined the text will be inflected from the* fieldName.* @param array|string $options An array of HTML attributes, or a string, to be used as a class name.* @return string The formatted LABEL element* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::label*/public function label($fieldName = null, $text = null, $options = array()) {if ($fieldName === null) {$fieldName = implode('.', $this->entity());}if ($text === null) {if (strpos($fieldName, '.') !== false) {$fieldElements = explode('.', $fieldName);$text = array_pop($fieldElements);} else {$text = $fieldName;}if (substr($text, -3) === '_id') {$text = substr($text, 0, -3);}$text = __(Inflector::humanize(Inflector::underscore($text)));}if (is_string($options)) {$options = array('class' => $options);}if (isset($options['for'])) {$labelFor = $options['for'];unset($options['for']);} else {$labelFor = $this->domId($fieldName);}return $this->Html->useTag('label', $labelFor, $options, $text);}/*** Generate a set of inputs for `$fields`. If $fields is null the fields of current model* will be used.** You can customize individual inputs through `$fields`.* {{{* $this->Form->inputs(array(* 'name' => array('label' => 'custom label')* ));* }}}** In addition to controller fields output, `$fields` can be used to control legend* and fieldset rendering.* `$this->Form->inputs('My legend');` Would generate an input set with a custom legend.* Passing `fieldset` and `legend` key in `$fields` array has been deprecated since 2.3,* for more fine grained control use the `fieldset` and `legend` keys in `$options` param.** @param array $fields An array of fields to generate inputs for, or null.* @param array $blacklist A simple array of fields to not create inputs for.* @param array $options Options array. Valid keys are:* - `fieldset` Set to false to disable the fieldset. If a string is supplied it will be used as* the class name for the fieldset element.* - `legend` Set to false to disable the legend for the generated input set. Or supply a string* to customize the legend text.* @return string Completed form inputs.* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::inputs*/public function inputs($fields = null, $blacklist = null, $options = array()) {$fieldset = $legend = true;$modelFields = array();$model = $this->model();if ($model) {$modelFields = array_keys((array)$this->_introspectModel($model, 'fields'));}if (is_array($fields)) {if (array_key_exists('legend', $fields) && !in_array('legend', $modelFields)) {$legend = $fields['legend'];unset($fields['legend']);}if (isset($fields['fieldset']) && !in_array('fieldset', $modelFields)) {$fieldset = $fields['fieldset'];unset($fields['fieldset']);}} elseif ($fields !== null) {$fieldset = $legend = $fields;if (!is_bool($fieldset)) {$fieldset = true;}$fields = array();}if (isset($options['legend'])) {$legend = $options['legend'];}if (isset($options['fieldset'])) {$fieldset = $options['fieldset'];}if (empty($fields)) {$fields = $modelFields;}if ($legend === true) {$actionName = __d('cake', 'New %s');$isEdit = (strpos($this->request->params['action'], 'update') !== false ||strpos($this->request->params['action'], 'edit') !== false);if ($isEdit) {$actionName = __d('cake', 'Edit %s');}$modelName = Inflector::humanize(Inflector::underscore($model));$legend = sprintf($actionName, __($modelName));}$out = null;foreach ($fields as $name => $options) {if (is_numeric($name) && !is_array($options)) {$name = $options;$options = array();}$entity = explode('.', $name);$blacklisted = (is_array($blacklist) &&(in_array($name, $blacklist) || in_array(end($entity), $blacklist)));if ($blacklisted) {continue;}$out .= $this->input($name, $options);}if (is_string($fieldset)) {$fieldsetClass = sprintf(' class="%s"', $fieldset);} else {$fieldsetClass = '';}if ($fieldset) {if ($legend) {$out = $this->Html->useTag('legend', $legend) . $out;}$out = $this->Html->useTag('fieldset', $fieldsetClass, $out);}return $out;}/*** Generates a form input element complete with label and wrapper div** ### Options** See each field type method for more information. Any options that are part of* $attributes or $options for the different **type** methods can be included in `$options` for input().i* Additionally, any unknown keys that are not in the list below, or part of the selected type's options* will be treated as a regular html attribute for the generated input.** - `type` - Force the type of widget you want. e.g. `type => 'select'`* - `label` - Either a string label, or an array of options for the label. See FormHelper::label().* - `div` - Either `false` to disable the div, or an array of options for the div.* See HtmlHelper::div() for more options.* - `options` - For widgets that take options e.g. radio, select.* - `error` - Control the error message that is produced. Set to `false` to disable any kind of error reporting (field* error and error messages).* - `errorMessage` - Boolean to control rendering error messages (field error will still occur).* - `empty` - String or boolean to enable empty select box options.* - `before` - Content to place before the label + input.* - `after` - Content to place after the label + input.* - `between` - Content to place between the label + input.* - `format` - Format template for element order. Any element that is not in the array, will not be in the output.* - Default input format order: array('before', 'label', 'between', 'input', 'after', 'error')* - Default checkbox format order: array('before', 'input', 'between', 'label', 'after', 'error')* - Hidden input will not be formatted* - Radio buttons cannot have the order of input and label elements controlled with these settings.** @param string $fieldName This should be "Modelname.fieldname"* @param array $options Each type of input takes different options.* @return string Completed form widget.* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#creating-form-elements*/public function input($fieldName, $options = array()) {$this->setEntity($fieldName);$options = $this->_parseOptions($options);$divOptions = $this->_divOptions($options);unset($options['div']);if ($options['type'] === 'radio' && isset($options['options'])) {$radioOptions = (array)$options['options'];unset($options['options']);}$label = $this->_getLabel($fieldName, $options);if ($options['type'] !== 'radio') {unset($options['label']);}$error = $this->_extractOption('error', $options, null);unset($options['error']);$errorMessage = $this->_extractOption('errorMessage', $options, true);unset($options['errorMessage']);$selected = $this->_extractOption('selected', $options, null);unset($options['selected']);if ($options['type'] === 'datetime' || $options['type'] === 'date' || $options['type'] === 'time') {$dateFormat = $this->_extractOption('dateFormat', $options, 'MDY');$timeFormat = $this->_extractOption('timeFormat', $options, 12);unset($options['dateFormat'], $options['timeFormat']);}$type = $options['type'];$out = array('before' => $options['before'], 'label' => $label, 'between' => $options['between'], 'after' => $options['after']);$format = $this->_getFormat($options);unset($options['type'], $options['before'], $options['between'], $options['after'], $options['format']);$out['error'] = null;if ($type !== 'hidden' && $error !== false) {$errMsg = $this->error($fieldName, $error);if ($errMsg) {$divOptions = $this->addClass($divOptions, 'error');if ($errorMessage) {$out['error'] = $errMsg;}}}if ($type === 'radio' && isset($out['between'])) {$options['between'] = $out['between'];$out['between'] = null;}$out['input'] = $this->_getInput(compact('type', 'fieldName', 'options', 'radioOptions', 'selected', 'dateFormat', 'timeFormat'));$output = '';foreach ($format as $element) {$output .= $out[$element];}if (!empty($divOptions['tag'])) {$tag = $divOptions['tag'];unset($divOptions['tag']);$output = $this->Html->tag($tag, $output, $divOptions);}return $output;}/*** Generates an input element** @param array $args The options for the input element* @return string The generated input element*/protected function _getInput($args) {extract($args);switch ($type) {case 'hidden':return $this->hidden($fieldName, $options);case 'checkbox':return $this->checkbox($fieldName, $options);case 'radio':return $this->radio($fieldName, $radioOptions, $options);case 'file':return $this->file($fieldName, $options);case 'select':$options += array('options' => array(), 'value' => $selected);$list = $options['options'];unset($options['options']);return $this->select($fieldName, $list, $options);case 'time':$options['value'] = $selected;return $this->dateTime($fieldName, null, $timeFormat, $options);case 'date':$options['value'] = $selected;return $this->dateTime($fieldName, $dateFormat, null, $options);case 'datetime':$options['value'] = $selected;return $this->dateTime($fieldName, $dateFormat, $timeFormat, $options);case 'textarea':return $this->textarea($fieldName, $options + array('cols' => '30', 'rows' => '6'));case 'url':return $this->text($fieldName, array('type' => 'url') + $options);default:return $this->{$type}($fieldName, $options);}}/*** Generates input options array** @param array $options* @return array Options*/protected function _parseOptions($options) {$options = array_merge(array('before' => null, 'between' => null, 'after' => null, 'format' => null),$this->_inputDefaults,$options);if (!isset($options['type'])) {$options = $this->_magicOptions($options);}if (in_array($options['type'], array('radio', 'select'))) {$options = $this->_optionsOptions($options);}if (isset($options['rows']) || isset($options['cols'])) {$options['type'] = 'textarea';}if ($options['type'] === 'datetime' || $options['type'] === 'date' || $options['type'] === 'time' || $options['type'] === 'select') {$options += array('empty' => false);}return $options;}/*** Generates list of options for multiple select** @param array $options* @return array*/protected function _optionsOptions($options) {if (isset($options['options'])) {return $options;}$varName = Inflector::variable(Inflector::pluralize(preg_replace('/_id$/', '', $this->field())));$varOptions = $this->_View->get($varName);if (!is_array($varOptions)) {return $options;}if ($options['type'] !== 'radio') {$options['type'] = 'select';}$options['options'] = $varOptions;return $options;}/*** Magically set option type and corresponding options** @param array $options* @return array*/protected function _magicOptions($options) {$modelKey = $this->model();$fieldKey = $this->field();$options['type'] = 'text';if (isset($options['options'])) {$options['type'] = 'select';} elseif (in_array($fieldKey, array('psword', 'passwd', 'password'))) {$options['type'] = 'password';} elseif (in_array($fieldKey, array('tel', 'telephone', 'phone'))) {$options['type'] = 'tel';} elseif ($fieldKey === 'email') {$options['type'] = 'email';} elseif (isset($options['checked'])) {$options['type'] = 'checkbox';} elseif ($fieldDef = $this->_introspectModel($modelKey, 'fields', $fieldKey)) {$type = $fieldDef['type'];$primaryKey = $this->fieldset[$modelKey]['key'];$map = array('string' => 'text', 'datetime' => 'datetime','boolean' => 'checkbox', 'timestamp' => 'datetime','text' => 'textarea', 'time' => 'time','date' => 'date', 'float' => 'number','integer' => 'number');if (isset($this->map[$type])) {$options['type'] = $this->map[$type];} elseif (isset($map[$type])) {$options['type'] = $map[$type];}if ($fieldKey == $primaryKey) {$options['type'] = 'hidden';}if ($options['type'] === 'number' &&$type === 'float' &&!isset($options['step'])) {$options['step'] = 'any';}}if (preg_match('/_id$/', $fieldKey) && $options['type'] !== 'hidden') {$options['type'] = 'select';}if ($modelKey === $fieldKey) {$options['type'] = 'select';if (!isset($options['multiple'])) {$options['multiple'] = 'multiple';}}if (in_array($options['type'], array('text', 'number'))) {$options = $this->_optionsOptions($options);}if ($options['type'] === 'select' && array_key_exists('step', $options)) {unset($options['step']);}$options = $this->_maxLength($options);return $options;}/*** Generate format options** @param array $options* @return array*/protected function _getFormat($options) {if ($options['type'] === 'hidden') {return array('input');}if (is_array($options['format']) && in_array('input', $options['format'])) {return $options['format'];}if ($options['type'] === 'checkbox') {return array('before', 'input', 'between', 'label', 'after', 'error');}return array('before', 'label', 'between', 'input', 'after', 'error');}/*** Generate label for input** @param string $fieldName* @param array $options* @return boolean|string false or Generated label element*/protected function _getLabel($fieldName, $options) {if ($options['type'] === 'radio') {return false;}$label = null;if (isset($options['label'])) {$label = $options['label'];}if ($label === false) {return false;}return $this->_inputLabel($fieldName, $label, $options);}/*** Calculates maxlength option** @param array $options* @return array*/protected function _maxLength($options) {$fieldDef = $this->_introspectModel($this->model(), 'fields', $this->field());$autoLength = (!array_key_exists('maxlength', $options) &&isset($fieldDef['length']) &&is_scalar($fieldDef['length']) &&$options['type'] !== 'select');if ($autoLength &&in_array($options['type'], array('text', 'email', 'tel', 'url', 'search'))) {$options['maxlength'] = $fieldDef['length'];}return $options;}/*** Generate div options for input** @param array $options* @return array*/protected function _divOptions($options) {if ($options['type'] === 'hidden') {return array();}$div = $this->_extractOption('div', $options, true);if (!$div) {return array();}$divOptions = array('class' => 'input');$divOptions = $this->addClass($divOptions, $options['type']);if (is_string($div)) {$divOptions['class'] = $div;} elseif (is_array($div)) {$divOptions = array_merge($divOptions, $div);}if ($this->_extractOption('required', $options) !== false &&$this->_introspectModel($this->model(), 'validates', $this->field())) {$divOptions = $this->addClass($divOptions, 'required');}if (!isset($divOptions['tag'])) {$divOptions['tag'] = 'div';}return $divOptions;}/*** Extracts a single option from an options array.** @param string $name The name of the option to pull out.* @param array $options The array of options you want to extract.* @param mixed $default The default option value* @return mixed the contents of the option or default*/protected function _extractOption($name, $options, $default = null) {if (array_key_exists($name, $options)) {return $options[$name];}return $default;}/*** Generate a label for an input() call.** $options can contain a hash of id overrides. These overrides will be* used instead of the generated values if present.** @param string $fieldName* @param string $label* @param array $options Options for the label element. 'NONE' option is deprecated and will be removed in 3.0* @return string Generated label element*/protected function _inputLabel($fieldName, $label, $options) {$labelAttributes = $this->domId(array(), 'for');$idKey = null;if ($options['type'] === 'date' || $options['type'] === 'datetime') {$firstInput = 'M';if (array_key_exists('dateFormat', $options) &&($options['dateFormat'] === null || $options['dateFormat'] === 'NONE')) {$firstInput = 'H';} elseif (!empty($options['dateFormat'])) {$firstInput = substr($options['dateFormat'], 0, 1);}switch ($firstInput) {case 'D':$idKey = 'day';$labelAttributes['for'] .= 'Day';break;case 'Y':$idKey = 'year';$labelAttributes['for'] .= 'Year';break;case 'M':$idKey = 'month';$labelAttributes['for'] .= 'Month';break;case 'H':$idKey = 'hour';$labelAttributes['for'] .= 'Hour';}}if ($options['type'] === 'time') {$labelAttributes['for'] .= 'Hour';$idKey = 'hour';}if (isset($idKey) && isset($options['id']) && isset($options['id'][$idKey])) {$labelAttributes['for'] = $options['id'][$idKey];}if (is_array($label)) {$labelText = null;if (isset($label['text'])) {$labelText = $label['text'];unset($label['text']);}$labelAttributes = array_merge($labelAttributes, $label);} else {$labelText = $label;}if (isset($options['id']) && is_string($options['id'])) {$labelAttributes = array_merge($labelAttributes, array('for' => $options['id']));}return $this->label($fieldName, $labelText, $labelAttributes);}/*** Creates a checkbox input widget.** ### Options:** - `value` - the value of the checkbox* - `checked` - boolean indicate that this checkbox is checked.* - `hiddenField` - boolean to indicate if you want the results of checkbox() to include* a hidden input with a value of ''.* - `disabled` - create a disabled input.* - `default` - Set the default value for the checkbox. This allows you to start checkboxes* as checked, without having to check the POST data. A matching POST data value, will overwrite* the default value.** @param string $fieldName Name of a field, like this "Modelname.fieldname"* @param array $options Array of HTML attributes.* @return string An HTML text input element.* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#options-for-select-checkbox-and-radio-inputs*/public function checkbox($fieldName, $options = array()) {$valueOptions = array();if (isset($options['default'])) {$valueOptions['default'] = $options['default'];unset($options['default']);}$options += array('required' => false);$options = $this->_initInputField($fieldName, $options) + array('hiddenField' => true);$value = current($this->value($valueOptions));$output = '';if (empty($options['value'])) {$options['value'] = 1;}if ((!isset($options['checked']) && !empty($value) && $value == $options['value']) ||!empty($options['checked'])) {$options['checked'] = 'checked';}if ($options['hiddenField']) {$hiddenOptions = array('id' => $options['id'] . '_','name' => $options['name'],'value' => ($options['hiddenField'] !== true ? $options['hiddenField'] : '0'),'secure' => false);if (isset($options['disabled']) && $options['disabled']) {$hiddenOptions['disabled'] = 'disabled';}$output = $this->hidden($fieldName, $hiddenOptions);}unset($options['hiddenField']);return $output . $this->Html->useTag('checkbox', $options['name'], array_diff_key($options, array('name' => null)));}/*** Creates a set of radio widgets. Will create a legend and fieldset* by default. Use $options to control this** ### Attributes:** - `separator` - define the string in between the radio buttons* - `between` - the string between legend and input set or array of strings to insert* strings between each input block* - `legend` - control whether or not the widget set has a fieldset & legend* - `value` - indicate a value that is should be checked* - `label` - boolean to indicate whether or not labels for widgets show be displayed* - `hiddenField` - boolean to indicate if you want the results of radio() to include* a hidden input with a value of ''. This is useful for creating radio sets that non-continuous* - `disabled` - Set to `true` or `disabled` to disable all the radio buttons.* - `empty` - Set to `true` to create a input with the value '' as the first option. When `true`* the radio label will be 'empty'. Set this option to a string to control the label value.** @param string $fieldName Name of a field, like this "Modelname.fieldname"* @param array $options Radio button options array.* @param array $attributes Array of HTML attributes, and special attributes above.* @return string Completed radio widget set.* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#options-for-select-checkbox-and-radio-inputs*/public function radio($fieldName, $options = array(), $attributes = array()) {$attributes = $this->_initInputField($fieldName, $attributes);$showEmpty = $this->_extractOption('empty', $attributes);if ($showEmpty) {$showEmpty = ($showEmpty === true) ? __d('cake', 'empty') : $showEmpty;$options = array('' => $showEmpty) + $options;}unset($attributes['empty']);$legend = false;if (isset($attributes['legend'])) {$legend = $attributes['legend'];unset($attributes['legend']);} elseif (count($options) > 1) {$legend = __(Inflector::humanize($this->field()));}$label = true;if (isset($attributes['label'])) {$label = $attributes['label'];unset($attributes['label']);}$separator = null;if (isset($attributes['separator'])) {$separator = $attributes['separator'];unset($attributes['separator']);}$between = null;if (isset($attributes['between'])) {$between = $attributes['between'];unset($attributes['between']);}$value = null;if (isset($attributes['value'])) {$value = $attributes['value'];} else {$value = $this->value($fieldName);}$disabled = array();if (isset($attributes['disabled'])) {$disabled = $attributes['disabled'];}$out = array();$hiddenField = isset($attributes['hiddenField']) ? $attributes['hiddenField'] : true;unset($attributes['hiddenField']);if (isset($value) && is_bool($value)) {$value = $value ? 1 : 0;}foreach ($options as $optValue => $optTitle) {$optionsHere = array('value' => $optValue, 'disabled' => false);if (isset($value) && strval($optValue) === strval($value)) {$optionsHere['checked'] = 'checked';}$isNumeric = is_numeric($optValue);if ($disabled && (!is_array($disabled) || in_array((string)$optValue, $disabled, !$isNumeric))) {$optionsHere['disabled'] = true;}$tagName = Inflector::camelize($attributes['id'] . '_' . Inflector::slug($optValue));if ($label) {$labelOpts = is_array($label) ? $label : array();$labelOpts += array('for' => $tagName);$optTitle = $this->label($tagName, $optTitle, $labelOpts);}if (is_array($between)) {$optTitle .= array_shift($between);}$allOptions = array_merge($attributes, $optionsHere);$out[] = $this->Html->useTag('radio', $attributes['name'], $tagName,array_diff_key($allOptions, array('name' => null, 'type' => null, 'id' => null)),$optTitle);}$hidden = null;if ($hiddenField) {if (!isset($value) || $value === '') {$hidden = $this->hidden($fieldName, array('id' => $attributes['id'] . '_', 'value' => '', 'name' => $attributes['name']));}}$out = $hidden . implode($separator, $out);if (is_array($between)) {$between = '';}if ($legend) {$out = $this->Html->useTag('fieldset', '', $this->Html->useTag('legend', $legend) . $between . $out);}return $out;}/*** Missing method handler - implements various simple input types. Is used to create inputs* of various types. e.g. `$this->Form->text();` will create `<input type="text" />` while* `$this->Form->range();` will create `<input type="range" />`** ### Usage** `$this->Form->search('User.query', array('value' => 'test'));`** Will make an input like:** `<input type="search" id="UserQuery" name="data[User][query]" value="test" />`** The first argument to an input type should always be the fieldname, in `Model.field` format.* The second argument should always be an array of attributes for the input.** @param string $method Method name / input type to make.* @param array $params Parameters for the method call* @return string Formatted input method.* @throws CakeException When there are no params for the method call.*/public function __call($method, $params) {$options = array();if (empty($params)) {throw new CakeException(__d('cake_dev', 'Missing field name for FormHelper::%s', $method));}if (isset($params[1])) {$options = $params[1];}if (!isset($options['type'])) {$options['type'] = $method;}$options = $this->_initInputField($params[0], $options);return $this->Html->useTag('input', $options['name'], array_diff_key($options, array('name' => null)));}/*** Creates a textarea widget.** ### Options:** - `escape` - Whether or not the contents of the textarea should be escaped. Defaults to true.** @param string $fieldName Name of a field, in the form "Modelname.fieldname"* @param array $options Array of HTML attributes, and special options above.* @return string A generated HTML text input element* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::textarea*/public function textarea($fieldName, $options = array()) {$options = $this->_initInputField($fieldName, $options);$value = null;if (array_key_exists('value', $options)) {$value = $options['value'];if (!array_key_exists('escape', $options) || $options['escape'] !== false) {$value = h($value);}unset($options['value']);}return $this->Html->useTag('textarea', $options['name'], array_diff_key($options, array('type' => null, 'name' => null)), $value);}/*** Creates a hidden input field.** @param string $fieldName Name of a field, in the form of "Modelname.fieldname"* @param array $options Array of HTML attributes.* @return string A generated hidden input* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::hidden*/public function hidden($fieldName, $options = array()) {$options += array('required' => false, 'secure' => true);$secure = $options['secure'];unset($options['secure']);$options = $this->_initInputField($fieldName, array_merge($options, array('secure' => self::SECURE_SKIP)));if ($secure === true) {$this->_secure(true, null, '' . $options['value']);}return $this->Html->useTag('hidden', $options['name'], array_diff_key($options, array('name' => null)));}/*** Creates file input widget.** @param string $fieldName Name of a field, in the form "Modelname.fieldname"* @param array $options Array of HTML attributes.* @return string A generated file input.* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::file*/public function file($fieldName, $options = array()) {$options += array('secure' => true);$secure = $options['secure'];$options['secure'] = self::SECURE_SKIP;$options = $this->_initInputField($fieldName, $options);$field = $this->entity();foreach (array('name', 'type', 'tmp_name', 'error', 'size') as $suffix) {$this->_secure($secure, array_merge($field, array($suffix)));}$exclude = array('name' => null, 'value' => null);return $this->Html->useTag('file', $options['name'], array_diff_key($options, $exclude));}/*** Creates a `<button>` tag. The type attribute defaults to `type="submit"`* You can change it to a different value by using `$options['type']`.** ### Options:** - `escape` - HTML entity encode the $title of the button. Defaults to false.** @param string $title The button's caption. Not automatically HTML encoded* @param array $options Array of options and HTML attributes.* @return string A HTML button tag.* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::button*/public function button($title, $options = array()) {$options += array('type' => 'submit', 'escape' => false, 'secure' => false);if ($options['escape']) {$title = h($title);}if (isset($options['name'])) {$name = str_replace(array('[', ']'), array('.', ''), $options['name']);$this->_secure($options['secure'], $name);}return $this->Html->useTag('button', $options, $title);}/*** Create a `<button>` tag with a surrounding `<form>` that submits via POST.** This method creates a `<form>` element. So do not use this method in an already opened form.* Instead use FormHelper::submit() or FormHelper::button() to create buttons inside opened forms.** ### Options:** - `data` - Array with key/value to pass in input hidden* - Other options is the same of button method.** @param string $title The button's caption. Not automatically HTML encoded* @param string|array $url URL as string or array* @param array $options Array of options and HTML attributes.* @return string A HTML button tag.* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::postButton*/public function postButton($title, $url, $options = array()) {$out = $this->create(false, array('id' => false, 'url' => $url));if (isset($options['data']) && is_array($options['data'])) {foreach ($options['data'] as $key => $value) {$out .= $this->hidden($key, array('value' => $value, 'id' => false));}unset($options['data']);}$out .= $this->button($title, $options);$out .= $this->end();return $out;}/*** Creates an HTML link, but access the URL using the method you specify (defaults to POST).* Requires javascript to be enabled in browser.** This method creates a `<form>` element. So do not use this method inside an existing form.* Instead you should add a submit button using FormHelper::submit()** ### Options:** - `data` - Array with key/value to pass in input hidden* - `method` - Request method to use. Set to 'delete' to simulate HTTP/1.1 DELETE request. Defaults to 'post'.* - `confirm` - Can be used instead of $confirmMessage.* - Other options is the same of HtmlHelper::link() method.* - The option `onclick` will be replaced.** @param string $title The content to be wrapped by <a> tags.* @param string|array $url Cake-relative URL or array of URL parameters, or external URL (starts with http://)* @param array $options Array of HTML attributes.* @param boolean|string $confirmMessage JavaScript confirmation message.* @return string An `<a />` element.* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::postLink*/public function postLink($title, $url = null, $options = array(), $confirmMessage = false) {$requestMethod = 'POST';if (!empty($options['method'])) {$requestMethod = strtoupper($options['method']);unset($options['method']);}if (!empty($options['confirm'])) {$confirmMessage = $options['confirm'];unset($options['confirm']);}$formName = str_replace('.', '', uniqid('post_', true));$formUrl = $this->url($url);$formOptions = array('name' => $formName,'id' => $formName,'style' => 'display:none;','method' => 'post',);if (isset($options['target'])) {$formOptions['target'] = $options['target'];unset($options['target']);}$out = $this->Html->useTag('form', $formUrl, $formOptions);$out .= $this->Html->useTag('hidden', '_method', array('value' => $requestMethod));$out .= $this->_csrfField();$fields = array();if (isset($options['data']) && is_array($options['data'])) {foreach ($options['data'] as $key => $value) {$fields[$key] = $value;$out .= $this->hidden($key, array('value' => $value, 'id' => false));}unset($options['data']);}$out .= $this->secure($fields);$out .= $this->Html->useTag('formend');$url = '#';$onClick = 'document.' . $formName . '.submit();';if ($confirmMessage) {$options['onclick'] = $this->_confirm($confirmMessage, $onClick, '', $options);} else {$options['onclick'] = $onClick . ' ';}$options['onclick'] .= 'event.returnValue = false; return false;';$out .= $this->Html->link($title, $url, $options);return $out;}/*** Creates a submit button element. This method will generate `<input />` elements that* can be used to submit, and reset forms by using $options. image submits can be created by supplying an* image path for $caption.** ### Options** - `div` - Include a wrapping div? Defaults to true. Accepts sub options similar to* FormHelper::input().* - `before` - Content to include before the input.* - `after` - Content to include after the input.* - `type` - Set to 'reset' for reset inputs. Defaults to 'submit'* - Other attributes will be assigned to the input element.** ### Options** - `div` - Include a wrapping div? Defaults to true. Accepts sub options similar to* FormHelper::input().* - Other attributes will be assigned to the input element.** @param string $caption The label appearing on the button OR if string contains :// or the* extension .jpg, .jpe, .jpeg, .gif, .png use an image if the extension* exists, AND the first character is /, image is relative to webroot,* OR if the first character is not /, image is relative to webroot/img.* @param array $options Array of options. See above.* @return string A HTML submit button* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::submit*/public function submit($caption = null, $options = array()) {if (!is_string($caption) && empty($caption)) {$caption = __d('cake', 'Submit');}$out = null;$div = true;if (isset($options['div'])) {$div = $options['div'];unset($options['div']);}$options += array('type' => 'submit', 'before' => null, 'after' => null, 'secure' => false);$divOptions = array('tag' => 'div');if ($div === true) {$divOptions['class'] = 'submit';} elseif ($div === false) {unset($divOptions);} elseif (is_string($div)) {$divOptions['class'] = $div;} elseif (is_array($div)) {$divOptions = array_merge(array('class' => 'submit', 'tag' => 'div'), $div);}if (isset($options['name'])) {$name = str_replace(array('[', ']'), array('.', ''), $options['name']);$this->_secure($options['secure'], $name);}unset($options['secure']);$before = $options['before'];$after = $options['after'];unset($options['before'], $options['after']);$isUrl = strpos($caption, '://') !== false;$isImage = preg_match('/\.(jpg|jpe|jpeg|gif|png|ico)$/', $caption);if ($isUrl || $isImage) {$unlockFields = array('x', 'y');if (isset($options['name'])) {$unlockFields = array($options['name'] . '_x', $options['name'] . '_y');}foreach ($unlockFields as $ignore) {$this->unlockField($ignore);}}if ($isUrl) {unset($options['type']);$tag = $this->Html->useTag('submitimage', $caption, $options);} elseif ($isImage) {unset($options['type']);if ($caption{0} !== '/') {$url = $this->webroot(Configure::read('App.imageBaseUrl') . $caption);} else {$url = $this->webroot(trim($caption, '/'));}$url = $this->assetTimestamp($url);$tag = $this->Html->useTag('submitimage', $url, $options);} else {$options['value'] = $caption;$tag = $this->Html->useTag('submit', $options);}$out = $before . $tag . $after;if (isset($divOptions)) {$tag = $divOptions['tag'];unset($divOptions['tag']);$out = $this->Html->tag($tag, $out, $divOptions);}return $out;}/*** Returns a formatted SELECT element.** ### Attributes:** - `showParents` - If included in the array and set to true, an additional option element* will be added for the parent of each option group. You can set an option with the same name* and it's key will be used for the value of the option.* - `multiple` - show a multiple select box. If set to 'checkbox' multiple checkboxes will be* created instead.* - `empty` - If true, the empty select option is shown. If a string,* that string is displayed as the empty element.* - `escape` - If true contents of options will be HTML entity encoded. Defaults to true.* - `value` The selected value of the input.* - `class` - When using multiple = checkbox the class name to apply to the divs. Defaults to 'checkbox'.* - `disabled` - Control the disabled attribute. When creating a select box, set to true to disable the* select box. When creating checkboxes, `true` will disable all checkboxes. You can also set disabled* to a list of values you want to disable when creating checkboxes.** ### Using options** A simple array will create normal options:** {{{* $options = array(1 => 'one', 2 => 'two);* $this->Form->select('Model.field', $options));* }}}** While a nested options array will create optgroups with options inside them.* {{{* $options = array(* 1 => 'bill',* 'fred' => array(* 2 => 'fred',* 3 => 'fred jr.'* )* );* $this->Form->select('Model.field', $options);* }}}** In the above `2 => 'fred'` will not generate an option element. You should enable the `showParents`* attribute to show the fred option.** If you have multiple options that need to have the same value attribute, you can* use an array of arrays to express this:** {{{* $options = array(* array('name' => 'United states', 'value' => 'USA'),* array('name' => 'USA', 'value' => 'USA'),* );* }}}** @param string $fieldName Name attribute of the SELECT* @param array $options Array of the OPTION elements (as 'value'=>'Text' pairs) to be used in the* SELECT element* @param array $attributes The HTML attributes of the select element.* @return string Formatted SELECT element* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#options-for-select-checkbox-and-radio-inputs*/public function select($fieldName, $options = array(), $attributes = array()) {$select = array();$style = null;$tag = null;$attributes += array('class' => null,'escape' => true,'secure' => true,'empty' => '','showParents' => false,'hiddenField' => true,'disabled' => false);$escapeOptions = $this->_extractOption('escape', $attributes);$secure = $this->_extractOption('secure', $attributes);$showEmpty = $this->_extractOption('empty', $attributes);$showParents = $this->_extractOption('showParents', $attributes);$hiddenField = $this->_extractOption('hiddenField', $attributes);unset($attributes['escape'], $attributes['secure'], $attributes['empty'], $attributes['showParents'], $attributes['hiddenField']);$id = $this->_extractOption('id', $attributes);$attributes = $this->_initInputField($fieldName, array_merge((array)$attributes, array('secure' => self::SECURE_SKIP)));if (is_string($options) && isset($this->_options[$options])) {$options = $this->_generateOptions($options);} elseif (!is_array($options)) {$options = array();}if (isset($attributes['type'])) {unset($attributes['type']);}if (!empty($attributes['multiple'])) {$style = ($attributes['multiple'] === 'checkbox') ? 'checkbox' : null;$template = ($style) ? 'checkboxmultiplestart' : 'selectmultiplestart';$tag = $template;if ($hiddenField) {$hiddenAttributes = array('value' => '','id' => $attributes['id'] . ($style ? '' : '_'),'secure' => false,'name' => $attributes['name']);$select[] = $this->hidden(null, $hiddenAttributes);}} else {$tag = 'selectstart';}if ($tag === 'checkboxmultiplestart') {unset($attributes['required']);}if (!empty($tag) || isset($template)) {$hasOptions = (count($options) > 0 || $showEmpty);// Secure the field if there are options, or its a multi select.// Single selects with no options don't submit, but multiselects do.if ((!isset($secure) || $secure) &&empty($attributes['disabled']) &&(!empty($attributes['multiple']) || $hasOptions)) {$this->_secure(true, $this->_secureFieldName($attributes));}$select[] = $this->Html->useTag($tag, $attributes['name'], array_diff_key($attributes, array('name' => null, 'value' => null)));}$emptyMulti = ($showEmpty !== null && $showEmpty !== false && !(empty($showEmpty) && (isset($attributes) &&array_key_exists('multiple', $attributes))));if ($emptyMulti) {$showEmpty = ($showEmpty === true) ? '' : $showEmpty;$options = array('' => $showEmpty) + $options;}if (!$id) {$attributes['id'] = Inflector::camelize($attributes['id']);}$select = array_merge($select, $this->_selectOptions(array_reverse($options, true),array(),$showParents,array('escape' => $escapeOptions,'style' => $style,'name' => $attributes['name'],'value' => $attributes['value'],'class' => $attributes['class'],'id' => $attributes['id'],'disabled' => $attributes['disabled'],)));$template = ($style === 'checkbox') ? 'checkboxmultipleend' : 'selectend';$select[] = $this->Html->useTag($template);return implode("\n", $select);}/*** Returns a SELECT element for days.** ### Attributes:** - `empty` - If true, the empty select option is shown. If a string,* that string is displayed as the empty element.* - `value` The selected value of the input.** @param string $fieldName Prefix name for the SELECT element* @param array $attributes HTML attributes for the select element* @return string A generated day select box.* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::day*/public function day($fieldName = null, $attributes = array()) {$attributes += array('empty' => true, 'value' => null);$attributes = $this->_dateTimeSelected('day', $fieldName, $attributes);if (strlen($attributes['value']) > 2) {$attributes['value'] = date_create($attributes['value'])->format('d');} elseif ($attributes['value'] === false) {$attributes['value'] = null;}return $this->select($fieldName . ".day", $this->_generateOptions('day'), $attributes);}/*** Returns a SELECT element for years** ### Attributes:** - `empty` - If true, the empty select option is shown. If a string,* that string is displayed as the empty element.* - `orderYear` - Ordering of year values in select options.* Possible values 'asc', 'desc'. Default 'desc'* - `value` The selected value of the input.** @param string $fieldName Prefix name for the SELECT element* @param integer $minYear First year in sequence* @param integer $maxYear Last year in sequence* @param array $attributes Attribute array for the select elements.* @return string Completed year select input* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::year*/public function year($fieldName, $minYear = null, $maxYear = null, $attributes = array()) {$attributes += array('empty' => true, 'value' => null);if ((empty($attributes['value']) || $attributes['value'] === true) && $value = $this->value($fieldName)) {if (is_array($value)) {$year = null;extract($value);$attributes['value'] = $year;} else {if (empty($value)) {if (!$attributes['empty'] && !$maxYear) {$attributes['value'] = 'now';} elseif (!$attributes['empty'] && $maxYear && !$attributes['value']) {$attributes['value'] = $maxYear;}} else {$attributes['value'] = $value;}}}if (strlen($attributes['value']) > 4 || $attributes['value'] === 'now') {$attributes['value'] = date_create($attributes['value'])->format('Y');} elseif ($attributes['value'] === false) {$attributes['value'] = null;}$yearOptions = array('value' => $attributes['value'], 'min' => $minYear, 'max' => $maxYear, 'order' => 'desc');if (isset($attributes['orderYear'])) {$yearOptions['order'] = $attributes['orderYear'];unset($attributes['orderYear']);}return $this->select($fieldName . '.year', $this->_generateOptions('year', $yearOptions),$attributes);}/*** Returns a SELECT element for months.** ### Attributes:** - `monthNames` - If false, 2 digit numbers will be used instead of text.* If a array, the given array will be used.* - `empty` - If true, the empty select option is shown. If a string,* that string is displayed as the empty element.* - `value` The selected value of the input.** @param string $fieldName Prefix name for the SELECT element* @param array $attributes Attributes for the select element* @return string A generated month select dropdown.* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::month*/public function month($fieldName, $attributes = array()) {$attributes += array('empty' => true, 'value' => null);$attributes = $this->_dateTimeSelected('month', $fieldName, $attributes);if (strlen($attributes['value']) > 2) {$attributes['value'] = date_create($attributes['value'])->format('m');} elseif ($attributes['value'] === false) {$attributes['value'] = null;}$defaults = array('monthNames' => true);$attributes = array_merge($defaults, (array)$attributes);$monthNames = $attributes['monthNames'];unset($attributes['monthNames']);return $this->select($fieldName . ".month",$this->_generateOptions('month', array('monthNames' => $monthNames)),$attributes);}/*** Returns a SELECT element for hours.** ### Attributes:** - `empty` - If true, the empty select option is shown. If a string,* that string is displayed as the empty element.* - `value` The selected value of the input.** @param string $fieldName Prefix name for the SELECT element* @param boolean $format24Hours True for 24 hours format* @param array $attributes List of HTML attributes* @return string Completed hour select input* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::hour*/public function hour($fieldName, $format24Hours = false, $attributes = array()) {$attributes += array('empty' => true, 'value' => null);$attributes = $this->_dateTimeSelected('hour', $fieldName, $attributes);if (strlen($attributes['value']) > 2) {$Date = new DateTime($attributes['value']);if ($format24Hours) {$attributes['value'] = $Date->format('H');} else {$attributes['value'] = $Date->format('g');}} elseif ($attributes['value'] === false) {$attributes['value'] = null;}if ($attributes['value'] > 12 && !$format24Hours) {$attributes['value'] -= 12;}if (($attributes['value'] === 0 || $attributes['value'] === '00') && !$format24Hours) {$attributes['value'] = 12;}return $this->select($fieldName . ".hour",$this->_generateOptions($format24Hours ? 'hour24' : 'hour'),$attributes);}/*** Returns a SELECT element for minutes.** ### Attributes:** - `empty` - If true, the empty select option is shown. If a string,* that string is displayed as the empty element.* - `value` The selected value of the input.** @param string $fieldName Prefix name for the SELECT element* @param array $attributes Array of Attributes* @return string Completed minute select input.* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::minute*/public function minute($fieldName, $attributes = array()) {$attributes += array('empty' => true, 'value' => null);$attributes = $this->_dateTimeSelected('min', $fieldName, $attributes);if (strlen($attributes['value']) > 2) {$attributes['value'] = date_create($attributes['value'])->format('i');} elseif ($attributes['value'] === false) {$attributes['value'] = null;}$minuteOptions = array();if (isset($attributes['interval'])) {$minuteOptions['interval'] = $attributes['interval'];unset($attributes['interval']);}return $this->select($fieldName . ".min", $this->_generateOptions('minute', $minuteOptions),$attributes);}/*** Selects values for dateTime selects.** @param string $select Name of element field. ex. 'day'* @param string $fieldName Name of fieldName being generated ex. Model.created* @param array $attributes Array of attributes, must contain 'empty' key.* @return array Attributes array with currently selected value.*/protected function _dateTimeSelected($select, $fieldName, $attributes) {if ((empty($attributes['value']) || $attributes['value'] === true) && $value = $this->value($fieldName)) {if (is_array($value)) {$attributes['value'] = isset($value[$select]) ? $value[$select] : null;} else {if (empty($value)) {if (!$attributes['empty']) {$attributes['value'] = 'now';}} else {$attributes['value'] = $value;}}}return $attributes;}/*** Returns a SELECT element for AM or PM.** ### Attributes:** - `empty` - If true, the empty select option is shown. If a string,* that string is displayed as the empty element.* - `value` The selected value of the input.** @param string $fieldName Prefix name for the SELECT element* @param array|string $attributes Array of Attributes* @return string Completed meridian select input* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::meridian*/public function meridian($fieldName, $attributes = array()) {$attributes += array('empty' => true, 'value' => null);if ((empty($attributes['value']) || $attributes['value'] === true) && $value = $this->value($fieldName)) {if (is_array($value)) {$meridian = null;extract($value);$attributes['value'] = $meridian;} else {if (empty($value)) {if (!$attributes['empty']) {$attributes['value'] = date('a');}} else {$attributes['value'] = date_create($attributes['value'])->format('a');}}}if ($attributes['value'] === false) {$attributes['value'] = null;}return $this->select($fieldName . ".meridian", $this->_generateOptions('meridian'),$attributes);}/*** Returns a set of SELECT elements for a full datetime setup: day, month and year, and then time.** ### Attributes:** - `monthNames` If false, 2 digit numbers will be used instead of text.* If a array, the given array will be used.* - `minYear` The lowest year to use in the year select* - `maxYear` The maximum year to use in the year select* - `interval` The interval for the minutes select. Defaults to 1* - `separator` The contents of the string between select elements. Defaults to '-'* - `empty` - If true, the empty select option is shown. If a string,* that string is displayed as the empty element.* - `round` - Set to `up` or `down` if you want to force rounding in either direction. Defaults to null.* - `value` | `default` The default value to be used by the input. A value in `$this->data`* matching the field name will override this value. If no default is provided `time()` will be used.** @param string $fieldName Prefix name for the SELECT element* @param string $dateFormat DMY, MDY, YMD, or null to not generate date inputs.* @param string $timeFormat 12, 24, or null to not generate time inputs.* @param array|string $attributes array of Attributes* @return string Generated set of select boxes for the date and time formats chosen.* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::dateTime*/public function dateTime($fieldName, $dateFormat = 'DMY', $timeFormat = '12', $attributes = array()) {$attributes += array('empty' => true, 'value' => null);$year = $month = $day = $hour = $min = $meridian = null;if (empty($attributes['value'])) {$attributes = $this->value($attributes, $fieldName);}if ($attributes['value'] === null && $attributes['empty'] != true) {$attributes['value'] = time();if (!empty($attributes['maxYear']) && $attributes['maxYear'] < date('Y')) {$attributes['value'] = strtotime(date($attributes['maxYear'] . '-m-d'));}}if (!empty($attributes['value'])) {list($year, $month, $day, $hour, $min, $meridian) = $this->_getDateTimeValue($attributes['value'],$timeFormat);}$defaults = array('minYear' => null, 'maxYear' => null, 'separator' => '-','interval' => 1, 'monthNames' => true, 'round' => null);$attributes = array_merge($defaults, (array)$attributes);if (isset($attributes['minuteInterval'])) {$attributes['interval'] = $attributes['minuteInterval'];unset($attributes['minuteInterval']);}$minYear = $attributes['minYear'];$maxYear = $attributes['maxYear'];$separator = $attributes['separator'];$interval = $attributes['interval'];$monthNames = $attributes['monthNames'];$round = $attributes['round'];$attributes = array_diff_key($attributes, $defaults);if ($timeFormat == 12 && $hour == 12) {$hour = 0;}if (!empty($interval) && $interval > 1 && !empty($min)) {$current = new DateTime();if ($year !== null) {$current->setDate($year, $month, $day);}if ($hour !== null) {$current->setTime($hour, $min);}$changeValue = $min * (1 / $interval);switch ($round) {case 'up':$changeValue = ceil($changeValue);break;case 'down':$changeValue = floor($changeValue);break;default:$changeValue = round($changeValue);}$change = ($changeValue * $interval) - $min;$current->modify($change > 0 ? "+$change minutes" : "$change minutes");$format = ($timeFormat == 12) ? 'Y m d h i a' : 'Y m d H i a';$newTime = explode(' ', $current->format($format));list($year, $month, $day, $hour, $min, $meridian) = $newTime;}$keys = array('Day', 'Month', 'Year', 'Hour', 'Minute', 'Meridian');$attrs = array_fill_keys($keys, $attributes);$hasId = isset($attributes['id']);if ($hasId && is_array($attributes['id'])) {// check for missing ones and build selectAttr for each element$attributes['id'] += array('month' => '','year' => '','day' => '','hour' => '','minute' => '','meridian' => '');foreach ($keys as $key) {$attrs[$key]['id'] = $attributes['id'][strtolower($key)];}}if ($hasId && is_string($attributes['id'])) {// build out an array versionforeach ($keys as $key) {$attrs[$key]['id'] = $attributes['id'] . $key;}}if (is_array($attributes['empty'])) {$attributes['empty'] += array('month' => true,'year' => true,'day' => true,'hour' => true,'minute' => true,'meridian' => true);foreach ($keys as $key) {$attrs[$key]['empty'] = $attributes['empty'][strtolower($key)];}}$selects = array();foreach (preg_split('//', $dateFormat, -1, PREG_SPLIT_NO_EMPTY) as $char) {switch ($char) {case 'Y':$attrs['Year']['value'] = $year;$selects[] = $this->year($fieldName, $minYear, $maxYear, $attrs['Year']);break;case 'M':$attrs['Month']['value'] = $month;$attrs['Month']['monthNames'] = $monthNames;$selects[] = $this->month($fieldName, $attrs['Month']);break;case 'D':$attrs['Day']['value'] = $day;$selects[] = $this->day($fieldName, $attrs['Day']);break;}}$opt = implode($separator, $selects);$attrs['Minute']['interval'] = $interval;switch ($timeFormat) {case '24':$attrs['Hour']['value'] = $hour;$attrs['Minute']['value'] = $min;$opt .= $this->hour($fieldName, true, $attrs['Hour']) . ':' .$this->minute($fieldName, $attrs['Minute']);break;case '12':$attrs['Hour']['value'] = $hour;$attrs['Minute']['value'] = $min;$attrs['Meridian']['value'] = $meridian;$opt .= $this->hour($fieldName, false, $attrs['Hour']) . ':' .$this->minute($fieldName, $attrs['Minute']) . ' ' .$this->meridian($fieldName, $attrs['Meridian']);break;}return $opt;}/*** Parse the value for a datetime selected value** @param string|array $value The selected value.* @param integer $timeFormat The time format* @return array Array of selected value.*/protected function _getDateTimeValue($value, $timeFormat) {$year = $month = $day = $hour = $min = $meridian = null;if (is_array($value)) {extract($value);if ($meridian === 'pm') {$hour += 12;}return array($year, $month, $day, $hour, $min, $meridian);}if (is_numeric($value)) {$value = strftime('%Y-%m-%d %H:%M:%S', $value);}$meridian = 'am';$pos = strpos($value, '-');if ($pos !== false) {$date = explode('-', $value);$days = explode(' ', $date[2]);$day = $days[0];$month = $date[1];$year = $date[0];} else {$days[1] = $value;}if (!empty($timeFormat)) {$time = explode(':', $days[1]);if ($time[0] >= 12) {$meridian = 'pm';}$hour = $min = null;if (isset($time[1])) {$hour = $time[0];$min = $time[1];}}return array($year, $month, $day, $hour, $min, $meridian);}/*** Gets the input field name for the current tag** @param array $options* @param string $field* @param string $key* @return array*/protected function _name($options = array(), $field = null, $key = 'name') {if ($this->requestType === 'get') {if ($options === null) {$options = array();} elseif (is_string($options)) {$field = $options;$options = 0;}if (!empty($field)) {$this->setEntity($field);}if (is_array($options) && isset($options[$key])) {return $options;}$entity = $this->entity();$model = $this->model();$name = $model === $entity[0] && isset($entity[1]) ? $entity[1] : $entity[0];$last = $entity[count($entity) - 1];if (in_array($last, $this->_fieldSuffixes)) {$name .= '[' . $last . ']';}if (is_array($options)) {$options[$key] = $name;return $options;}return $name;}return parent::_name($options, $field, $key);}/*** Returns an array of formatted OPTION/OPTGROUP elements** @param array $elements* @param array $parents* @param boolean $showParents* @param array $attributes* @return array*/protected function _selectOptions($elements = array(), $parents = array(), $showParents = null, $attributes = array()) {$select = array();$attributes = array_merge(array('escape' => true, 'style' => null, 'value' => null, 'class' => null),$attributes);$selectedIsEmpty = ($attributes['value'] === '' || $attributes['value'] === null);$selectedIsArray = is_array($attributes['value']);foreach ($elements as $name => $title) {$htmlOptions = array();if (is_array($title) && (!isset($title['name']) || !isset($title['value']))) {if (!empty($name)) {if ($attributes['style'] === 'checkbox') {$select[] = $this->Html->useTag('fieldsetend');} else {$select[] = $this->Html->useTag('optiongroupend');}$parents[] = $name;}$select = array_merge($select, $this->_selectOptions($title, $parents, $showParents, $attributes));if (!empty($name)) {$name = $attributes['escape'] ? h($name) : $name;if ($attributes['style'] === 'checkbox') {$select[] = $this->Html->useTag('fieldsetstart', $name);} else {$select[] = $this->Html->useTag('optiongroup', $name, '');}}$name = null;} elseif (is_array($title)) {$htmlOptions = $title;$name = $title['value'];$title = $title['name'];unset($htmlOptions['name'], $htmlOptions['value']);}if ($name !== null) {$isNumeric = is_numeric($name);if ((!$selectedIsArray && !$selectedIsEmpty && (string)$attributes['value'] == (string)$name) ||($selectedIsArray && in_array((string)$name, $attributes['value'], !$isNumeric))) {if ($attributes['style'] === 'checkbox') {$htmlOptions['checked'] = true;} else {$htmlOptions['selected'] = 'selected';}}if ($showParents || (!in_array($title, $parents))) {$title = ($attributes['escape']) ? h($title) : $title;$hasDisabled = !empty($attributes['disabled']);if ($hasDisabled) {$disabledIsArray = is_array($attributes['disabled']);if ($disabledIsArray) {$disabledIsNumeric = is_numeric($name);}}if ($hasDisabled &&$disabledIsArray &&in_array((string)$name, $attributes['disabled'], !$disabledIsNumeric)) {$htmlOptions['disabled'] = 'disabled';}if ($hasDisabled && !$disabledIsArray && $attributes['style'] === 'checkbox') {$htmlOptions['disabled'] = $attributes['disabled'] === true ? 'disabled' : $attributes['disabled'];}if ($attributes['style'] === 'checkbox') {$htmlOptions['value'] = $name;$tagName = $attributes['id'] . Inflector::camelize(Inflector::slug($name));$htmlOptions['id'] = $tagName;$label = array('for' => $tagName);if (isset($htmlOptions['checked']) && $htmlOptions['checked'] === true) {$label['class'] = 'selected';}$name = $attributes['name'];if (empty($attributes['class'])) {$attributes['class'] = 'checkbox';} elseif ($attributes['class'] === 'form-error') {$attributes['class'] = 'checkbox ' . $attributes['class'];}$label = $this->label(null, $title, $label);$item = $this->Html->useTag('checkboxmultiple', $name, $htmlOptions);$select[] = $this->Html->div($attributes['class'], $item . $label);} else {$select[] = $this->Html->useTag('selectoption', $name, $htmlOptions, $title);}}}}return array_reverse($select, true);}/*** Generates option lists for common <select /> menus** @param string $name* @param array $options* @return array*/protected function _generateOptions($name, $options = array()) {if (!empty($this->options[$name])) {return $this->options[$name];}$data = array();switch ($name) {case 'minute':if (isset($options['interval'])) {$interval = $options['interval'];} else {$interval = 1;}$i = 0;while ($i < 60) {$data[sprintf('%02d', $i)] = sprintf('%02d', $i);$i += $interval;}break;case 'hour':for ($i = 1; $i <= 12; $i++) {$data[sprintf('%02d', $i)] = $i;}break;case 'hour24':for ($i = 0; $i <= 23; $i++) {$data[sprintf('%02d', $i)] = $i;}break;case 'meridian':$data = array('am' => 'am', 'pm' => 'pm');break;case 'day':$min = 1;$max = 31;if (isset($options['min'])) {$min = $options['min'];}if (isset($options['max'])) {$max = $options['max'];}for ($i = $min; $i <= $max; $i++) {$data[sprintf('%02d', $i)] = $i;}break;case 'month':if ($options['monthNames'] === true) {$data['01'] = __d('cake', 'January');$data['02'] = __d('cake', 'February');$data['03'] = __d('cake', 'March');$data['04'] = __d('cake', 'April');$data['05'] = __d('cake', 'May');$data['06'] = __d('cake', 'June');$data['07'] = __d('cake', 'July');$data['08'] = __d('cake', 'August');$data['09'] = __d('cake', 'September');$data['10'] = __d('cake', 'October');$data['11'] = __d('cake', 'November');$data['12'] = __d('cake', 'December');} elseif (is_array($options['monthNames'])) {$data = $options['monthNames'];} else {for ($m = 1; $m <= 12; $m++) {$data[sprintf("%02s", $m)] = strftime("%m", mktime(1, 1, 1, $m, 1, 1999));}}break;case 'year':$current = intval(date('Y'));$min = !isset($options['min']) ? $current - 20 : (int)$options['min'];$max = !isset($options['max']) ? $current + 20 : (int)$options['max'];if ($min > $max) {list($min, $max) = array($max, $min);}if (!empty($options['value']) && (int)$options['value'] < $min) {$min = (int)$options['value'];} elseif (!empty($options['value']) && (int)$options['value'] > $max) {$max = (int)$options['value'];}for ($i = $min; $i <= $max; $i++) {$data[$i] = $i;}if ($options['order'] !== 'asc') {$data = array_reverse($data, true);}break;}$this->_options[$name] = $data;return $this->_options[$name];}/*** Sets field defaults and adds field to form security input hash.* Will also add a 'form-error' class if the field contains validation errors.** ### Options** - `secure` - boolean whether or not the field should be added to the security fields.* Disabling the field using the `disabled` option, will also omit the field from being* part of the hashed key.** This method will convert a numerically indexed 'disabled' into a associative* value. FormHelper's internals expect associative options.** @param string $field Name of the field to initialize options for.* @param array $options Array of options to append options into.* @return array Array of options for the input.*/protected function _initInputField($field, $options = array()) {if (isset($options['secure'])) {$secure = $options['secure'];unset($options['secure']);} else {$secure = (isset($this->request['_Token']) && !empty($this->request['_Token']));}$disabledIndex = array_search('disabled', $options, true);if (is_int($disabledIndex)) {unset($options[$disabledIndex]);$options['disabled'] = true;}$result = parent::_initInputField($field, $options);if ($this->tagIsInvalid() !== false) {$result = $this->addClass($result, 'form-error');}if (!empty($result['disabled'])) {return $result;}if (!isset($result['required']) &&$this->_introspectModel($this->model(), 'validates', $this->field())) {$result['required'] = true;}if ($secure === self::SECURE_SKIP) {return $result;}$this->_secure($secure, $this->_secureFieldName($options));return $result;}/*** Get the field name for use with _secure().** Parses the name attribute to create a dot separated name value for use* in secured field hash.** @param array $options An array of options possibly containing a name key.* @return string|null*/protected function _secureFieldName($options) {if (isset($options['name'])) {preg_match_all('/\[(.*?)\]/', $options['name'], $matches);if (isset($matches[1])) {return $matches[1];}}return null;}/*** Set/Get inputDefaults for form elements** @param array $defaults New default values* @param boolean Merge with current defaults* @return array inputDefaults*/public function inputDefaults($defaults = null, $merge = false) {if ($defaults !== null) {if ($merge) {$this->_inputDefaults = array_merge($this->_inputDefaults, (array)$defaults);} else {$this->_inputDefaults = (array)$defaults;}}return $this->_inputDefaults;}}