CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Reporting Security Issues
    • Privacy Policy
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Get Involved
    • Issues (GitHub)
    • Bakery
    • Featured Resources
    • Training
    • Meetups
    • My CakePHP
    • CakeFest
    • Newsletter
    • Linkedin
    • YouTube
    • Facebook
    • Twitter
    • Mastodon
    • Help & Support
    • Forum
    • Stack Overflow
    • Slack
    • Paid Support
CakePHP

C CakePHP 1.3 API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 1.3
      • 4.2
      • 4.1
      • 4.0
      • 3.9
      • 3.8
      • 3.7
      • 3.6
      • 3.5
      • 3.4
      • 3.3
      • 3.2
      • 3.1
      • 3.0
      • 2.10
      • 2.9
      • 2.8
      • 2.7
      • 2.6
      • 2.5
      • 2.4
      • 2.3
      • 2.2
      • 2.1
      • 2.0
      • 1.3
      • 1.2

Classes

  • AclBase
  • AclBehavior
  • AclComponent
  • AclNode
  • AclShell
  • Aco
  • AcoAction
  • AjaxHelper
  • ApcEngine
  • ApiShell
  • App
  • AppController
  • AppHelper
  • AppModel
  • Aro
  • AuthComponent
  • BakeShell
  • BakeTask
  • BehaviorCollection
  • Cache
  • CacheEngine
  • CacheHelper
  • CakeErrorController
  • CakeLog
  • CakeRoute
  • CakeSchema
  • CakeSession
  • CakeSocket
  • ClassRegistry
  • Component
  • Configure
  • ConnectionManager
  • ConsoleShell
  • ContainableBehavior
  • Controller
  • ControllerTask
  • CookieComponent
  • DataSource
  • DbAcl
  • DbConfigTask
  • DboMssql
  • DboMysql
  • DboMysqlBase
  • DboMysqli
  • DboOracle
  • DboPostgres
  • DboSource
  • DboSqlite
  • Debugger
  • EmailComponent
  • ErrorHandler
  • ExtractTask
  • File
  • FileEngine
  • FileLog
  • FixtureTask
  • Folder
  • FormHelper
  • Helper
  • HtmlHelper
  • HttpSocket
  • I18n
  • I18nModel
  • I18nShell
  • Inflector
  • IniAcl
  • JavascriptHelper
  • JqueryEngineHelper
  • JsBaseEngineHelper
  • JsHelper
  • L10n
  • MagicDb
  • MagicFileResource
  • MediaView
  • MemcacheEngine
  • Model
  • ModelBehavior
  • ModelTask
  • MootoolsEngineHelper
  • Multibyte
  • NumberHelper
  • Object
  • Overloadable
  • Overloadable2
  • PagesController
  • PaginatorHelper
  • Permission
  • PluginShortRoute
  • PluginTask
  • ProjectTask
  • PrototypeEngineHelper
  • RequestHandlerComponent
  • Router
  • RssHelper
  • Sanitize
  • Scaffold
  • ScaffoldView
  • SchemaShell
  • Security
  • SecurityComponent
  • SessionComponent
  • SessionHelper
  • Set
  • Shell
  • String
  • TemplateTask
  • TestSuiteShell
  • TestTask
  • TextHelper
  • ThemeView
  • TimeHelper
  • TranslateBehavior
  • TreeBehavior
  • Validation
  • View
  • ViewTask
  • XcacheEngine
  • Xml
  • XmlElement
  • XmlHelper
  • XmlManager
  • XmlNode
  • XmlTextNode

Functions

  • mb_encode_mimeheader
  • mb_stripos
  • mb_stristr
  • mb_strlen
  • mb_strpos
  • mb_strrchr
  • mb_strrichr
  • mb_strripos
  • mb_strrpos
  • mb_strstr
  • mb_strtolower
  • mb_strtoupper
  • mb_substr
  • mb_substr_count
   1: <?php
   2: /**
   3:  * Automatic generation of HTML FORMs from given data.
   4:  *
   5:  * Used for scaffolding.
   6:  *
   7:  * PHP versions 4 and 5
   8:  *
   9:  * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  10:  * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
  11:  *
  12:  * Licensed under The MIT License
  13:  * Redistributions of files must retain the above copyright notice.
  14:  *
  15:  * @copyright     Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
  16:  * @link          http://cakephp.org CakePHP(tm) Project
  17:  * @package       cake
  18:  * @subpackage    cake.cake.libs.view.helpers
  19:  * @since         CakePHP(tm) v 0.10.0.1076
  20:  * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
  21:  */
  22: 
  23: /**
  24:  * Form helper library.
  25:  *
  26:  * Automatic generation of HTML FORMs from given data.
  27:  *
  28:  * @package       cake
  29:  * @subpackage    cake.cake.libs.view.helpers
  30:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#Form
  31:  */
  32: class FormHelper extends AppHelper {
  33: 
  34: /**
  35:  * Other helpers used by FormHelper
  36:  *
  37:  * @var array
  38:  * @access public
  39:  */
  40:     var $helpers = array('Html');
  41: 
  42: /**
  43:  * Holds the fields array('field_name' => array('type'=> 'string', 'length'=> 100),
  44:  * primaryKey and validates array('field_name')
  45:  *
  46:  * @access public
  47:  */
  48:     var $fieldset = array();
  49: 
  50: /**
  51:  * Options used by DateTime fields
  52:  *
  53:  * @var array
  54:  */
  55:     var $__options = array(
  56:         'day' => array(), 'minute' => array(), 'hour' => array(),
  57:         'month' => array(), 'year' => array(), 'meridian' => array()
  58:     );
  59: 
  60: /**
  61:  * List of fields created, used with secure forms.
  62:  *
  63:  * @var array
  64:  * @access public
  65:  */
  66:     var $fields = array();
  67: 
  68: /**
  69:  * Defines the type of form being created.  Set by FormHelper::create().
  70:  *
  71:  * @var string
  72:  * @access public
  73:  */
  74:     var $requestType = null;
  75: 
  76: /**
  77:  * The default model being used for the current form.
  78:  *
  79:  * @var string
  80:  * @access public
  81:  */
  82:     var $defaultModel = null;
  83: 
  84: /**
  85:  * Persistent default options used by input(). Set by FormHelper::create().
  86:  *
  87:  * @var array
  88:  * @access protected
  89:  */
  90:     var $_inputDefaults = array();
  91: 
  92: /**
  93:  * The action attribute value of the last created form.
  94:  * Used to make form/request specific hashes for SecurityComponent.
  95:  *
  96:  * @var string
  97:  */
  98:     var $_lastAction = '';
  99: 
 100: /**
 101:  * Introspects model information and extracts information related
 102:  * to validation, field length and field type. Appends information into
 103:  * $this->fieldset.
 104:  *
 105:  * @return Model Returns a model instance
 106:  * @access protected
 107:  */
 108:     function &_introspectModel($model) {
 109:         $object = null;
 110:         if (is_string($model) && strpos($model, '.') !== false) {
 111:             $path = explode('.', $model);
 112:             $model = end($path);
 113:         }
 114: 
 115:         if (ClassRegistry::isKeySet($model)) {
 116:             $object =& ClassRegistry::getObject($model);
 117:         }
 118: 
 119:         if (!empty($object)) {
 120:             $fields = $object->schema();
 121:             foreach ($fields as $key => $value) {
 122:                 unset($fields[$key]);
 123:                 $fields[$key] = $value;
 124:             }
 125: 
 126:             if (!empty($object->hasAndBelongsToMany)) {
 127:                 foreach ($object->hasAndBelongsToMany as $alias => $assocData) {
 128:                     $fields[$alias] = array('type' => 'multiple');
 129:                 }
 130:             }
 131:             $validates = array();
 132:             if (!empty($object->validate)) {
 133:                 foreach ($object->validate as $validateField => $validateProperties) {
 134:                     if ($this->_isRequiredField($validateProperties)) {
 135:                         $validates[] = $validateField;
 136:                     }
 137:                 }
 138:             }
 139:             $defaults = array('fields' => array(), 'key' => 'id', 'validates' => array());
 140:             $key = $object->primaryKey;
 141:             $this->fieldset[$model] = array_merge($defaults, compact('fields', 'key', 'validates'));
 142:         }
 143: 
 144:         return $object;
 145:     }
 146: 
 147: /**
 148:  * Returns if a field is required to be filled based on validation properties from the validating object
 149:  *
 150:  * @return boolean true if field is required to be filled, false otherwise
 151:  * @access protected
 152:  */
 153:     function _isRequiredField($validateProperties) {
 154:         $required = false;
 155:         if (is_array($validateProperties)) {
 156: 
 157:             $dims = Set::countDim($validateProperties);
 158:             if ($dims == 1 || ($dims == 2 && isset($validateProperties['rule']))) {
 159:                 $validateProperties = array($validateProperties);
 160:             }
 161: 
 162:             foreach ($validateProperties as $rule => $validateProp) {
 163:                 if (isset($validateProp['allowEmpty']) && $validateProp['allowEmpty'] === true) {
 164:                     return false;
 165:                 }
 166:                 $rule = isset($validateProp['rule']) ? $validateProp['rule'] : false;
 167:                 $required = $rule || empty($validateProp);
 168:                 if ($required) {
 169:                     break;
 170:                 }
 171:             }
 172:         }
 173:         return $required;
 174:     }
 175: 
 176: /**
 177:  * Returns an HTML FORM element.
 178:  *
 179:  * ### Options:
 180:  *
 181:  * - `type` Form method defaults to POST
 182:  * - `action`  The controller action the form submits to, (optional).
 183:  * - `url`  The url the form submits to. Can be a string or a url array.  If you use 'url'
 184:  *    you should leave 'action' undefined.
 185:  * - `default`  Allows for the creation of Ajax forms. Set this to false to prevent the default event handler.
 186:  *   Will create an onsubmit attribute if it doesn't not exist. If it does, default action suppression
 187:  *   will be appended.
 188:  * - `onsubmit` Used in conjunction with 'default' to create ajax forms.
 189:  * - `inputDefaults` set the default $options for FormHelper::input(). Any options that would
 190:  *    be set when using FormHelper::input() can be set here.  Options set with `inputDefaults`
 191:  *    can be overridden when calling input()
 192:  * - `encoding` Set the accept-charset encoding for the form.  Defaults to `Configure::read('App.encoding')`
 193:  *
 194:  * @access public
 195:  * @param string $model The model object which the form is being defined for
 196:  * @param array $options An array of html attributes and options.
 197:  * @return string An formatted opening FORM tag.
 198:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#Creating-Forms
 199:  */
 200:     function create($model = null, $options = array()) {
 201:         $created = $id = false;
 202:         $append = '';
 203:         $view =& ClassRegistry::getObject('view');
 204: 
 205:         if (is_array($model) && empty($options)) {
 206:             $options = $model;
 207:             $model = null;
 208:         }
 209:         if (empty($model) && $model !== false && !empty($this->params['models'])) {
 210:             $model = $this->params['models'][0];
 211:             $this->defaultModel = $this->params['models'][0];
 212:         } elseif (empty($model) && empty($this->params['models'])) {
 213:             $model = false;
 214:         }
 215: 
 216:         $models = ClassRegistry::keys();
 217:         foreach ($models as $currentModel) {
 218:             if (ClassRegistry::isKeySet($currentModel)) {
 219:                 $currentObject =& ClassRegistry::getObject($currentModel);
 220:                 if (is_a($currentObject, 'Model') && !empty($currentObject->validationErrors)) {
 221:                     $this->validationErrors[Inflector::camelize($currentModel)] =& $currentObject->validationErrors;
 222:                 }
 223:             }
 224:         }
 225: 
 226:         $object = $this->_introspectModel($model);
 227:         $this->setEntity($model . '.', true);
 228: 
 229:         $modelEntity = $this->model();
 230:         if (isset($this->fieldset[$modelEntity]['key'])) {
 231:             $data = $this->fieldset[$modelEntity];
 232:             $recordExists = (
 233:                 isset($this->data[$model]) &&
 234:                 !empty($this->data[$model][$data['key']]) &&
 235:                 !is_array($this->data[$model][$data['key']])
 236:             );
 237: 
 238:             if ($recordExists) {
 239:                 $created = true;
 240:                 $id = $this->data[$model][$data['key']];
 241:             }
 242:         }
 243: 
 244:         $options = array_merge(array(
 245:             'type' => ($created && empty($options['action'])) ? 'put' : 'post',
 246:             'action' => null,
 247:             'url' => null,
 248:             'default' => true,
 249:             'encoding' => strtolower(Configure::read('App.encoding')),
 250:             'inputDefaults' => array()),
 251:         $options);
 252:         $this->_inputDefaults = $options['inputDefaults'];
 253:         unset($options['inputDefaults']);
 254: 
 255:         if (empty($options['url']) || is_array($options['url'])) {
 256:             if (empty($options['url']['controller'])) {
 257:                 if (!empty($model) && $model != $this->defaultModel) {
 258:                     $options['url']['controller'] = Inflector::underscore(Inflector::pluralize($model));
 259:                 } elseif (!empty($this->params['controller'])) {
 260:                     $options['url']['controller'] = Inflector::underscore($this->params['controller']);
 261:                 }
 262:             }
 263:             if (empty($options['action'])) {
 264:                 $options['action'] = $this->params['action'];
 265:             }
 266: 
 267:             $actionDefaults = array(
 268:                 'plugin' => $this->plugin,
 269:                 'controller' => $view->viewPath,
 270:                 'action' => $options['action']
 271:             );
 272:             if (!empty($options['action']) && !isset($options['id'])) {
 273:                 $options['id'] = $this->domId($options['action'] . 'Form');
 274:             }
 275:             $options['action'] = array_merge($actionDefaults, (array)$options['url']);
 276:             if (empty($options['action'][0])) {
 277:                 $options['action'][0] = $id;
 278:             }
 279:         } elseif (is_string($options['url'])) {
 280:             $options['action'] = $options['url'];
 281:         }
 282:         unset($options['url']);
 283: 
 284:         switch (strtolower($options['type'])) {
 285:             case 'get':
 286:                 $htmlAttributes['method'] = 'get';
 287:             break;
 288:             case 'file':
 289:                 $htmlAttributes['enctype'] = 'multipart/form-data';
 290:                 $options['type'] = ($created) ? 'put' : 'post';
 291:             case 'post':
 292:             case 'put':
 293:             case 'delete':
 294:                 $append .= $this->hidden('_method', array(
 295:                     'name' => '_method', 'value' => strtoupper($options['type']), 'id' => null
 296:                 ));
 297:             default:
 298:                 $htmlAttributes['method'] = 'post';
 299:             break;
 300:         }
 301:         $this->requestType = strtolower($options['type']);
 302: 
 303:         $action = $this->url($options['action']);
 304:         unset($options['type'], $options['action']);
 305: 
 306:         if ($options['default'] == false) {
 307:             if (!isset($options['onsubmit'])) {
 308:                 $options['onsubmit'] = '';
 309:             }
 310:             $htmlAttributes['onsubmit'] = $options['onsubmit'] . 'event.returnValue = false; return false;';
 311:         }
 312:         unset($options['default']);
 313: 
 314:         if (!empty($options['encoding'])) {
 315:             $htmlAttributes['accept-charset'] = $options['encoding'];
 316:             unset($options['encoding']);
 317:         }
 318: 
 319:         $htmlAttributes = array_merge($options, $htmlAttributes);
 320: 
 321:         $this->fields = array();
 322:         if (isset($this->params['_Token']) && !empty($this->params['_Token'])) {
 323:             $append .= $this->hidden('_Token.key', array(
 324:                 'value' => $this->params['_Token']['key'], 'id' => 'Token' . mt_rand())
 325:             );
 326:         }
 327: 
 328:         if (!empty($append)) {
 329:             $append = sprintf($this->Html->tags['block'], ' style="display:none;"', $append);
 330:         }
 331: 
 332:         $this->_lastAction($action);
 333:         $this->setEntity($model . '.', true);
 334:         $attributes = sprintf('action="%s" ', $action) . $this->_parseAttributes($htmlAttributes, null, '');
 335:         return sprintf($this->Html->tags['form'], $attributes) . $append;
 336:     }
 337: 
 338: /**
 339:  * Sets the last created form action.
 340:  *
 341:  * @param string|array $url URL.
 342:  * @return void
 343:  */
 344:     function _lastAction($url) {
 345:         $action = FULL_BASE_URL . $url;
 346:         $parts = parse_url($action);
 347:         $this->_lastAction = $parts['path'];
 348:     }
 349: 
 350: /**
 351:  * Closes an HTML form, cleans up values set by FormHelper::create(), and writes hidden
 352:  * input fields where appropriate.
 353:  *
 354:  * If $options is set a form submit button will be created. Options can be either a string or an array.
 355:  *
 356:  * {{{
 357:  * array usage:
 358:  *
 359:  * array('label' => 'save'); value="save"
 360:  * array('label' => 'save', 'name' => 'Whatever'); value="save" name="Whatever"
 361:  * array('name' => 'Whatever'); value="Submit" name="Whatever"
 362:  * array('label' => 'save', 'name' => 'Whatever', 'div' => 'good') <div class="good"> value="save" name="Whatever"
 363:  * array('label' => 'save', 'name' => 'Whatever', 'div' => array('class' => 'good')); <div class="good"> value="save" name="Whatever"
 364:  * }}}
 365:  *
 366:  * @param mixed $options as a string will use $options as the value of button,
 367:  * @return string a closing FORM tag optional submit button.
 368:  * @access public
 369:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#Closing-the-Form
 370:  */
 371:     function end($options = null) {
 372:         if (!empty($this->params['models'])) {
 373:             $models = $this->params['models'][0];
 374:         }
 375:         $out = null;
 376:         $submit = null;
 377: 
 378:         if ($options !== null) {
 379:             $submitOptions = array();
 380:             if (is_string($options)) {
 381:                 $submit = $options;
 382:             } else {
 383:                 if (isset($options['label'])) {
 384:                     $submit = $options['label'];
 385:                     unset($options['label']);
 386:                 }
 387:                 $submitOptions = $options;
 388:             }
 389:             $out .= $this->submit($submit, $submitOptions);
 390:         }
 391:         if (isset($this->params['_Token']) && !empty($this->params['_Token'])) {
 392:             $out .= $this->secure($this->fields);
 393:             $this->fields = array();
 394:         }
 395:         $this->setEntity(null);
 396:         $out .= $this->Html->tags['formend'];
 397: 
 398:         $view =& ClassRegistry::getObject('view');
 399:         $view->modelScope = false;
 400:         return $out;
 401:     }
 402: 
 403: /**
 404:  * Generates a hidden field with a security hash based on the fields used in the form.
 405:  *
 406:  * @param array $fields The list of fields to use when generating the hash
 407:  * @return string A hidden input field with a security hash
 408:  * @access public
 409:  */
 410:     function secure($fields = array()) {
 411:         if (!isset($this->params['_Token']) || empty($this->params['_Token'])) {
 412:             return;
 413:         }
 414:         $locked = array();
 415: 
 416:         foreach ($fields as $key => $value) {
 417:             if (!is_int($key)) {
 418:                 $locked[$key] = $value;
 419:                 unset($fields[$key]);
 420:             }
 421:         }
 422:         sort($fields, SORT_STRING);
 423:         ksort($locked, SORT_STRING);
 424:         $fields += $locked;
 425: 
 426:         $fields = Security::hash(
 427:             $this->_lastAction .
 428:             serialize($fields) .
 429:             Configure::read('Security.salt')
 430:         );
 431:         $locked = implode(array_keys($locked), '|');
 432: 
 433:         $out = $this->hidden('_Token.fields', array(
 434:             'value' => urlencode($fields . ':' . $locked),
 435:             'id' => 'TokenFields' . mt_rand()
 436:         ));
 437:         $out = sprintf($this->Html->tags['block'], ' style="display:none;"', $out);
 438:         return $out;
 439:     }
 440: 
 441: /**
 442:  * Determine which fields of a form should be used for hash.
 443:  * Populates $this->fields
 444:  *
 445:  * @param mixed $field Reference to field to be secured
 446:  * @param mixed $value Field value, if value should not be tampered with.
 447:  * @return void
 448:  * @access private
 449:  */
 450:     function __secure($field = null, $value = null) {
 451:         if (!$field) {
 452:             $view =& ClassRegistry::getObject('view');
 453:             $field = $view->entity();
 454:         } elseif (is_string($field)) {
 455:             $field = Set::filter(explode('.', $field), true);
 456:         }
 457: 
 458:         if (!empty($this->params['_Token']['disabledFields'])) {
 459:             foreach ((array)$this->params['_Token']['disabledFields'] as $disabled) {
 460:                 $disabled = explode('.', $disabled);
 461:                 if (array_values(array_intersect($field, $disabled)) === $disabled) {
 462:                     return;
 463:                 }
 464:             }
 465:         }
 466: 
 467:         $last = end($field);
 468:         if (is_numeric($last) || empty($last)) {
 469:             array_pop($field);
 470:         }
 471: 
 472:         $field = implode('.', $field);
 473:         if (!in_array($field, $this->fields)) {
 474:             if ($value !== null) {
 475:                 return $this->fields[$field] = $value;
 476:             }
 477:             $this->fields[] = $field;
 478:         }
 479:     }
 480: 
 481: /**
 482:  * Returns true if there is an error for the given field, otherwise false
 483:  *
 484:  * @param string $field This should be "Modelname.fieldname"
 485:  * @return boolean If there are errors this method returns true, else false.
 486:  * @access public
 487:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#isFieldError
 488:  */
 489:     function isFieldError($field) {
 490:         $this->setEntity($field);
 491:         return (bool)$this->tagIsInvalid();
 492:     }
 493: 
 494: /**
 495:  * Returns a formatted error message for given FORM field, NULL if no errors.
 496:  *
 497:  * ### Options:
 498:  *
 499:  * - `escape`  bool  Whether or not to html escape the contents of the error.
 500:  * - `wrap`  mixed  Whether or not the error message should be wrapped in a div. If a
 501:  *   string, will be used as the HTML tag to use.
 502:  * - `class` string  The classname for the error message
 503:  *
 504:  * @param string $field A field name, like "Modelname.fieldname"
 505:  * @param mixed $text Error message or array of $options. If array, `attributes` key
 506:  * will get used as html attributes for error container
 507:  * @param array $options Rendering options for <div /> wrapper tag
 508:  * @return string If there are errors this method returns an error message, otherwise null.
 509:  * @access public
 510:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#error
 511:  */
 512:     function error($field, $text = null, $options = array()) {
 513:         $defaults = array('wrap' => true, 'class' => 'error-message', 'escape' => true);
 514:         $options = array_merge($defaults, $options);
 515:         $this->setEntity($field);
 516: 
 517:         $error = $this->tagIsInvalid();
 518:         if ($error !== null) {
 519:             if (is_array($error)) {
 520:                 list(,,$field) = explode('.', $field);
 521:                 if (isset($error[$field])) {
 522:                     $error = $error[$field];
 523:                 } else {
 524:                     return null;
 525:                 }
 526:             }
 527: 
 528:             if (is_array($text) && is_numeric($error) && $error > 0) {
 529:                 $error--;
 530:             }
 531:             if (is_array($text)) {
 532:                 $options = array_merge($options, array_intersect_key($text, $defaults));
 533:                 if (isset($text['attributes']) && is_array($text['attributes'])) {
 534:                     $options = array_merge($options, $text['attributes']);
 535:                 }
 536:                 $text = isset($text[$error]) ? $text[$error] : null;
 537:                 unset($options[$error]);
 538:             }
 539: 
 540:             if ($text !== null) {
 541:                 $error = $text;
 542:             } elseif (is_numeric($error)) {
 543:                 $error = sprintf(__('Error in field %s', true), Inflector::humanize($this->field()));
 544:             }
 545:             if ($options['escape']) {
 546:                 $error = h($error);
 547:                 unset($options['escape']);
 548:             }
 549:             if ($options['wrap']) {
 550:                 $tag = is_string($options['wrap']) ? $options['wrap'] : 'div';
 551:                 unset($options['wrap']);
 552:                 return $this->Html->tag($tag, $error, $options);
 553:             } else {
 554:                 return $error;
 555:             }
 556:         } else {
 557:             return null;
 558:         }
 559:     }
 560: 
 561: /**
 562:  * Returns a formatted LABEL element for HTML FORMs. Will automatically generate
 563:  * a for attribute if one is not provided.
 564:  *
 565:  * @param string $fieldName This should be "Modelname.fieldname"
 566:  * @param string $text Text that will appear in the label field.
 567:  * @param mixed $options An array of HTML attributes, or a string, to be used as a class name.
 568:  * @return string The formatted LABEL element
 569:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#label
 570:  */
 571:     function label($fieldName = null, $text = null, $options = array()) {
 572:         if (empty($fieldName)) {
 573:             $view = ClassRegistry::getObject('view');
 574:             $fieldName = implode('.', $view->entity());
 575:         }
 576: 
 577:         if ($text === null) {
 578:             if (strpos($fieldName, '.') !== false) {
 579:                 $text = array_pop(explode('.', $fieldName));
 580:             } else {
 581:                 $text = $fieldName;
 582:             }
 583:             if (substr($text, -3) == '_id') {
 584:                 $text = substr($text, 0, strlen($text) - 3);
 585:             }
 586:             $text = __(Inflector::humanize(Inflector::underscore($text)), true);
 587:         }
 588: 
 589:         if (is_string($options)) {
 590:             $options = array('class' => $options);
 591:         }
 592: 
 593:         if (isset($options['for'])) {
 594:             $labelFor = $options['for'];
 595:             unset($options['for']);
 596:         } else {
 597:             $labelFor = $this->domId($fieldName);
 598:         }
 599: 
 600:         return sprintf(
 601:             $this->Html->tags['label'],
 602:             $labelFor,
 603:             $this->_parseAttributes($options), $text
 604:         );
 605:     }
 606: 
 607: /**
 608:  * Generate a set of inputs for `$fields`.  If $fields is null the current model
 609:  * will be used.
 610:  *
 611:  * In addition to controller fields output, `$fields` can be used to control legend
 612:  * and fieldset rendering with the `fieldset` and `legend` keys.
 613:  * `$form->inputs(array('legend' => 'My legend'));` Would generate an input set with
 614:  * a custom legend.  You can customize individual inputs through `$fields` as well.
 615:  *
 616:  * {{{
 617:  *  $form->inputs(array(
 618:  *      'name' => array('label' => 'custom label')
 619:  *  ));
 620:  * }}}
 621:  *
 622:  * In addition to fields control, inputs() allows you to use a few additional options.
 623:  *
 624:  * - `fieldset` Set to false to disable the fieldset. If a string is supplied it will be used as
 625:  *    the classname for the fieldset element.
 626:  * - `legend` Set to false to disable the legend for the generated input set. Or supply a string
 627:  *    to customize the legend text.
 628:  *
 629:  * @param mixed $fields An array of fields to generate inputs for, or null.
 630:  * @param array $blacklist a simple array of fields to not create inputs for.
 631:  * @return string Completed form inputs.
 632:  * @access public
 633:  */
 634:     function inputs($fields = null, $blacklist = null) {
 635:         $fieldset = $legend = true;
 636:         $model = $this->model();
 637:         if (is_array($fields)) {
 638:             if (array_key_exists('legend', $fields)) {
 639:                 $legend = $fields['legend'];
 640:                 unset($fields['legend']);
 641:             }
 642: 
 643:             if (isset($fields['fieldset'])) {
 644:                 $fieldset = $fields['fieldset'];
 645:                 unset($fields['fieldset']);
 646:             }
 647:         } elseif ($fields !== null) {
 648:             $fieldset = $legend = $fields;
 649:             if (!is_bool($fieldset)) {
 650:                 $fieldset = true;
 651:             }
 652:             $fields = array();
 653:         }
 654: 
 655:         if (empty($fields)) {
 656:             $fields = array_keys($this->fieldset[$model]['fields']);
 657:         }
 658: 
 659:         if ($legend === true) {
 660:             $actionName = __('New %s', true);
 661:             $isEdit = (
 662:                 strpos($this->action, 'update') !== false ||
 663:                 strpos($this->action, 'edit') !== false
 664:             );
 665:             if ($isEdit) {
 666:                 $actionName = __('Edit %s', true);
 667:             }
 668:             $modelName = Inflector::humanize(Inflector::underscore($model));
 669:             $legend = sprintf($actionName, __($modelName, true));
 670:         }
 671: 
 672:         $out = null;
 673:         foreach ($fields as $name => $options) {
 674:             if (is_numeric($name) && !is_array($options)) {
 675:                 $name = $options;
 676:                 $options = array();
 677:             }
 678:             $entity = explode('.', $name);
 679:             $blacklisted = (
 680:                 is_array($blacklist) &&
 681:                 (in_array($name, $blacklist) || in_array(end($entity), $blacklist))
 682:             );
 683:             if ($blacklisted) {
 684:                 continue;
 685:             }
 686:             $out .= $this->input($name, $options);
 687:         }
 688: 
 689:         if (is_string($fieldset)) {
 690:             $fieldsetClass = sprintf(' class="%s"', $fieldset);
 691:         } else {
 692:             $fieldsetClass = '';
 693:         }
 694: 
 695:         if ($fieldset && $legend) {
 696:             return sprintf(
 697:                 $this->Html->tags['fieldset'],
 698:                 $fieldsetClass,
 699:                 sprintf($this->Html->tags['legend'], $legend) . $out
 700:             );
 701:         } elseif ($fieldset) {
 702:             return sprintf($this->Html->tags['fieldset'], $fieldsetClass, $out);
 703:         } else {
 704:             return $out;
 705:         }
 706:     }
 707: 
 708: /**
 709:  * Generates a form input element complete with label and wrapper div
 710:  *
 711:  * ### Options
 712:  *
 713:  * See each field type method for more information. Any options that are part of
 714:  * $attributes or $options for the different **type** methods can be included in `$options` for input().i
 715:  * Additionally, any unknown keys that are not in the list below, or part of the selected type's options
 716:  * will be treated as a regular html attribute for the generated input.
 717:  *
 718:  * - `type` - Force the type of widget you want. e.g. `type => 'select'`
 719:  * - `label` - Either a string label, or an array of options for the label. See FormHelper::label()
 720:  * - `div` - Either `false` to disable the div, or an array of options for the div.
 721:  *    See HtmlHelper::div() for more options.
 722:  * - `options` - for widgets that take options e.g. radio, select
 723:  * - `error` - control the error message that is produced
 724:  * - `empty` - String or boolean to enable empty select box options.
 725:  * - `before` - Content to place before the label + input.
 726:  * - `after` - Content to place after the label + input.
 727:  * - `between` - Content to place between the label + input.
 728:  * - `format` - format template for element order. Any element that is not in the array, will not be in the output.
 729:  *    - Default input format order: array('before', 'label', 'between', 'input', 'after', 'error')
 730:  *    - Default checkbox format order: array('before', 'input', 'between', 'label', 'after', 'error')
 731:  *    - Hidden input will not be formatted
 732:  *    - Radio buttons cannot have the order of input and label elements controlled with these settings.
 733:  *
 734:  * @param string $fieldName This should be "Modelname.fieldname"
 735:  * @param array $options Each type of input takes different options.
 736:  * @return string Completed form widget.
 737:  * @access public
 738:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#Automagic-Form-Elements
 739:  */
 740:     function input($fieldName, $options = array()) {
 741:         $this->setEntity($fieldName);
 742: 
 743:         $options = array_merge(
 744:             array('before' => null, 'between' => null, 'after' => null, 'format' => null),
 745:             $this->_inputDefaults,
 746:             $options
 747:         );
 748: 
 749:         $modelKey = $this->model();
 750:         $fieldKey = $this->field();
 751:         if (!isset($this->fieldset[$modelKey])) {
 752:             $this->_introspectModel($modelKey);
 753:         }
 754: 
 755:         if (!isset($options['type'])) {
 756:             $magicType = true;
 757:             $options['type'] = 'text';
 758:             if (isset($options['options'])) {
 759:                 $options['type'] = 'select';
 760:             } elseif (in_array($fieldKey, array('psword', 'passwd', 'password'))) {
 761:                 $options['type'] = 'password';
 762:             } elseif (isset($this->fieldset[$modelKey]['fields'][$fieldKey])) {
 763:                 $fieldDef = $this->fieldset[$modelKey]['fields'][$fieldKey];
 764:                 $type = $fieldDef['type'];
 765:                 $primaryKey = $this->fieldset[$modelKey]['key'];
 766:             }
 767: 
 768:             if (isset($type)) {
 769:                 $map = array(
 770:                     'string'  => 'text',     'datetime'  => 'datetime',
 771:                     'boolean' => 'checkbox', 'timestamp' => 'datetime',
 772:                     'text'    => 'textarea', 'time'      => 'time',
 773:                     'date'    => 'date',     'float'     => 'text'
 774:                 );
 775: 
 776:                 if (isset($this->map[$type])) {
 777:                     $options['type'] = $this->map[$type];
 778:                 } elseif (isset($map[$type])) {
 779:                     $options['type'] = $map[$type];
 780:                 }
 781:                 if ($fieldKey == $primaryKey) {
 782:                     $options['type'] = 'hidden';
 783:                 }
 784:             }
 785:             if (preg_match('/_id$/', $fieldKey) && $options['type'] !== 'hidden') {
 786:                 $options['type'] = 'select';
 787:             }
 788: 
 789:             if ($modelKey === $fieldKey) {
 790:                 $options['type'] = 'select';
 791:                 if (!isset($options['multiple'])) {
 792:                     $options['multiple'] = 'multiple';
 793:                 }
 794:             }
 795:         }
 796:         $types = array('checkbox', 'radio', 'select');
 797: 
 798:         if (
 799:             (!isset($options['options']) && in_array($options['type'], $types)) ||
 800:             (isset($magicType) && $options['type'] == 'text')
 801:         ) {
 802:             $view =& ClassRegistry::getObject('view');
 803:             $varName = Inflector::variable(
 804:                 Inflector::pluralize(preg_replace('/_id$/', '', $fieldKey))
 805:             );
 806:             $varOptions = $view->getVar($varName);
 807:             if (is_array($varOptions)) {
 808:                 if ($options['type'] !== 'radio') {
 809:                     $options['type'] = 'select';
 810:                 }
 811:                 $options['options'] = $varOptions;
 812:             }
 813:         }
 814: 
 815:         $autoLength = (!array_key_exists('maxlength', $options) && isset($fieldDef['length']));
 816:         if ($autoLength && $options['type'] == 'text') {
 817:             $options['maxlength'] = $fieldDef['length'];
 818:         }
 819:         if ($autoLength && $fieldDef['type'] == 'float') {
 820:             $options['maxlength'] = array_sum(explode(',', $fieldDef['length']))+1;
 821:         }
 822: 
 823:         $divOptions = array();
 824:         $div = $this->_extractOption('div', $options, true);
 825:         unset($options['div']);
 826: 
 827:         if (!empty($div)) {
 828:             $divOptions['class'] = 'input';
 829:             $divOptions = $this->addClass($divOptions, $options['type']);
 830:             if (is_string($div)) {
 831:                 $divOptions['class'] = $div;
 832:             } elseif (is_array($div)) {
 833:                 $divOptions = array_merge($divOptions, $div);
 834:             }
 835:             if (
 836:                 isset($this->fieldset[$modelKey]) &&
 837:                 in_array($fieldKey, $this->fieldset[$modelKey]['validates'])
 838:             ) {
 839:                 $divOptions = $this->addClass($divOptions, 'required');
 840:             }
 841:             if (!isset($divOptions['tag'])) {
 842:                 $divOptions['tag'] = 'div';
 843:             }
 844:         }
 845: 
 846:         $label = null;
 847:         if (isset($options['label']) && $options['type'] !== 'radio') {
 848:             $label = $options['label'];
 849:             unset($options['label']);
 850:         }
 851: 
 852:         if ($options['type'] === 'radio') {
 853:             $label = false;
 854:             if (isset($options['options'])) {
 855:                 $radioOptions = (array)$options['options'];
 856:                 unset($options['options']);
 857:             }
 858:         }
 859: 
 860:         if ($label !== false) {
 861:             $label = $this->_inputLabel($fieldName, $label, $options);
 862:         }
 863: 
 864:         $error = $this->_extractOption('error', $options, null);
 865:         unset($options['error']);
 866: 
 867:         $selected = $this->_extractOption('selected', $options, null);
 868:         unset($options['selected']);
 869: 
 870:         if (isset($options['rows']) || isset($options['cols'])) {
 871:             $options['type'] = 'textarea';
 872:         }
 873: 
 874:         if ($options['type'] === 'datetime' || $options['type'] === 'date' || $options['type'] === 'time' || $options['type'] === 'select') {
 875:             $options += array('empty' => false);
 876:         }
 877:         if ($options['type'] === 'datetime' || $options['type'] === 'date' || $options['type'] === 'time') {
 878:             $dateFormat = $this->_extractOption('dateFormat', $options, 'MDY');
 879:             $timeFormat = $this->_extractOption('timeFormat', $options, 12);
 880:             unset($options['dateFormat'], $options['timeFormat']);
 881:         }
 882: 
 883:         $type = $options['type'];
 884:         $out = array_merge(
 885:             array('before' => null, 'label' => null, 'between' => null, 'input' => null, 'after' => null, 'error' => null),
 886:             array('before' => $options['before'], 'label' => $label, 'between' => $options['between'], 'after' => $options['after'])
 887:         );
 888:         $format = null;
 889:         if (is_array($options['format']) && in_array('input', $options['format'])) {
 890:             $format = $options['format'];
 891:         }
 892:         unset($options['type'], $options['before'], $options['between'], $options['after'], $options['format']);
 893: 
 894:         switch ($type) {
 895:             case 'hidden':
 896:                 $input = $this->hidden($fieldName, $options);
 897:                 $format = array('input');
 898:                 unset($divOptions);
 899:             break;
 900:             case 'checkbox':
 901:                 $input = $this->checkbox($fieldName, $options);
 902:                 $format = $format ? $format : array('before', 'input', 'between', 'label', 'after', 'error');
 903:             break;
 904:             case 'radio':
 905:                 $input = $this->radio($fieldName, $radioOptions, $options);
 906:             break;
 907:             case 'text':
 908:             case 'password':
 909:             case 'file':
 910:                 $input = $this->{$type}($fieldName, $options);
 911:             break;
 912:             case 'select':
 913:                 $options += array('options' => array());
 914:                 $list = $options['options'];
 915:                 unset($options['options']);
 916:                 $input = $this->select($fieldName, $list, $selected, $options);
 917:             break;
 918:             case 'time':
 919:                 $input = $this->dateTime($fieldName, null, $timeFormat, $selected, $options);
 920:             break;
 921:             case 'date':
 922:                 $input = $this->dateTime($fieldName, $dateFormat, null, $selected, $options);
 923:             break;
 924:             case 'datetime':
 925:                 $input = $this->dateTime($fieldName, $dateFormat, $timeFormat, $selected, $options);
 926:             break;
 927:             case 'textarea':
 928:             default:
 929:                 $input = $this->textarea($fieldName, $options + array('cols' => '30', 'rows' => '6'));
 930:             break;
 931:         }
 932: 
 933:         if ($type != 'hidden' && $error !== false) {
 934:             $errMsg = $this->error($fieldName, $error);
 935:             if ($errMsg) {
 936:                 $divOptions = $this->addClass($divOptions, 'error');
 937:                 $out['error'] = $errMsg;
 938:             }
 939:         }
 940: 
 941:         $out['input'] = $input;
 942:         $format = $format ? $format : array('before', 'label', 'between', 'input', 'after', 'error');
 943:         $output = '';
 944:         foreach ($format as $element) {
 945:             $output .= $out[$element];
 946:             unset($out[$element]);
 947:         }
 948: 
 949:         if (!empty($divOptions['tag'])) {
 950:             $tag = $divOptions['tag'];
 951:             unset($divOptions['tag']);
 952:             $output = $this->Html->tag($tag, $output, $divOptions);
 953:         }
 954:         return $output;
 955:     }
 956: 
 957: /**
 958:  * Extracts a single option from an options array.
 959:  *
 960:  * @param string $name The name of the option to pull out.
 961:  * @param array $options The array of options you want to extract.
 962:  * @param mixed $default The default option value
 963:  * @return the contents of the option or default
 964:  * @access protected
 965:  */
 966:     function _extractOption($name, $options, $default = null) {
 967:         if (array_key_exists($name, $options)) {
 968:             return $options[$name];
 969:         }
 970:         return $default;
 971:     }
 972: 
 973: /**
 974:  * Generate a label for an input() call.
 975:  *
 976:  * @param array $options Options for the label element.
 977:  * @return string Generated label element
 978:  * @access protected
 979:  */
 980:     function _inputLabel($fieldName, $label, $options) {
 981:         $labelAttributes = $this->domId(array(), 'for');
 982:         if ($options['type'] === 'date' || $options['type'] === 'datetime') {
 983:             if (isset($options['dateFormat']) && $options['dateFormat'] === 'NONE') {
 984:                 $labelAttributes['for'] .= 'Hour';
 985:                 $idKey = 'hour';
 986:             } else {
 987:                 $labelAttributes['for'] .= 'Month';
 988:                 $idKey = 'month';
 989:             }
 990:             if (isset($options['id']) && isset($options['id'][$idKey])) {
 991:                 $labelAttributes['for'] = $options['id'][$idKey];
 992:             }
 993:         } elseif ($options['type'] === 'time') {
 994:             $labelAttributes['for'] .= 'Hour';
 995:             if (isset($options['id']) && isset($options['id']['hour'])) {
 996:                 $labelAttributes['for'] = $options['id']['hour'];
 997:             }
 998:         }
 999: 
1000:         if (is_array($label)) {
1001:             $labelText = null;
1002:             if (isset($label['text'])) {
1003:                 $labelText = $label['text'];
1004:                 unset($label['text']);
1005:             }
1006:             $labelAttributes = array_merge($labelAttributes, $label);
1007:         } else {
1008:             $labelText = $label;
1009:         }
1010: 
1011:         if (isset($options['id']) && is_string($options['id'])) {
1012:             $labelAttributes = array_merge($labelAttributes, array('for' => $options['id']));
1013:         }
1014:         return $this->label($fieldName, $labelText, $labelAttributes);
1015:     }
1016: 
1017: /**
1018:  * Creates a checkbox input widget.
1019:  *
1020:  * ### Options:
1021:  *
1022:  * - `value` - the value of the checkbox
1023:  * - `checked` - boolean indicate that this checkbox is checked.
1024:  * - `hiddenField` - boolean to indicate if you want the results of checkbox() to include
1025:  *    a hidden input with a value of ''.
1026:  * - `disabled` - create a disabled input.
1027:  *
1028:  * @param string $fieldName Name of a field, like this "Modelname.fieldname"
1029:  * @param array $options Array of HTML attributes.
1030:  * @return string An HTML text input element.
1031:  * @access public
1032:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#checkbox
1033:  */
1034:     function checkbox($fieldName, $options = array()) {
1035:         $options = $this->_initInputField($fieldName, $options) + array('hiddenField' => true);
1036:         $value = current($this->value());
1037:         $output = "";
1038: 
1039:         if (empty($options['value'])) {
1040:             $options['value'] = 1;
1041:         } elseif (
1042:             (!isset($options['checked']) && !empty($value) && $value === $options['value']) ||
1043:             !empty($options['checked'])
1044:         ) {
1045:             $options['checked'] = 'checked';
1046:         }
1047:         if ($options['hiddenField']) {
1048:             $hiddenOptions = array(
1049:                 'id' => $options['id'] . '_', 'name' => $options['name'],
1050:                 'value' => '0', 'secure' => false
1051:             );
1052:             if (isset($options['disabled']) && $options['disabled'] == true) {
1053:                 $hiddenOptions['disabled'] = 'disabled';
1054:             }
1055:             $output = $this->hidden($fieldName, $hiddenOptions);
1056:         }
1057:         unset($options['hiddenField']);
1058: 
1059:         return $output . sprintf(
1060:             $this->Html->tags['checkbox'],
1061:             $options['name'],
1062:             $this->_parseAttributes($options, array('name'), null, ' ')
1063:         );
1064:     }
1065: 
1066: /**
1067:  * Creates a set of radio widgets. Will create a legend and fieldset
1068:  * by default.  Use $options to control this
1069:  *
1070:  * ### Attributes:
1071:  *
1072:  * - `separator` - define the string in between the radio buttons
1073:  * - `legend` - control whether or not the widget set has a fieldset & legend
1074:  * - `value` - indicate a value that is should be checked
1075:  * - `label` - boolean to indicate whether or not labels for widgets show be displayed
1076:  * - `hiddenField` - boolean to indicate if you want the results of radio() to include
1077:  *    a hidden input with a value of ''. This is useful for creating radio sets that non-continuous
1078:  *
1079:  * @param string $fieldName Name of a field, like this "Modelname.fieldname"
1080:  * @param array $options Radio button options array.
1081:  * @param array $attributes Array of HTML attributes, and special attributes above.
1082:  * @return string Completed radio widget set.
1083:  * @access public
1084:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#radio
1085:  */
1086:     function radio($fieldName, $options = array(), $attributes = array()) {
1087:         $attributes = $this->_initInputField($fieldName, $attributes);
1088:         $legend = false;
1089: 
1090:         if (isset($attributes['legend'])) {
1091:             $legend = $attributes['legend'];
1092:             unset($attributes['legend']);
1093:         } elseif (count($options) > 1) {
1094:             $legend = __(Inflector::humanize($this->field()), true);
1095:         }
1096:         $label = true;
1097: 
1098:         if (isset($attributes['label'])) {
1099:             $label = $attributes['label'];
1100:             unset($attributes['label']);
1101:         }
1102:         $inbetween = null;
1103: 
1104:         if (isset($attributes['separator'])) {
1105:             $inbetween = $attributes['separator'];
1106:             unset($attributes['separator']);
1107:         }
1108: 
1109:         if (isset($attributes['value'])) {
1110:             $value = $attributes['value'];
1111:         } else {
1112:             $value =  $this->value($fieldName);
1113:         }
1114:         $out = array();
1115: 
1116:         $hiddenField = isset($attributes['hiddenField']) ? $attributes['hiddenField'] : true;
1117:         unset($attributes['hiddenField']);
1118: 
1119:         foreach ($options as $optValue => $optTitle) {
1120:             $optionsHere = array('value' => $optValue);
1121: 
1122:             if (isset($value) && $value !== '' && $optValue == $value) {
1123:                 $optionsHere['checked'] = 'checked';
1124:             }
1125:             $parsedOptions = $this->_parseAttributes(
1126:                 array_merge($attributes, $optionsHere),
1127:                 array('name', 'type', 'id'), '', ' '
1128:             );
1129:             $tagName = Inflector::camelize(
1130:                 $attributes['id'] . '_' . Inflector::slug($optValue)
1131:             );
1132: 
1133:             if ($label) {
1134:                 $optTitle =  sprintf($this->Html->tags['label'], $tagName, null, $optTitle);
1135:             }
1136:             $out[] =  sprintf(
1137:                 $this->Html->tags['radio'], $attributes['name'],
1138:                 $tagName, $parsedOptions, $optTitle
1139:             );
1140:         }
1141:         $hidden = null;
1142: 
1143:         if ($hiddenField) {
1144:             if (!isset($value) || $value === '') {
1145:                 $hidden = $this->hidden($fieldName, array(
1146:                     'id' => $attributes['id'] . '_', 'value' => '', 'name' => $attributes['name']
1147:                 ));
1148:             }
1149:         }
1150:         $out = $hidden . implode($inbetween, $out);
1151: 
1152:         if ($legend) {
1153:             $out = sprintf(
1154:                 $this->Html->tags['fieldset'], '',
1155:                 sprintf($this->Html->tags['legend'], $legend) . $out
1156:             );
1157:         }
1158:         return $out;
1159:     }
1160: 
1161: /**
1162:  * Creates a text input widget.
1163:  *
1164:  * @param string $fieldName Name of a field, in the form "Modelname.fieldname"
1165:  * @param array $options Array of HTML attributes.
1166:  * @return string A generated HTML text input element
1167:  * @access public
1168:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#text
1169:  */
1170:     function text($fieldName, $options = array()) {
1171:         $options = $this->_initInputField($fieldName, array_merge(
1172:             array('type' => 'text'), $options
1173:         ));
1174:         return sprintf(
1175:             $this->Html->tags['input'],
1176:             $options['name'],
1177:             $this->_parseAttributes($options, array('name'), null, ' ')
1178:         );
1179:     }
1180: 
1181: /**
1182:  * Creates a password input widget.
1183:  *
1184:  * @param string $fieldName Name of a field, like in the form "Modelname.fieldname"
1185:  * @param array $options Array of HTML attributes.
1186:  * @return string A generated password input.
1187:  * @access public
1188:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#password
1189:  */
1190:     function password($fieldName, $options = array()) {
1191:         $options = $this->_initInputField($fieldName, $options);
1192:         return sprintf(
1193:             $this->Html->tags['password'],
1194:             $options['name'],
1195:             $this->_parseAttributes($options, array('name'), null, ' ')
1196:         );
1197:     }
1198: 
1199: /**
1200:  * Creates a textarea widget.
1201:  *
1202:  * ### Options:
1203:  *
1204:  * - `escape` - Whether or not the contents of the textarea should be escaped. Defaults to true.
1205:  *
1206:  * @param string $fieldName Name of a field, in the form "Modelname.fieldname"
1207:  * @param array $options Array of HTML attributes, and special options above.
1208:  * @return string A generated HTML text input element
1209:  * @access public
1210:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#textarea
1211:  */
1212:     function textarea($fieldName, $options = array()) {
1213:         $options = $this->_initInputField($fieldName, $options);
1214:         $value = null;
1215: 
1216:         if (array_key_exists('value', $options)) {
1217:             $value = $options['value'];
1218:             if (!array_key_exists('escape', $options) || $options['escape'] !== false) {
1219:                 $value = h($value);
1220:             }
1221:             unset($options['value']);
1222:         }
1223:         return sprintf(
1224:             $this->Html->tags['textarea'],
1225:             $options['name'],
1226:             $this->_parseAttributes($options, array('type', 'name'), null, ' '),
1227:             $value
1228:         );
1229:     }
1230: 
1231: /**
1232:  * Creates a hidden input field.
1233:  *
1234:  * @param string $fieldName Name of a field, in the form of "Modelname.fieldname"
1235:  * @param array $options Array of HTML attributes.
1236:  * @return string A generated hidden input
1237:  * @access public
1238:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#hidden
1239:  */
1240:     function hidden($fieldName, $options = array()) {
1241:         $secure = true;
1242: 
1243:         if (isset($options['secure'])) {
1244:             $secure = $options['secure'];
1245:             unset($options['secure']);
1246:         }
1247:         $options = $this->_initInputField($fieldName, array_merge(
1248:             $options, array('secure' => false)
1249:         ));
1250:         $model = $this->model();
1251: 
1252:         if ($fieldName !== '_method' && $model !== '_Token' && $secure) {
1253:             $this->__secure(null, '' . $options['value']);
1254:         }
1255: 
1256:         return sprintf(
1257:             $this->Html->tags['hidden'],
1258:             $options['name'],
1259:             $this->_parseAttributes($options, array('name', 'class'), '', ' ')
1260:         );
1261:     }
1262: 
1263: /**
1264:  * Creates file input widget.
1265:  *
1266:  * @param string $fieldName Name of a field, in the form "Modelname.fieldname"
1267:  * @param array $options Array of HTML attributes.
1268:  * @return string A generated file input.
1269:  * @access public
1270:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#file
1271:  */
1272:     function file($fieldName, $options = array()) {
1273:         $options = array_merge($options, array('secure' => false));
1274:         $options = $this->_initInputField($fieldName, $options);
1275:         $view =& ClassRegistry::getObject('view');
1276:         $field = $view->entity();
1277: 
1278:         foreach (array('name', 'type', 'tmp_name', 'error', 'size') as $suffix) {
1279:             $this->__secure(array_merge($field, array($suffix)));
1280:         }
1281: 
1282:         $attributes = $this->_parseAttributes($options, array('name'), '', ' ');
1283:         return sprintf($this->Html->tags['file'], $options['name'], $attributes);
1284:     }
1285: 
1286: /**
1287:  * Creates a `<button>` tag.  The type attribute defaults to `type="submit"`
1288:  * You can change it to a different value by using `$options['type']`.
1289:  *
1290:  * ### Options:
1291:  *
1292:  * - `escape` - HTML entity encode the $title of the button. Defaults to false.
1293:  *
1294:  * @param string $title The button's caption. Not automatically HTML encoded
1295:  * @param array $options Array of options and HTML attributes.
1296:  * @return string A HTML button tag.
1297:  * @access public
1298:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#button
1299:  */
1300:     function button($title, $options = array()) {
1301:         $options += array('type' => 'submit', 'escape' => false);
1302:         if ($options['escape']) {
1303:             $title = h($title);
1304:         }
1305:         return sprintf(
1306:             $this->Html->tags['button'],
1307:             $options['type'],
1308:             $this->_parseAttributes($options, array('type'), ' ', ''),
1309:             $title
1310:         );
1311:     }
1312: 
1313: /**
1314:  * Creates a submit button element.  This method will generate `<input />` elements that
1315:  * can be used to submit, and reset forms by using $options.  image submits can be created by supplying an
1316:  * image path for $caption.
1317:  *
1318:  * ### Options
1319:  *
1320:  * - `div` - Include a wrapping div?  Defaults to true.  Accepts sub options similar to
1321:  *   FormHelper::input().
1322:  * - `before` - Content to include before the input.
1323:  * - `after` - Content to include after the input.
1324:  * - `type` - Set to 'reset' for reset inputs.  Defaults to 'submit'
1325:  * - Other attributes will be assigned to the input element.
1326:  *
1327:  * ### Options
1328:  *
1329:  * - `div` - Include a wrapping div?  Defaults to true.  Accepts sub options similar to
1330:  *   FormHelper::input().
1331:  * - Other attributes will be assigned to the input element.
1332:  *
1333:  * @param string $caption The label appearing on the button OR if string contains :// or the
1334:  *  extension .jpg, .jpe, .jpeg, .gif, .png use an image if the extension
1335:  *  exists, AND the first character is /, image is relative to webroot,
1336:  *  OR if the first character is not /, image is relative to webroot/img.
1337:  * @param array $options Array of options.  See above.
1338:  * @return string A HTML submit button
1339:  * @access public
1340:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#submit
1341:  */
1342:     function submit($caption = null, $options = array()) {
1343:         if (!is_string($caption) && empty($caption)) {
1344:             $caption = __('Submit', true);
1345:         }
1346:         $out = null;
1347:         $div = true;
1348: 
1349:         if (isset($options['div'])) {
1350:             $div = $options['div'];
1351:             unset($options['div']);
1352:         }
1353:         $options += array('type' => 'submit', 'before' => null, 'after' => null);
1354:         $divOptions = array('tag' => 'div');
1355: 
1356:         if ($div === true) {
1357:             $divOptions['class'] = 'submit';
1358:         } elseif ($div === false) {
1359:             unset($divOptions);
1360:         } elseif (is_string($div)) {
1361:             $divOptions['class'] = $div;
1362:         } elseif (is_array($div)) {
1363:             $divOptions = array_merge(array('class' => 'submit', 'tag' => 'div'), $div);
1364:         }
1365: 
1366:         $before = $options['before'];
1367:         $after = $options['after'];
1368:         unset($options['before'], $options['after']);
1369: 
1370:         if (strpos($caption, '://') !== false) {
1371:             unset($options['type']);
1372:             $out .=  $before . sprintf(
1373:                 $this->Html->tags['submitimage'],
1374:                 $caption,
1375:                 $this->_parseAttributes($options, null, '', ' ')
1376:             ) . $after;
1377:         } elseif (preg_match('/\.(jpg|jpe|jpeg|gif|png|ico)$/', $caption)) {
1378:             unset($options['type']);
1379:             if ($caption{0} !== '/') {
1380:                 $url = $this->webroot(IMAGES_URL . $caption);
1381:             } else {
1382:                 $caption = trim($caption, '/');
1383:                 $url = $this->webroot($caption);
1384:             }
1385:             $out .= $before . sprintf(
1386:                 $this->Html->tags['submitimage'],
1387:                 $this->assetTimestamp($url),
1388:                 $this->_parseAttributes($options, null, '', ' ')
1389:             ) . $after;
1390:         } else {
1391:             $options['value'] = $caption;
1392:             $out .= $before . sprintf(
1393:                 $this->Html->tags['submit'],
1394:                 $this->_parseAttributes($options, null, '', ' ')
1395:             ). $after;
1396:         }
1397: 
1398:         if (isset($divOptions)) {
1399:             $tag = $divOptions['tag'];
1400:             unset($divOptions['tag']);
1401:             $out = $this->Html->tag($tag, $out, $divOptions);
1402:         }
1403:         return $out;
1404:     }
1405: 
1406: /**
1407:  * Returns a formatted SELECT element.
1408:  *
1409:  * ### Attributes:
1410:  *
1411:  * - `showParents` - If included in the array and set to true, an additional option element
1412:  *   will be added for the parent of each option group. You can set an option with the same name
1413:  *   and it's key will be used for the value of the option.
1414:  * - `multiple` - show a multiple select box.  If set to 'checkbox' multiple checkboxes will be
1415:  *   created instead.
1416:  * - `empty` - If true, the empty select option is shown.  If a string,
1417:  *   that string is displayed as the empty element.
1418:  * - `escape` - If true contents of options will be HTML entity encoded. Defaults to true.
1419:  * - `class` - When using multiple = checkbox the classname to apply to the divs. Defaults to 'checkbox'.
1420:  *
1421:  * ### Using options
1422:  *
1423:  * A simple array will create normal options:
1424:  *
1425:  * {{{
1426:  * $options = array(1 => 'one', 2 => 'two);
1427:  * $this->Form->select('Model.field', $options));
1428:  * }}}
1429:  *
1430:  * While a nested options array will create optgroups with options inside them.
1431:  * {{{
1432:  * $options = array(
1433:  *    1 => 'bill',
1434:  *    'fred' => array(
1435:  *        2 => 'fred',
1436:  *        3 => 'fred jr.'
1437:  *     )
1438:  * );
1439:  * $this->Form->select('Model.field', $options);
1440:  * }}}
1441:  *
1442:  * In the above `2 => 'fred'` will not generate an option element.  You should enable the `showParents`
1443:  * attribute to show the fred option.
1444:  *
1445:  * @param string $fieldName Name attribute of the SELECT
1446:  * @param array $options Array of the OPTION elements (as 'value'=>'Text' pairs) to be used in the
1447:  *    SELECT element
1448:  * @param mixed $selected The option selected by default.  If null, the default value
1449:  *   from POST data will be used when available.
1450:  * @param array $attributes The HTML attributes of the select element.
1451:  * @return string Formatted SELECT element
1452:  * @access public
1453:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#select
1454:  */
1455:     function select($fieldName, $options = array(), $selected = null, $attributes = array()) {
1456:         $select = array();
1457:         $style = null;
1458:         $tag = null;
1459:         $attributes += array(
1460:             'class' => null,
1461:             'escape' => true,
1462:             'secure' => null,
1463:             'empty' => '',
1464:             'showParents' => false,
1465:             'hiddenField' => true
1466:         );
1467: 
1468:         $escapeOptions = $this->_extractOption('escape', $attributes);
1469:         $secure = $this->_extractOption('secure', $attributes);
1470:         $showEmpty = $this->_extractOption('empty', $attributes);
1471:         $showParents = $this->_extractOption('showParents', $attributes);
1472:         $hiddenField = $this->_extractOption('hiddenField', $attributes);
1473:         unset($attributes['escape'], $attributes['secure'], $attributes['empty'], $attributes['showParents'], $attributes['hiddenField']);
1474: 
1475:         $attributes = $this->_initInputField($fieldName, array_merge(
1476:             (array)$attributes, array('secure' => false)
1477:         ));
1478: 
1479:         if (is_string($options) && isset($this->__options[$options])) {
1480:             $options = $this->__generateOptions($options);
1481:         } elseif (!is_array($options)) {
1482:             $options = array();
1483:         }
1484:         if (isset($attributes['type'])) {
1485:             unset($attributes['type']);
1486:         }
1487: 
1488:         if (!isset($selected)) {
1489:             $selected = $attributes['value'];
1490:         }
1491: 
1492:         if (!empty($attributes['multiple'])) {
1493:             $style = ($attributes['multiple'] === 'checkbox') ? 'checkbox' : null;
1494:             $template = ($style) ? 'checkboxmultiplestart' : 'selectmultiplestart';
1495:             $tag = $this->Html->tags[$template];
1496:             if ($hiddenField) {
1497:                 $hiddenAttributes = array(
1498:                     'value' => '',
1499:                     'id' => $attributes['id'] . ($style ? '' : '_'),
1500:                     'secure' => false,
1501:                     'name' => $attributes['name']
1502:                 );
1503:                 $select[] = $this->hidden(null, $hiddenAttributes);
1504:             }
1505:         } else {
1506:             $tag = $this->Html->tags['selectstart'];
1507:         }
1508: 
1509:         if (!empty($tag) || isset($template)) {
1510:             if (!isset($secure) || $secure == true) {
1511:                 $this->__secure();
1512:             }
1513:             $select[] = sprintf($tag, $attributes['name'], $this->_parseAttributes(
1514:                 $attributes, array('name', 'value'))
1515:             );
1516:         }
1517:         $emptyMulti = (
1518:             $showEmpty !== null && $showEmpty !== false && !(
1519:                 empty($showEmpty) && (isset($attributes) &&
1520:                 array_key_exists('multiple', $attributes))
1521:             )
1522:         );
1523: 
1524:         if ($emptyMulti) {
1525:             $showEmpty = ($showEmpty === true) ? '' : $showEmpty;
1526:             $options = array_reverse($options, true);
1527:             $options[''] = $showEmpty;
1528:             $options = array_reverse($options, true);
1529:         }
1530: 
1531:         $select = array_merge($select, $this->__selectOptions(
1532:             array_reverse($options, true),
1533:             $selected,
1534:             array(),
1535:             $showParents,
1536:             array('escape' => $escapeOptions, 'style' => $style, 'name' => $attributes['name'], 'class' => $attributes['class'])
1537:         ));
1538: 
1539:         $template = ($style == 'checkbox') ? 'checkboxmultipleend' : 'selectend';
1540:         $select[] = $this->Html->tags[$template];
1541:         return implode("\n", $select);
1542:     }
1543: 
1544: /**
1545:  * Returns a SELECT element for days.
1546:  *
1547:  * ### Attributes:
1548:  *
1549:  * - `empty` - If true, the empty select option is shown.  If a string,
1550:  *   that string is displayed as the empty element.
1551:  *
1552:  * @param string $fieldName Prefix name for the SELECT element
1553:  * @param string $selected Option which is selected.
1554:  * @param array $attributes HTML attributes for the select element
1555:  * @return string A generated day select box.
1556:  * @access public
1557:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#day
1558:  */
1559:     function day($fieldName, $selected = null, $attributes = array()) {
1560:         $attributes += array('empty' => true);
1561:         $selected = $this->__dateTimeSelected('day', $fieldName, $selected, $attributes);
1562: 
1563:         if (strlen($selected) > 2) {
1564:             $selected = date('d', strtotime($selected));
1565:         } elseif ($selected === false) {
1566:             $selected = null;
1567:         }
1568:         return $this->select($fieldName . ".day", $this->__generateOptions('day'), $selected, $attributes);
1569:     }
1570: 
1571: /**
1572:  * Returns a SELECT element for years
1573:  *
1574:  * ### Attributes:
1575:  *
1576:  * - `empty` - If true, the empty select option is shown.  If a string,
1577:  *   that string is displayed as the empty element.
1578:  * - `orderYear` - Ordering of year values in select options.
1579:  *   Possible values 'asc', 'desc'. Default 'desc'
1580:  *
1581:  * @param string $fieldName Prefix name for the SELECT element
1582:  * @param integer $minYear First year in sequence
1583:  * @param integer $maxYear Last year in sequence
1584:  * @param string $selected Option which is selected.
1585:  * @param array $attributes Attribute array for the select elements.
1586:  * @return string Completed year select input
1587:  * @access public
1588:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#year
1589:  */
1590:     function year($fieldName, $minYear = null, $maxYear = null, $selected = null, $attributes = array()) {
1591:         $attributes += array('empty' => true);
1592:         if ((empty($selected) || $selected === true) && $value = $this->value($fieldName)) {
1593:             if (is_array($value)) {
1594:                 extract($value);
1595:                 $selected = $year;
1596:             } else {
1597:                 if (empty($value)) {
1598:                     if (!$attributes['empty'] && !$maxYear) {
1599:                         $selected = 'now';
1600: 
1601:                     } elseif (!$attributes['empty'] && $maxYear && !$selected) {
1602:                         $selected = $maxYear;
1603:                     }
1604:                 } else {
1605:                     $selected = $value;
1606:                 }
1607:             }
1608:         }
1609: 
1610:         if (strlen($selected) > 4 || $selected === 'now') {
1611:             $selected = date('Y', strtotime($selected));
1612:         } elseif ($selected === false) {
1613:             $selected = null;
1614:         }
1615:         $yearOptions = array('min' => $minYear, 'max' => $maxYear, 'order' => 'desc');
1616:         if (isset($attributes['orderYear'])) {
1617:             $yearOptions['order'] = $attributes['orderYear'];
1618:             unset($attributes['orderYear']);
1619:         }
1620:         return $this->select(
1621:             $fieldName . '.year', $this->__generateOptions('year', $yearOptions),
1622:             $selected, $attributes
1623:         );
1624:     }
1625: 
1626: /**
1627:  * Returns a SELECT element for months.
1628:  *
1629:  * ### Attributes:
1630:  *
1631:  * - `monthNames` - If false, 2 digit numbers will be used instead of text.
1632:  *   If a array, the given array will be used.
1633:  * - `empty` - If true, the empty select option is shown.  If a string,
1634:  *   that string is displayed as the empty element.
1635:  *
1636:  * @param string $fieldName Prefix name for the SELECT element
1637:  * @param string $selected Option which is selected.
1638:  * @param array $attributes Attributes for the select element
1639:  * @return string A generated month select dropdown.
1640:  * @access public
1641:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#month
1642:  */
1643:     function month($fieldName, $selected = null, $attributes = array()) {
1644:         $attributes += array('empty' => true);
1645:         $selected = $this->__dateTimeSelected('month', $fieldName, $selected, $attributes);
1646: 
1647:         if (strlen($selected) > 2) {
1648:             $selected = date('m', strtotime($selected));
1649:         } elseif ($selected === false) {
1650:             $selected = null;
1651:         }
1652:         $defaults = array('monthNames' => true);
1653:         $attributes = array_merge($defaults, (array) $attributes);
1654:         $monthNames = $attributes['monthNames'];
1655:         unset($attributes['monthNames']);
1656: 
1657:         return $this->select(
1658:             $fieldName . ".month",
1659:             $this->__generateOptions('month', array('monthNames' => $monthNames)),
1660:             $selected, $attributes
1661:         );
1662:     }
1663: 
1664: /**
1665:  * Returns a SELECT element for hours.
1666:  *
1667:  * ### Attributes:
1668:  *
1669:  * - `empty` - If true, the empty select option is shown.  If a string,
1670:  *   that string is displayed as the empty element.
1671:  *
1672:  * @param string $fieldName Prefix name for the SELECT element
1673:  * @param boolean $format24Hours True for 24 hours format
1674:  * @param string $selected Option which is selected.
1675:  * @param array $attributes List of HTML attributes
1676:  * @return string Completed hour select input
1677:  * @access public
1678:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#hour
1679:  */
1680:     function hour($fieldName, $format24Hours = false, $selected = null, $attributes = array()) {
1681:         $attributes += array('empty' => true);
1682:         $selected = $this->__dateTimeSelected('hour', $fieldName, $selected, $attributes);
1683: 
1684:         if (strlen($selected) > 2) {
1685:             if ($format24Hours) {
1686:                 $selected = date('H', strtotime($selected));
1687:             } else {
1688:                 $selected = date('g', strtotime($selected));
1689:             }
1690:         } elseif ($selected === false) {
1691:             $selected = null;
1692:         }
1693:         return $this->select(
1694:             $fieldName . ".hour",
1695:             $this->__generateOptions($format24Hours ? 'hour24' : 'hour'),
1696:             $selected, $attributes
1697:         );
1698:     }
1699: 
1700: /**
1701:  * Returns a SELECT element for minutes.
1702:  *
1703:  * ### Attributes:
1704:  *
1705:  * - `empty` - If true, the empty select option is shown.  If a string,
1706:  *   that string is displayed as the empty element.
1707:  *
1708:  * @param string $fieldName Prefix name for the SELECT element
1709:  * @param string $selected Option which is selected.
1710:  * @param string $attributes Array of Attributes
1711:  * @return string Completed minute select input.
1712:  * @access public
1713:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#minute
1714:  */
1715:     function minute($fieldName, $selected = null, $attributes = array()) {
1716:         $attributes += array('empty' => true);
1717:         $selected = $this->__dateTimeSelected('min', $fieldName, $selected, $attributes);
1718: 
1719:         if (strlen($selected) > 2) {
1720:             $selected = date('i', strtotime($selected));
1721:         } elseif ($selected === false) {
1722:             $selected = null;
1723:         }
1724:         $minuteOptions = array();
1725: 
1726:         if (isset($attributes['interval'])) {
1727:             $minuteOptions['interval'] = $attributes['interval'];
1728:             unset($attributes['interval']);
1729:         }
1730:         return $this->select(
1731:             $fieldName . ".min", $this->__generateOptions('minute', $minuteOptions),
1732:             $selected, $attributes
1733:         );
1734:     }
1735: 
1736: /**
1737:  * Selects values for dateTime selects.
1738:  *
1739:  * @param string $select Name of element field. ex. 'day'
1740:  * @param string $fieldName Name of fieldName being generated ex. Model.created
1741:  * @param mixed $selected The current selected value.
1742:  * @param array $attributes Array of attributes, must contain 'empty' key.
1743:  * @return string Currently selected value.
1744:  * @access private
1745:  */
1746:     function __dateTimeSelected($select, $fieldName, $selected, $attributes) {
1747:         if ((empty($selected) || $selected === true) && $value = $this->value($fieldName)) {
1748:             if (is_array($value) && isset($value[$select])) {
1749:                 $selected = $value[$select];
1750:             } else {
1751:                 if (empty($value)) {
1752:                     if (!$attributes['empty']) {
1753:                         $selected = 'now';
1754:                     }
1755:                 } else {
1756:                     $selected = $value;
1757:                 }
1758:             }
1759:         }
1760:         return $selected;
1761:     }
1762: 
1763: /**
1764:  * Returns a SELECT element for AM or PM.
1765:  *
1766:  * ### Attributes:
1767:  *
1768:  * - `empty` - If true, the empty select option is shown.  If a string,
1769:  *   that string is displayed as the empty element.
1770:  *
1771:  * @param string $fieldName Prefix name for the SELECT element
1772:  * @param string $selected Option which is selected.
1773:  * @param string $attributes Array of Attributes
1774:  * @param bool $showEmpty Show/Hide an empty option
1775:  * @return string Completed meridian select input
1776:  * @access public
1777:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#meridian
1778:  */
1779:     function meridian($fieldName, $selected = null, $attributes = array()) {
1780:         $attributes += array('empty' => true);
1781:         if ((empty($selected) || $selected === true) && $value = $this->value($fieldName)) {
1782:             if (is_array($value)) {
1783:                 extract($value);
1784:                 $selected = $meridian;
1785:             } else {
1786:                 if (empty($value)) {
1787:                     if (!$attribues['empty']) {
1788:                         $selected = date('a');
1789:                     }
1790:                 } else {
1791:                     $selected = date('a', strtotime($value));
1792:                 }
1793:             }
1794:         }
1795: 
1796:         if ($selected === false) {
1797:             $selected = null;
1798:         }
1799:         return $this->select(
1800:             $fieldName . ".meridian", $this->__generateOptions('meridian'),
1801:             $selected, $attributes
1802:         );
1803:     }
1804: 
1805: /**
1806:  * Returns a set of SELECT elements for a full datetime setup: day, month and year, and then time.
1807:  *
1808:  * ### Attributes:
1809:  *
1810:  * - `monthNames` If false, 2 digit numbers will be used instead of text.
1811:  *   If a array, the given array will be used.
1812:  * - `minYear` The lowest year to use in the year select
1813:  * - `maxYear` The maximum year to use in the year select
1814:  * - `interval` The interval for the minutes select. Defaults to 1
1815:  * - `separator` The contents of the string between select elements. Defaults to '-'
1816:  * - `empty` - If true, the empty select option is shown.  If a string,
1817:  *   that string is displayed as the empty element.
1818:  * - `value` | `default` The default value to be used by the input.  A value in `$this->data`
1819:  *   matching the field name will override this value.  If no default is provided `time()` will be used.
1820:  *
1821:  * @param string $fieldName Prefix name for the SELECT element
1822:  * @param string $dateFormat DMY, MDY, YMD.
1823:  * @param string $timeFormat 12, 24.
1824:  * @param string $selected Option which is selected.
1825:  * @param string $attributes array of Attributes
1826:  * @return string Generated set of select boxes for the date and time formats chosen.
1827:  * @access public
1828:  * @link http://book.cakephp.org/1.3/en/The-Manual/Core-Helpers/Form.html#dateTime
1829:  */
1830:     function dateTime($fieldName, $dateFormat = 'DMY', $timeFormat = '12', $selected = null, $attributes = array()) {
1831:         $attributes += array('empty' => true);
1832:         $year = $month = $day = $hour = $min = $meridian = null;
1833: 
1834:         if (empty($selected)) {
1835:             $selected = $this->value($attributes, $fieldName);
1836:             if (isset($selected['value'])) {
1837:                 $selected = $selected['value'];
1838:             } else {
1839:                 $selected = null;
1840:             }
1841:         }
1842: 
1843:         if ($selected === null && $attributes['empty'] != true) {
1844:             $selected = time();
1845:         }
1846: 
1847:         if (!empty($selected)) {
1848:             if (is_array($selected)) {
1849:                 extract($selected);
1850:             } else {
1851:                 if (is_numeric($selected)) {
1852:                     $selected = strftime('%Y-%m-%d %H:%M:%S', $selected);
1853:                 }
1854:                 $meridian = 'am';
1855:                 $pos = strpos($selected, '-');
1856:                 if ($pos !== false) {
1857:                     $date = explode('-', $selected);
1858:                     $days = explode(' ', $date[2]);
1859:                     $day = $days[0];
1860:                     $month = $date[1];
1861:                     $year = $date[0];
1862:                 } else {
1863:                     $days[1] = $selected;
1864:                 }
1865: 
1866:                 if (!empty($timeFormat)) {
1867:                     $time = explode(':', $days[1]);
1868: 
1869:                     if (($time[0] > 12) && $timeFormat == '12') {
1870:                         $time[0] = $time[0] - 12;
1871:                         $meridian = 'pm';
1872:                     } elseif ($time[0] == '12' && $timeFormat == '12') {
1873:                         $meridian = 'pm';
1874:                     } elseif ($time[0] == '00' && $timeFormat == '12') {
1875:                         $time[0] = 12;
1876:                     } elseif ($time[0] > 12) {
1877:                         $meridian = 'pm';
1878:                     }
1879:                     if ($time[0] == 0 && $timeFormat == '12') {
1880:                         $time[0] = 12;
1881:                     }
1882:                     $hour = $min = null;
1883:                     if (isset($time[1])) {
1884:                         $hour = $time[0];
1885:                         $min = $time[1];
1886:                     }
1887:                 }
1888:             }
1889:         }
1890: 
1891:         $elements = array('Day', 'Month', 'Year', 'Hour', 'Minute', 'Meridian');
1892:         $defaults = array(
1893:             'minYear' => null, 'maxYear' => null, 'separator' => '-',
1894:             'interval' => 1, 'monthNames' => true
1895:         );
1896:         $attributes = array_merge($defaults, (array) $attributes);
1897:         if (isset($attributes['minuteInterval'])) {
1898:             $attributes['interval'] = $attributes['minuteInterval'];
1899:             unset($attributes['minuteInterval']);
1900:         }
1901:         $minYear = $attributes['minYear'];
1902:         $maxYear = $attributes['maxYear'];
1903:         $separator = $attributes['separator'];
1904:         $interval = $attributes['interval'];
1905:         $monthNames = $attributes['monthNames'];
1906:         $attributes = array_diff_key($attributes, $defaults);
1907: 
1908:         if (isset($attributes['id'])) {
1909:             if (is_string($attributes['id'])) {
1910:                 // build out an array version
1911:                 foreach ($elements as $element) {
1912:                     $selectAttrName = 'select' . $element . 'Attr';
1913:                     ${$selectAttrName} = $attributes;
1914:                     ${$selectAttrName}['id'] = $attributes['id'] . $element;
1915:                 }
1916:             } elseif (is_array($attributes['id'])) {
1917:                 // check for missing ones and build selectAttr for each element
1918:                 $attributes['id'] += array(
1919:                     'month' => '', 'year' => '', 'day' => '',
1920:                     'hour' => '', 'minute' => '', 'meridian' => ''
1921:                 );
1922:                 foreach ($elements as $element) {
1923:                     $selectAttrName = 'select' . $element . 'Attr';
1924:                     ${$selectAttrName} = $attributes;
1925:                     ${$selectAttrName}['id'] = $attributes['id'][strtolower($element)];
1926:                 }
1927:             }
1928:         } else {
1929:             // build the selectAttrName with empty id's to pass
1930:             foreach ($elements as $element) {
1931:                 $selectAttrName = 'select' . $element . 'Attr';
1932:                 ${$selectAttrName} = $attributes;
1933:             }
1934:         }
1935: 
1936:         $selects = array();
1937:         foreach (preg_split('//', $dateFormat, -1, PREG_SPLIT_NO_EMPTY) as $char) {
1938:             switch ($char) {
1939:                 case 'Y':
1940:                     $selects[] = $this->year(
1941:                         $fieldName, $minYear, $maxYear, $year, $selectYearAttr
1942:                     );
1943:                 break;
1944:                 case 'M':
1945:                     $selectMonthAttr['monthNames'] = $monthNames;
1946:                     $selects[] = $this->month($fieldName, $month, $selectMonthAttr);
1947:                 break;
1948:                 case 'D':
1949:                     $selects[] = $this->day($fieldName, $day, $selectDayAttr);
1950:                 break;
1951:             }
1952:         }
1953:         $opt = implode($separator, $selects);
1954: 
1955:         if (!empty($interval) && $interval > 1 && !empty($min)) {
1956:             $min = round($min * (1 / $interval)) * $interval;
1957:         }
1958:         $selectMinuteAttr['interval'] = $interval;
1959:         switch ($timeFormat) {
1960:             case '24':
1961:                 $opt .= $this->hour($fieldName, true, $hour, $selectHourAttr) . ':' .
1962:                 $this->minute($fieldName, $min, $selectMinuteAttr);
1963:             break;
1964:             case '12':
1965:                 $opt .= $this->hour($fieldName, false, $hour, $selectHourAttr) . ':' .
1966:                 $this->minute($fieldName, $min, $selectMinuteAttr) . ' ' .
1967:                 $this->meridian($fieldName, $meridian, $selectMeridianAttr);
1968:             break;
1969:             default:
1970:                 $opt .= '';
1971:             break;
1972:         }
1973:         return $opt;
1974:     }
1975: 
1976: /**
1977:  * Gets the input field name for the current tag
1978:  *
1979:  * @param array $options
1980:  * @param string $key
1981:  * @return array
1982:  * @access protected
1983:  */
1984:     function _name($options = array(), $field = null, $key = 'name') {
1985:         if ($this->requestType == 'get') {
1986:             if ($options === null) {
1987:                 $options = array();
1988:             } elseif (is_string($options)) {
1989:                 $field = $options;
1990:                 $options = 0;
1991:             }
1992: 
1993:             if (!empty($field)) {
1994:                 $this->setEntity($field);
1995:             }
1996: 
1997:             if (is_array($options) && isset($options[$key])) {
1998:                 return $options;
1999:             }
2000: 
2001:             $view = ClassRegistry::getObject('view');
2002:             $name = !empty($view->field) ? $view->field : $view->model;
2003:             if (!empty($view->fieldSuffix)) {
2004:                 $name .= '[' . $view->fieldSuffix . ']';
2005:             }
2006: 
2007:             if (is_array($options)) {
2008:                 $options[$key] = $name;
2009:                 return $options;
2010:             } else {
2011:                 return $name;
2012:             }
2013:         }
2014:         return parent::_name($options, $field, $key);
2015:     }
2016: 
2017: /**
2018:  * Returns an array of formatted OPTION/OPTGROUP elements
2019:  * @access private
2020:  * @return array
2021:  */
2022:     function __selectOptions($elements = array(), $selected = null, $parents = array(), $showParents = null, $attributes = array()) {
2023:         $select = array();
2024:         $attributes = array_merge(array('escape' => true, 'style' => null, 'class' => null), $attributes);
2025:         $selectedIsEmpty = ($selected === '' || $selected === null);
2026:         $selectedIsArray = is_array($selected);
2027: 
2028:         foreach ($elements as $name => $title) {
2029:             $htmlOptions = array();
2030:             if (is_array($title) && (!isset($title['name']) || !isset($title['value']))) {
2031:                 if (!empty($name)) {
2032:                     if ($attributes['style'] === 'checkbox') {
2033:                         $select[] = $this->Html->tags['fieldsetend'];
2034:                     } else {
2035:                         $select[] = $this->Html->tags['optiongroupend'];
2036:                     }
2037:                     $parents[] = $name;
2038:                 }
2039:                 $select = array_merge($select, $this->__selectOptions(
2040:                     $title, $selected, $parents, $showParents, $attributes
2041:                 ));
2042: 
2043:                 if (!empty($name)) {
2044:                     $name = $attributes['escape'] ? h($name) : $name;
2045:                     if ($attributes['style'] === 'checkbox') {
2046:                         $select[] = sprintf($this->Html->tags['fieldsetstart'], $name);
2047:                     } else {
2048:                         $select[] = sprintf($this->Html->tags['optiongroup'], $name, '');
2049:                     }
2050:                 }
2051:                 $name = null;
2052:             } elseif (is_array($title)) {
2053:                 $htmlOptions = $title;
2054:                 $name = $title['value'];
2055:                 $title = $title['name'];
2056:                 unset($htmlOptions['name'], $htmlOptions['value']);
2057:             }
2058: 
2059:             if ($name !== null) {
2060:                 if (
2061:                     (!$selectedIsArray && !$selectedIsEmpty && (string)$selected == (string)$name) ||
2062:                     ($selectedIsArray && in_array($name, $selected))
2063:                 ) {
2064:                     if ($attributes['style'] === 'checkbox') {
2065:                         $htmlOptions['checked'] = true;
2066:                     } else {
2067:                         $htmlOptions['selected'] = 'selected';
2068:                     }
2069:                 }
2070: 
2071:                 if ($showParents || (!in_array($title, $parents))) {
2072:                     $title = ($attributes['escape']) ? h($title) : $title;
2073: 
2074:                     if ($attributes['style'] === 'checkbox') {
2075:                         $htmlOptions['value'] = $name;
2076: 
2077:                         $tagName = Inflector::camelize(
2078:                             $this->model() . '_' . $this->field().'_'.Inflector::slug($name)
2079:                         );
2080:                         $htmlOptions['id'] = $tagName;
2081:                         $label = array('for' => $tagName);
2082: 
2083:                         if (isset($htmlOptions['checked']) && $htmlOptions['checked'] === true) {
2084:                             $label['class'] = 'selected';
2085:                         }
2086: 
2087:                         $name = $attributes['name'];
2088: 
2089:                         if (empty($attributes['class'])) {
2090:                             $attributes['class'] = 'checkbox';
2091:                         } elseif ($attributes['class'] === 'form-error') {
2092:                             $attributes['class'] = 'checkbox ' . $attributes['class'];
2093:                         }
2094:                         $label = $this->label(null, $title, $label);
2095:                         $item = sprintf(
2096:                             $this->Html->tags['checkboxmultiple'], $name,
2097:                             $this->_parseAttributes($htmlOptions)
2098:                         );
2099:                         $select[] = $this->Html->div($attributes['class'], $item . $label);
2100:                     } else {
2101:                         $select[] = sprintf(
2102:                             $this->Html->tags['selectoption'],
2103:                             $name, $this->_parseAttributes($htmlOptions), $title
2104:                         );
2105:                     }
2106:                 }
2107:             }
2108:         }
2109: 
2110:         return array_reverse($select, true);
2111:     }
2112: 
2113: /**
2114:  * Generates option lists for common <select /> menus
2115:  * @access private
2116:  */
2117:     function __generateOptions($name, $options = array()) {
2118:         if (!empty($this->options[$name])) {
2119:             return $this->options[$name];
2120:         }
2121:         $data = array();
2122: 
2123:         switch ($name) {
2124:             case 'minute':
2125:                 if (isset($options['interval'])) {
2126:                     $interval = $options['interval'];
2127:                 } else {
2128:                     $interval = 1;
2129:                 }
2130:                 $i = 0;
2131:                 while ($i < 60) {
2132:                     $data[sprintf('%02d', $i)] = sprintf('%02d', $i);
2133:                     $i += $interval;
2134:                 }
2135:             break;
2136:             case 'hour':
2137:                 for ($i = 1; $i <= 12; $i++) {
2138:                     $data[sprintf('%02d', $i)] = $i;
2139:                 }
2140:             break;
2141:             case 'hour24':
2142:                 for ($i = 0; $i <= 23; $i++) {
2143:                     $data[sprintf('%02d', $i)] = $i;
2144:                 }
2145:             break;
2146:             case 'meridian':
2147:                 $data = array('am' => 'am', 'pm' => 'pm');
2148:             break;
2149:             case 'day':
2150:                 $min = 1;
2151:                 $max = 31;
2152: 
2153:                 if (isset($options['min'])) {
2154:                     $min = $options['min'];
2155:                 }
2156:                 if (isset($options['max'])) {
2157:                     $max = $options['max'];
2158:                 }
2159: 
2160:                 for ($i = $min; $i <= $max; $i++) {
2161:                     $data[sprintf('%02d', $i)] = $i;
2162:                 }
2163:             break;
2164:             case 'month':
2165:                 if ($options['monthNames'] === true) {
2166:                     $data['01'] = __('January', true);
2167:                     $data['02'] = __('February', true);
2168:                     $data['03'] = __('March', true);
2169:                     $data['04'] = __('April', true);
2170:                     $data['05'] = __('May', true);
2171:                     $data['06'] = __('June', true);
2172:                     $data['07'] = __('July', true);
2173:                     $data['08'] = __('August', true);
2174:                     $data['09'] = __('September', true);
2175:                     $data['10'] = __('October', true);
2176:                     $data['11'] = __('November', true);
2177:                     $data['12'] = __('December', true);
2178:                 } else if (is_array($options['monthNames'])) {
2179:                     $data = $options['monthNames'];
2180:                 } else {
2181:                     for ($m = 1; $m <= 12; $m++) {
2182:                         $data[sprintf("%02s", $m)] = strftime("%m", mktime(1, 1, 1, $m, 1, 1999));
2183:                     }
2184:                 }
2185:             break;
2186:             case 'year':
2187:                 $current = intval(date('Y'));
2188: 
2189:                 if (!isset($options['min'])) {
2190:                     $min = $current - 20;
2191:                 } else {
2192:                     $min = $options['min'];
2193:                 }
2194: 
2195:                 if (!isset($options['max'])) {
2196:                     $max = $current + 20;
2197:                 } else {
2198:                     $max = $options['max'];
2199:                 }
2200:                 if ($min > $max) {
2201:                     list($min, $max) = array($max, $min);
2202:                 }
2203:                 for ($i = $min; $i <= $max; $i++) {
2204:                     $data[$i] = $i;
2205:                 }
2206:                 if ($options['order'] != 'asc') {
2207:                     $data = array_reverse($data, true);
2208:                 }
2209:             break;
2210:         }
2211:         $this->__options[$name] = $data;
2212:         return $this->__options[$name];
2213:     }
2214: 
2215: /**
2216:  * Sets field defaults and adds field to form security input hash
2217:  *
2218:  * Options
2219:  *
2220:  *  - `secure` - boolean whether or not the field should be added to the security fields.
2221:  *
2222:  * @param string $field Name of the field to initialize options for.
2223:  * @param array $options Array of options to append options into.
2224:  * @return array Array of options for the input.
2225:  * @access protected
2226:  */
2227:     function _initInputField($field, $options = array()) {
2228:         if (isset($options['secure'])) {
2229:             $secure = $options['secure'];
2230:             unset($options['secure']);
2231:         } else {
2232:             $secure = (isset($this->params['_Token']) && !empty($this->params['_Token']));
2233:         }
2234: 
2235:         $fieldName = null;
2236:         if ($secure && !empty($options['name'])) {
2237:             preg_match_all('/\[(.*?)\]/', $options['name'], $matches);
2238:             if (isset($matches[1])) {
2239:                 $fieldName = $matches[1];
2240:             }
2241:         }
2242: 
2243:         $result = parent::_initInputField($field, $options);
2244: 
2245:         if ($secure) {
2246:             $this->__secure($fieldName);
2247:         }
2248:         return $result;
2249:     }
2250: }
2251: 
OpenHub
Rackspace
Rackspace
  • Business Solutions
  • Showcase
  • Documentation
  • Book
  • API
  • Videos
  • Reporting Security Issues
  • Privacy Policy
  • Logos & Trademarks
  • Community
  • Get Involved
  • Issues (GitHub)
  • Bakery
  • Featured Resources
  • Training
  • Meetups
  • My CakePHP
  • CakeFest
  • Newsletter
  • Linkedin
  • YouTube
  • Facebook
  • Twitter
  • Mastodon
  • Help & Support
  • Forum
  • Stack Overflow
  • Slack
  • Paid Support

Generated using CakePHP API Docs