1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
16:
17: App::uses('ClassRegistry', 'Utility');
18: App::uses('AppHelper', 'View/Helper');
19: App::uses('Hash', 'Utility');
20: App::uses('Inflector', 'Utility');
21:
22: 23: 24: 25: 26: 27: 28: 29: 30:
31: class FormHelper extends AppHelper {
32:
33: 34: 35: 36: 37:
38: public $helpers = array('Html');
39:
40: 41: 42: 43: 44:
45: protected $_options = array(
46: 'day' => array(), 'minute' => array(), 'hour' => array(),
47: 'month' => array(), 'year' => array(), 'meridian' => array()
48: );
49:
50: 51: 52: 53: 54:
55: public $fields = array();
56:
57: 58: 59: 60: 61: 62:
63: const SECURE_SKIP = 'skip';
64:
65: 66: 67: 68: 69:
70: public $requestType = null;
71:
72: 73: 74: 75: 76:
77: public $defaultModel = null;
78:
79: 80: 81: 82: 83:
84: protected $_inputDefaults = array();
85:
86: 87: 88: 89: 90: 91: 92: 93:
94: protected $_unlockedFields = array();
95:
96: 97: 98: 99: 100: 101:
102: protected $_models = array();
103:
104: 105: 106: 107: 108: 109: 110:
111: public $validationErrors = array();
112:
113: 114: 115: 116: 117:
118: protected $_domIdSuffixes = array();
119:
120: 121: 122: 123: 124: 125:
126: protected $_lastAction = '';
127:
128: 129: 130: 131: 132: 133:
134: public function __construct(View $View, $settings = array()) {
135: parent::__construct($View, $settings);
136: $this->validationErrors =& $View->validationErrors;
137: }
138:
139: 140: 141: 142: 143: 144: 145:
146: protected function _getModel($model) {
147: $object = null;
148: if (!$model || $model === 'Model') {
149: return $object;
150: }
151:
152: if (array_key_exists($model, $this->_models)) {
153: return $this->_models[$model];
154: }
155:
156: if (ClassRegistry::isKeySet($model)) {
157: $object = ClassRegistry::getObject($model);
158: } elseif (isset($this->request->params['models'][$model])) {
159: $plugin = $this->request->params['models'][$model]['plugin'];
160: $plugin .= ($plugin) ? '.' : null;
161: $object = ClassRegistry::init(array(
162: 'class' => $plugin . $this->request->params['models'][$model]['className'],
163: 'alias' => $model
164: ));
165: } elseif (ClassRegistry::isKeySet($this->defaultModel)) {
166: $defaultObject = ClassRegistry::getObject($this->defaultModel);
167: if ($defaultObject && in_array($model, array_keys($defaultObject->getAssociated()), true) && isset($defaultObject->{$model})) {
168: $object = $defaultObject->{$model};
169: }
170: } else {
171: $object = ClassRegistry::init($model, true);
172: }
173:
174: $this->_models[$model] = $object;
175: if (!$object) {
176: return null;
177: }
178:
179: $this->fieldset[$model] = array('fields' => null, 'key' => $object->primaryKey, 'validates' => null);
180: return $object;
181: }
182:
183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202:
203: protected function _introspectModel($model, $key, $field = null) {
204: $object = $this->_getModel($model);
205: if (!$object) {
206: return;
207: }
208:
209: if ($key === 'key') {
210: return $this->fieldset[$model]['key'] = $object->primaryKey;
211: }
212:
213: if ($key === 'fields') {
214: if (!isset($this->fieldset[$model]['fields'])) {
215: $this->fieldset[$model]['fields'] = $object->schema();
216: foreach ($object->hasAndBelongsToMany as $alias => $assocData) {
217: $this->fieldset[$object->alias]['fields'][$alias] = array('type' => 'multiple');
218: }
219: }
220: if ($field === null || $field === false) {
221: return $this->fieldset[$model]['fields'];
222: } elseif (isset($this->fieldset[$model]['fields'][$field])) {
223: return $this->fieldset[$model]['fields'][$field];
224: }
225: return isset($object->hasAndBelongsToMany[$field]) ? array('type' => 'multiple') : null;
226: }
227:
228: if ($key === 'errors' && !isset($this->validationErrors[$model])) {
229: $this->validationErrors[$model] =& $object->validationErrors;
230: return $this->validationErrors[$model];
231: } elseif ($key === 'errors' && isset($this->validationErrors[$model])) {
232: return $this->validationErrors[$model];
233: }
234:
235: if ($key === 'validates' && !isset($this->fieldset[$model]['validates'])) {
236: $validates = array();
237: foreach (iterator_to_array($object->validator(), true) as $validateField => $validateProperties) {
238: if ($this->_isRequiredField($validateProperties)) {
239: $validates[$validateField] = true;
240: }
241: }
242: $this->fieldset[$model]['validates'] = $validates;
243: }
244:
245: if ($key === 'validates') {
246: if (empty($field)) {
247: return $this->fieldset[$model]['validates'];
248: }
249: return isset($this->fieldset[$model]['validates'][$field]) ?
250: $this->fieldset[$model]['validates'] : null;
251: }
252: }
253:
254: 255: 256: 257: 258: 259:
260: protected function _isRequiredField($validationRules) {
261: if (empty($validationRules) || count($validationRules) === 0) {
262: return false;
263: }
264:
265: $isUpdate = $this->requestType === 'put';
266: foreach ($validationRules as $rule) {
267: $rule->isUpdate($isUpdate);
268: if ($rule->skip()) {
269: continue;
270: }
271:
272: return !$rule->allowEmpty;
273: }
274: return false;
275: }
276:
277: 278: 279: 280: 281: 282: 283: 284:
285: public function tagIsInvalid() {
286: $entity = $this->entity();
287: $model = array_shift($entity);
288:
289:
290: if (empty($model) || is_numeric($model)) {
291: array_splice($entity, 1, 0, $model);
292: $model = array_shift($entity);
293: }
294:
295: $errors = array();
296: if (!empty($entity) && isset($this->validationErrors[$model])) {
297: $errors = $this->validationErrors[$model];
298: }
299: if (!empty($entity) && empty($errors)) {
300: $errors = $this->_introspectModel($model, 'errors');
301: }
302: if (empty($errors)) {
303: return false;
304: }
305: $errors = Hash::get($errors, implode('.', $entity));
306: return $errors === null ? false : $errors;
307: }
308:
309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334:
335: public function create($model = null, $options = array()) {
336: $created = $id = false;
337: $append = '';
338:
339: if (is_array($model) && empty($options)) {
340: $options = $model;
341: $model = null;
342: }
343:
344: if (empty($model) && $model !== false && !empty($this->request->params['models'])) {
345: $model = key($this->request->params['models']);
346: } elseif (empty($model) && empty($this->request->params['models'])) {
347: $model = false;
348: }
349: $this->defaultModel = $model;
350:
351: $key = null;
352: if ($model !== false) {
353: list($plugin, $model) = pluginSplit($model, true);
354: $key = $this->_introspectModel($plugin . $model, 'key');
355: $this->setEntity($model, true);
356: }
357:
358: if ($model !== false && $key) {
359: $recordExists = (
360: isset($this->request->data[$model]) &&
361: !empty($this->request->data[$model][$key]) &&
362: !is_array($this->request->data[$model][$key])
363: );
364:
365: if ($recordExists) {
366: $created = true;
367: $id = $this->request->data[$model][$key];
368: }
369: }
370:
371: $options = array_merge(array(
372: 'type' => ($created && empty($options['action'])) ? 'put' : 'post',
373: 'action' => null,
374: 'url' => null,
375: 'default' => true,
376: 'encoding' => strtolower(Configure::read('App.encoding')),
377: 'inputDefaults' => array()),
378: $options);
379: $this->inputDefaults($options['inputDefaults']);
380: unset($options['inputDefaults']);
381:
382: if (!isset($options['id'])) {
383: $domId = isset($options['action']) ? $options['action'] : $this->request['action'];
384: $options['id'] = $this->domId($domId . 'Form');
385: }
386:
387: if ($options['action'] === null && $options['url'] === null) {
388: $options['action'] = $this->request->here(false);
389: } elseif (empty($options['url']) || is_array($options['url'])) {
390: if (empty($options['url']['controller'])) {
391: if (!empty($model)) {
392: $options['url']['controller'] = Inflector::underscore(Inflector::pluralize($model));
393: } elseif (!empty($this->request->params['controller'])) {
394: $options['url']['controller'] = Inflector::underscore($this->request->params['controller']);
395: }
396: }
397: if (empty($options['action'])) {
398: $options['action'] = $this->request->params['action'];
399: }
400:
401: $plugin = null;
402: if ($this->plugin) {
403: $plugin = Inflector::underscore($this->plugin);
404: }
405: $actionDefaults = array(
406: 'plugin' => $plugin,
407: 'controller' => $this->_View->viewPath,
408: 'action' => $options['action'],
409: );
410: $options['action'] = array_merge($actionDefaults, (array)$options['url']);
411: if (empty($options['action'][0]) && !empty($id)) {
412: $options['action'][0] = $id;
413: }
414: } elseif (is_string($options['url'])) {
415: $options['action'] = $options['url'];
416: }
417: unset($options['url']);
418:
419: switch (strtolower($options['type'])) {
420: case 'get':
421: $htmlAttributes['method'] = 'get';
422: break;
423: case 'file':
424: $htmlAttributes['enctype'] = 'multipart/form-data';
425: $options['type'] = ($created) ? 'put' : 'post';
426: case 'post':
427: case 'put':
428: case 'delete':
429: $append .= $this->hidden('_method', array(
430: 'name' => '_method', 'value' => strtoupper($options['type']), 'id' => null,
431: 'secure' => self::SECURE_SKIP
432: ));
433: default:
434: $htmlAttributes['method'] = 'post';
435: }
436: $this->requestType = strtolower($options['type']);
437:
438: $action = $this->url($options['action']);
439: unset($options['type'], $options['action']);
440:
441: if (!$options['default']) {
442: if (!isset($options['onsubmit'])) {
443: $options['onsubmit'] = '';
444: }
445: $htmlAttributes['onsubmit'] = $options['onsubmit'] . 'event.returnValue = false; return false;';
446: }
447: unset($options['default']);
448:
449: if (!empty($options['encoding'])) {
450: $htmlAttributes['accept-charset'] = $options['encoding'];
451: unset($options['encoding']);
452: }
453:
454: $htmlAttributes = array_merge($options, $htmlAttributes);
455:
456: $this->fields = array();
457: if ($this->requestType !== 'get') {
458: $append .= $this->_csrfField();
459: }
460:
461: if (!empty($append)) {
462: $append = $this->Html->useTag('hiddenblock', $append);
463: }
464:
465: if ($model !== false) {
466: $this->setEntity($model, true);
467: $this->_introspectModel($model, 'fields');
468: }
469:
470: $this->_lastAction = $action;
471: if (strpos($action, '://')) {
472: $query = parse_url($action, PHP_URL_QUERY);
473: $query = $query ? '?' . $query : '';
474: $this->_lastAction = parse_url($action, PHP_URL_PATH) . $query;
475: }
476:
477: return $this->Html->useTag('form', $action, $htmlAttributes) . $append;
478: }
479:
480: 481: 482: 483: 484: 485:
486: protected function _csrfField() {
487: if (empty($this->request->params['_Token'])) {
488: return '';
489: }
490: if (!empty($this->request['_Token']['unlockedFields'])) {
491: foreach ((array)$this->request['_Token']['unlockedFields'] as $unlocked) {
492: $this->_unlockedFields[] = $unlocked;
493: }
494: }
495: return $this->hidden('_Token.key', array(
496: 'value' => $this->request->params['_Token']['key'], 'id' => 'Token' . mt_rand(),
497: 'secure' => self::SECURE_SKIP
498: ));
499: }
500:
501: 502: 503: 504: 505: 506: 507: 508: 509: 510: 511: 512: 513: 514: 515: 516: 517: 518: 519: 520:
521: public function end($options = null) {
522: $out = null;
523: $submit = null;
524:
525: if ($options !== null) {
526: $submitOptions = array();
527: if (is_string($options)) {
528: $submit = $options;
529: } else {
530: if (isset($options['label'])) {
531: $submit = $options['label'];
532: unset($options['label']);
533: }
534: $submitOptions = $options;
535: }
536: $out .= $this->submit($submit, $submitOptions);
537: }
538: if (
539: $this->requestType !== 'get' &&
540: isset($this->request['_Token']) &&
541: !empty($this->request['_Token'])
542: ) {
543: $out .= $this->secure($this->fields);
544: $this->fields = array();
545: }
546: $this->setEntity(null);
547: $out .= $this->Html->useTag('formend');
548:
549: $this->_View->modelScope = false;
550: $this->requestType = null;
551: return $out;
552: }
553:
554: 555: 556: 557: 558: 559: 560:
561: public function secure($fields = array()) {
562: if (!isset($this->request['_Token']) || empty($this->request['_Token'])) {
563: return;
564: }
565: $locked = array();
566: $unlockedFields = $this->_unlockedFields;
567:
568: foreach ($fields as $key => $value) {
569: if (!is_int($key)) {
570: $locked[$key] = $value;
571: unset($fields[$key]);
572: }
573: }
574:
575: sort($unlockedFields, SORT_STRING);
576: sort($fields, SORT_STRING);
577: ksort($locked, SORT_STRING);
578: $fields += $locked;
579:
580: $locked = implode(array_keys($locked), '|');
581: $unlocked = implode($unlockedFields, '|');
582: $hashParts = array(
583: $this->_lastAction,
584: serialize($fields),
585: $unlocked,
586: Configure::read('Security.salt')
587: );
588: $fields = Security::hash(implode('', $hashParts), 'sha1');
589:
590: $out = $this->hidden('_Token.fields', array(
591: 'value' => urlencode($fields . ':' . $locked),
592: 'id' => 'TokenFields' . mt_rand()
593: ));
594: $out .= $this->hidden('_Token.unlocked', array(
595: 'value' => urlencode($unlocked),
596: 'id' => 'TokenUnlocked' . mt_rand()
597: ));
598: return $this->Html->useTag('hiddenblock', $out);
599: }
600:
601: 602: 603: 604: 605: 606: 607: 608: 609: 610:
611: public function unlockField($name = null) {
612: if ($name === null) {
613: return $this->_unlockedFields;
614: }
615: if (!in_array($name, $this->_unlockedFields)) {
616: $this->_unlockedFields[] = $name;
617: }
618: $index = array_search($name, $this->fields);
619: if ($index !== false) {
620: unset($this->fields[$index]);
621: }
622: unset($this->fields[$name]);
623: }
624:
625: 626: 627: 628: 629: 630: 631: 632: 633: 634:
635: protected function _secure($lock, $field = null, $value = null) {
636: if (!$field) {
637: $field = $this->entity();
638: } elseif (is_string($field)) {
639: $field = Hash::filter(explode('.', $field));
640: }
641:
642: foreach ($this->_unlockedFields as $unlockField) {
643: $unlockParts = explode('.', $unlockField);
644: if (array_values(array_intersect($field, $unlockParts)) === $unlockParts) {
645: return;
646: }
647: }
648:
649: $field = implode('.', $field);
650: $field = preg_replace('/(\.\d+)+$/', '', $field);
651:
652: if ($lock) {
653: if (!in_array($field, $this->fields)) {
654: if ($value !== null) {
655: return $this->fields[$field] = $value;
656: }
657: $this->fields[] = $field;
658: }
659: } else {
660: $this->unlockField($field);
661: }
662: }
663:
664: 665: 666: 667: 668: 669: 670:
671: public function isFieldError($field) {
672: $this->setEntity($field);
673: return (bool)$this->tagIsInvalid();
674: }
675:
676: 677: 678: 679: 680: 681: 682: 683: 684: 685: 686: 687: 688: 689: 690: 691: 692:
693: public function error($field, $text = null, $options = array()) {
694: $defaults = array('wrap' => true, 'class' => 'error-message', 'escape' => true);
695: $options = array_merge($defaults, $options);
696: $this->setEntity($field);
697:
698: $error = $this->tagIsInvalid();
699: if ($error === false) {
700: return null;
701: }
702: if (is_array($text)) {
703: if (isset($text['attributes']) && is_array($text['attributes'])) {
704: $options = array_merge($options, $text['attributes']);
705: unset($text['attributes']);
706: }
707: $tmp = array();
708: foreach ($error as &$e) {
709: if (isset($text[$e])) {
710: $tmp[] = $text[$e];
711: } else {
712: $tmp[] = $e;
713: }
714: }
715: $text = $tmp;
716: }
717:
718: if ($text !== null) {
719: $error = $text;
720: }
721: if (is_array($error)) {
722: foreach ($error as &$e) {
723: if (is_numeric($e)) {
724: $e = __d('cake', 'Error in field %s', Inflector::humanize($this->field()));
725: }
726: }
727: }
728: if ($options['escape']) {
729: $error = h($error);
730: unset($options['escape']);
731: }
732: if (is_array($error)) {
733: if (count($error) > 1) {
734: $listParams = array();
735: if (isset($options['listOptions'])) {
736: if (is_string($options['listOptions'])) {
737: $listParams[] = $options['listOptions'];
738: } else {
739: if (isset($options['listOptions']['itemOptions'])) {
740: $listParams[] = $options['listOptions']['itemOptions'];
741: unset($options['listOptions']['itemOptions']);
742: } else {
743: $listParams[] = array();
744: }
745: if (isset($options['listOptions']['tag'])) {
746: $listParams[] = $options['listOptions']['tag'];
747: unset($options['listOptions']['tag']);
748: }
749: array_unshift($listParams, $options['listOptions']);
750: }
751: unset($options['listOptions']);
752: }
753: array_unshift($listParams, $error);
754: $error = call_user_func_array(array($this->Html, 'nestedList'), $listParams);
755: } else {
756: $error = array_pop($error);
757: }
758: }
759: if ($options['wrap']) {
760: $tag = is_string($options['wrap']) ? $options['wrap'] : 'div';
761: unset($options['wrap']);
762: return $this->Html->tag($tag, $error, $options);
763: }
764: return $error;
765: }
766:
767: 768: 769: 770: 771: 772: 773: 774: 775: 776: 777: 778: 779: 780: 781: 782: 783: 784: 785: 786: 787: 788: 789: 790: 791: 792: 793: 794: 795: 796: 797: 798: 799: 800: 801: 802: 803: 804: 805: 806: 807: 808: 809: 810: 811: 812: 813: 814: 815: 816:
817: public function label($fieldName = null, $text = null, $options = array()) {
818: if ($fieldName === null) {
819: $fieldName = implode('.', $this->entity());
820: }
821:
822: if ($text === null) {
823: if (strpos($fieldName, '.') !== false) {
824: $fieldElements = explode('.', $fieldName);
825: $text = array_pop($fieldElements);
826: } else {
827: $text = $fieldName;
828: }
829: if (substr($text, -3) === '_id') {
830: $text = substr($text, 0, -3);
831: }
832: $text = __(Inflector::humanize(Inflector::underscore($text)));
833: }
834:
835: if (is_string($options)) {
836: $options = array('class' => $options);
837: }
838:
839: if (isset($options['for'])) {
840: $labelFor = $options['for'];
841: unset($options['for']);
842: } else {
843: $labelFor = $this->domId($fieldName);
844: }
845:
846: return $this->Html->useTag('label', $labelFor, $options, $text);
847: }
848:
849: 850: 851: 852: 853: 854: 855: 856: 857: 858: 859: 860: 861: 862: 863: 864: 865: 866: 867: 868: 869: 870: 871: 872: 873: 874: 875:
876: public function inputs($fields = null, $blacklist = null, $options = array()) {
877: $fieldset = $legend = true;
878: $modelFields = array();
879: $model = $this->model();
880: if ($model) {
881: $modelFields = array_keys((array)$this->_introspectModel($model, 'fields'));
882: }
883: if (is_array($fields)) {
884: if (array_key_exists('legend', $fields) && !in_array('legend', $modelFields)) {
885: $legend = $fields['legend'];
886: unset($fields['legend']);
887: }
888:
889: if (isset($fields['fieldset']) && !in_array('fieldset', $modelFields)) {
890: $fieldset = $fields['fieldset'];
891: unset($fields['fieldset']);
892: }
893: } elseif ($fields !== null) {
894: $fieldset = $legend = $fields;
895: if (!is_bool($fieldset)) {
896: $fieldset = true;
897: }
898: $fields = array();
899: }
900:
901: if (isset($options['legend'])) {
902: $legend = $options['legend'];
903: }
904: if (isset($options['fieldset'])) {
905: $fieldset = $options['fieldset'];
906: }
907:
908: if (empty($fields)) {
909: $fields = $modelFields;
910: }
911:
912: if ($legend === true) {
913: $actionName = __d('cake', 'New %s');
914: $isEdit = (
915: strpos($this->request->params['action'], 'update') !== false ||
916: strpos($this->request->params['action'], 'edit') !== false
917: );
918: if ($isEdit) {
919: $actionName = __d('cake', 'Edit %s');
920: }
921: $modelName = Inflector::humanize(Inflector::underscore($model));
922: $legend = sprintf($actionName, __($modelName));
923: }
924:
925: $out = null;
926: foreach ($fields as $name => $options) {
927: if (is_numeric($name) && !is_array($options)) {
928: $name = $options;
929: $options = array();
930: }
931: $entity = explode('.', $name);
932: $blacklisted = (
933: is_array($blacklist) &&
934: (in_array($name, $blacklist) || in_array(end($entity), $blacklist))
935: );
936: if ($blacklisted) {
937: continue;
938: }
939: $out .= $this->input($name, $options);
940: }
941:
942: if (is_string($fieldset)) {
943: $fieldsetClass = sprintf(' class="%s"', $fieldset);
944: } else {
945: $fieldsetClass = '';
946: }
947:
948: if ($fieldset) {
949: if ($legend) {
950: $out = $this->Html->useTag('legend', $legend) . $out;
951: }
952: $out = $this->Html->useTag('fieldset', $fieldsetClass, $out);
953: }
954: return $out;
955: }
956:
957: 958: 959: 960: 961: 962: 963: 964: 965: 966: 967: 968: 969: 970: 971: 972: 973: 974: 975: 976: 977: 978: 979: 980: 981: 982: 983: 984: 985: 986: 987: 988: 989:
990: public function input($fieldName, $options = array()) {
991: $this->setEntity($fieldName);
992: $options = $this->_parseOptions($options);
993:
994: $divOptions = $this->_divOptions($options);
995: unset($options['div']);
996:
997: if ($options['type'] === 'radio' && isset($options['options'])) {
998: $radioOptions = (array)$options['options'];
999: unset($options['options']);
1000: }
1001:
1002: $label = $this->_getLabel($fieldName, $options);
1003: if ($options['type'] !== 'radio') {
1004: unset($options['label']);
1005: }
1006:
1007: $error = $this->_extractOption('error', $options, null);
1008: unset($options['error']);
1009:
1010: $errorMessage = $this->_extractOption('errorMessage', $options, true);
1011: unset($options['errorMessage']);
1012:
1013: $selected = $this->_extractOption('selected', $options, null);
1014: unset($options['selected']);
1015:
1016: if ($options['type'] === 'datetime' || $options['type'] === 'date' || $options['type'] === 'time') {
1017: $dateFormat = $this->_extractOption('dateFormat', $options, 'MDY');
1018: $timeFormat = $this->_extractOption('timeFormat', $options, 12);
1019: unset($options['dateFormat'], $options['timeFormat']);
1020: }
1021:
1022: $type = $options['type'];
1023: $out = array('before' => $options['before'], 'label' => $label, 'between' => $options['between'], 'after' => $options['after']);
1024: $format = $this->_getFormat($options);
1025:
1026: unset($options['type'], $options['before'], $options['between'], $options['after'], $options['format']);
1027:
1028: $out['error'] = null;
1029: if ($type !== 'hidden' && $error !== false) {
1030: $errMsg = $this->error($fieldName, $error);
1031: if ($errMsg) {
1032: $divOptions = $this->addClass($divOptions, 'error');
1033: if ($errorMessage) {
1034: $out['error'] = $errMsg;
1035: }
1036: }
1037: }
1038:
1039: if ($type === 'radio' && isset($out['between'])) {
1040: $options['between'] = $out['between'];
1041: $out['between'] = null;
1042: }
1043: $out['input'] = $this->_getInput(compact('type', 'fieldName', 'options', 'radioOptions', 'selected', 'dateFormat', 'timeFormat'));
1044:
1045: $output = '';
1046: foreach ($format as $element) {
1047: $output .= $out[$element];
1048: }
1049:
1050: if (!empty($divOptions['tag'])) {
1051: $tag = $divOptions['tag'];
1052: unset($divOptions['tag']);
1053: $output = $this->Html->tag($tag, $output, $divOptions);
1054: }
1055: return $output;
1056: }
1057:
1058: 1059: 1060: 1061: 1062: 1063:
1064: protected function _getInput($args) {
1065: extract($args);
1066: switch ($type) {
1067: case 'hidden':
1068: return $this->hidden($fieldName, $options);
1069: case 'checkbox':
1070: return $this->checkbox($fieldName, $options);
1071: case 'radio':
1072: return $this->radio($fieldName, $radioOptions, $options);
1073: case 'file':
1074: return $this->file($fieldName, $options);
1075: case 'select':
1076: $options += array('options' => array(), 'value' => $selected);
1077: $list = $options['options'];
1078: unset($options['options']);
1079: return $this->select($fieldName, $list, $options);
1080: case 'time':
1081: $options['value'] = $selected;
1082: return $this->dateTime($fieldName, null, $timeFormat, $options);
1083: case 'date':
1084: $options['value'] = $selected;
1085: return $this->dateTime($fieldName, $dateFormat, null, $options);
1086: case 'datetime':
1087: $options['value'] = $selected;
1088: return $this->dateTime($fieldName, $dateFormat, $timeFormat, $options);
1089: case 'textarea':
1090: return $this->textarea($fieldName, $options + array('cols' => '30', 'rows' => '6'));
1091: case 'url':
1092: return $this->text($fieldName, array('type' => 'url') + $options);
1093: default:
1094: return $this->{$type}($fieldName, $options);
1095: }
1096: }
1097:
1098: 1099: 1100: 1101: 1102: 1103:
1104: protected function _parseOptions($options) {
1105: $options = array_merge(
1106: array('before' => null, 'between' => null, 'after' => null, 'format' => null),
1107: $this->_inputDefaults,
1108: $options
1109: );
1110:
1111: if (!isset($options['type'])) {
1112: $options = $this->_magicOptions($options);
1113: }
1114:
1115: if (in_array($options['type'], array('radio', 'select'))) {
1116: $options = $this->_optionsOptions($options);
1117: }
1118:
1119: if (isset($options['rows']) || isset($options['cols'])) {
1120: $options['type'] = 'textarea';
1121: }
1122:
1123: if ($options['type'] === 'datetime' || $options['type'] === 'date' || $options['type'] === 'time' || $options['type'] === 'select') {
1124: $options += array('empty' => false);
1125: }
1126: return $options;
1127: }
1128:
1129: 1130: 1131: 1132: 1133: 1134:
1135: protected function _optionsOptions($options) {
1136: if (isset($options['options'])) {
1137: return $options;
1138: }
1139: $varName = Inflector::variable(
1140: Inflector::pluralize(preg_replace('/_id$/', '', $this->field()))
1141: );
1142: $varOptions = $this->_View->get($varName);
1143: if (!is_array($varOptions)) {
1144: return $options;
1145: }
1146: if ($options['type'] !== 'radio') {
1147: $options['type'] = 'select';
1148: }
1149: $options['options'] = $varOptions;
1150: return $options;
1151: }
1152:
1153: 1154: 1155: 1156: 1157: 1158:
1159: protected function _magicOptions($options) {
1160: $modelKey = $this->model();
1161: $fieldKey = $this->field();
1162: $options['type'] = 'text';
1163: if (isset($options['options'])) {
1164: $options['type'] = 'select';
1165: } elseif (in_array($fieldKey, array('psword', 'passwd', 'password'))) {
1166: $options['type'] = 'password';
1167: } elseif (in_array($fieldKey, array('tel', 'telephone', 'phone'))) {
1168: $options['type'] = 'tel';
1169: } elseif ($fieldKey === 'email') {
1170: $options['type'] = 'email';
1171: } elseif (isset($options['checked'])) {
1172: $options['type'] = 'checkbox';
1173: } elseif ($fieldDef = $this->_introspectModel($modelKey, 'fields', $fieldKey)) {
1174: $type = $fieldDef['type'];
1175: $primaryKey = $this->fieldset[$modelKey]['key'];
1176: $map = array(
1177: 'string' => 'text', 'datetime' => 'datetime',
1178: 'boolean' => 'checkbox', 'timestamp' => 'datetime',
1179: 'text' => 'textarea', 'time' => 'time',
1180: 'date' => 'date', 'float' => 'number',
1181: 'integer' => 'number'
1182: );
1183:
1184: if (isset($this->map[$type])) {
1185: $options['type'] = $this->map[$type];
1186: } elseif (isset($map[$type])) {
1187: $options['type'] = $map[$type];
1188: }
1189: if ($fieldKey === $primaryKey) {
1190: $options['type'] = 'hidden';
1191: }
1192: if (
1193: $options['type'] === 'number' &&
1194: $type === 'float' &&
1195: !isset($options['step'])
1196: ) {
1197: $options['step'] = 'any';
1198: }
1199: }
1200:
1201: if (preg_match('/_id$/', $fieldKey) && $options['type'] !== 'hidden') {
1202: $options['type'] = 'select';
1203: }
1204:
1205: if ($modelKey === $fieldKey) {
1206: $options['type'] = 'select';
1207: if (!isset($options['multiple'])) {
1208: $options['multiple'] = 'multiple';
1209: }
1210: }
1211: if (in_array($options['type'], array('text', 'number'))) {
1212: $options = $this->_optionsOptions($options);
1213: }
1214: if ($options['type'] === 'select' && array_key_exists('step', $options)) {
1215: unset($options['step']);
1216: }
1217: $options = $this->_maxLength($options);
1218: return $options;
1219: }
1220:
1221: 1222: 1223: 1224: 1225: 1226:
1227: protected function _getFormat($options) {
1228: if ($options['type'] === 'hidden') {
1229: return array('input');
1230: }
1231: if (is_array($options['format']) && in_array('input', $options['format'])) {
1232: return $options['format'];
1233: }
1234: if ($options['type'] === 'checkbox') {
1235: return array('before', 'input', 'between', 'label', 'after', 'error');
1236: }
1237: return array('before', 'label', 'between', 'input', 'after', 'error');
1238: }
1239:
1240: 1241: 1242: 1243: 1244: 1245: 1246:
1247: protected function _getLabel($fieldName, $options) {
1248: if ($options['type'] === 'radio') {
1249: return false;
1250: }
1251:
1252: $label = null;
1253: if (isset($options['label'])) {
1254: $label = $options['label'];
1255: }
1256:
1257: if ($label === false) {
1258: return false;
1259: }
1260: return $this->_inputLabel($fieldName, $label, $options);
1261: }
1262:
1263: 1264: 1265: 1266: 1267: 1268:
1269: protected function _maxLength($options) {
1270: $fieldDef = $this->_introspectModel($this->model(), 'fields', $this->field());
1271: $autoLength = (
1272: !array_key_exists('maxlength', $options) &&
1273: isset($fieldDef['length']) &&
1274: is_scalar($fieldDef['length']) &&
1275: $options['type'] !== 'select'
1276: );
1277: if ($autoLength &&
1278: in_array($options['type'], array('text', 'email', 'tel', 'url', 'search'))
1279: ) {
1280: $options['maxlength'] = $fieldDef['length'];
1281: }
1282: return $options;
1283: }
1284:
1285: 1286: 1287: 1288: 1289: 1290:
1291: protected function _divOptions($options) {
1292: if ($options['type'] === 'hidden') {
1293: return array();
1294: }
1295: $div = $this->_extractOption('div', $options, true);
1296: if (!$div) {
1297: return array();
1298: }
1299:
1300: $divOptions = array('class' => 'input');
1301: $divOptions = $this->addClass($divOptions, $options['type']);
1302: if (is_string($div)) {
1303: $divOptions['class'] = $div;
1304: } elseif (is_array($div)) {
1305: $divOptions = array_merge($divOptions, $div);
1306: }
1307: if (
1308: $this->_extractOption('required', $options) !== false &&
1309: $this->_introspectModel($this->model(), 'validates', $this->field())
1310: ) {
1311: $divOptions = $this->addClass($divOptions, 'required');
1312: }
1313: if (!isset($divOptions['tag'])) {
1314: $divOptions['tag'] = 'div';
1315: }
1316: return $divOptions;
1317: }
1318:
1319: 1320: 1321: 1322: 1323: 1324: 1325: 1326:
1327: protected function _extractOption($name, $options, $default = null) {
1328: if (array_key_exists($name, $options)) {
1329: return $options[$name];
1330: }
1331: return $default;
1332: }
1333:
1334: 1335: 1336: 1337: 1338: 1339: 1340: 1341: 1342: 1343: 1344:
1345: protected function _inputLabel($fieldName, $label, $options) {
1346: $labelAttributes = $this->domId(array(), 'for');
1347: $idKey = null;
1348: if ($options['type'] === 'date' || $options['type'] === 'datetime') {
1349: $firstInput = 'M';
1350: if (
1351: array_key_exists('dateFormat', $options) &&
1352: ($options['dateFormat'] === null || $options['dateFormat'] === 'NONE')
1353: ) {
1354: $firstInput = 'H';
1355: } elseif (!empty($options['dateFormat'])) {
1356: $firstInput = substr($options['dateFormat'], 0, 1);
1357: }
1358: switch ($firstInput) {
1359: case 'D':
1360: $idKey = 'day';
1361: $labelAttributes['for'] .= 'Day';
1362: break;
1363: case 'Y':
1364: $idKey = 'year';
1365: $labelAttributes['for'] .= 'Year';
1366: break;
1367: case 'M':
1368: $idKey = 'month';
1369: $labelAttributes['for'] .= 'Month';
1370: break;
1371: case 'H':
1372: $idKey = 'hour';
1373: $labelAttributes['for'] .= 'Hour';
1374: }
1375: }
1376: if ($options['type'] === 'time') {
1377: $labelAttributes['for'] .= 'Hour';
1378: $idKey = 'hour';
1379: }
1380: if (isset($idKey) && isset($options['id']) && isset($options['id'][$idKey])) {
1381: $labelAttributes['for'] = $options['id'][$idKey];
1382: }
1383:
1384: if (is_array($label)) {
1385: $labelText = null;
1386: if (isset($label['text'])) {
1387: $labelText = $label['text'];
1388: unset($label['text']);
1389: }
1390: $labelAttributes = array_merge($labelAttributes, $label);
1391: } else {
1392: $labelText = $label;
1393: }
1394:
1395: if (isset($options['id']) && is_string($options['id'])) {
1396: $labelAttributes = array_merge($labelAttributes, array('for' => $options['id']));
1397: }
1398: return $this->label($fieldName, $labelText, $labelAttributes);
1399: }
1400:
1401: 1402: 1403: 1404: 1405: 1406: 1407: 1408: 1409: 1410: 1411: 1412: 1413: 1414: 1415: 1416: 1417: 1418: 1419:
1420: public function checkbox($fieldName, $options = array()) {
1421: $valueOptions = array();
1422: if (isset($options['default'])) {
1423: $valueOptions['default'] = $options['default'];
1424: unset($options['default']);
1425: }
1426:
1427: $options += array('value' => 1, 'required' => false);
1428: $options = $this->_initInputField($fieldName, $options) + array('hiddenField' => true);
1429: $value = current($this->value($valueOptions));
1430: $output = '';
1431:
1432: if (
1433: (!isset($options['checked']) && !empty($value) && $value == $options['value']) ||
1434: !empty($options['checked'])
1435: ) {
1436: $options['checked'] = 'checked';
1437: }
1438: if ($options['hiddenField']) {
1439: $hiddenOptions = array(
1440: 'id' => $options['id'] . '_',
1441: 'name' => $options['name'],
1442: 'value' => ($options['hiddenField'] !== true ? $options['hiddenField'] : '0'),
1443: 'form' => isset($options['form']) ? $options['form'] : null,
1444: 'secure' => false,
1445: );
1446: if (isset($options['disabled']) && $options['disabled']) {
1447: $hiddenOptions['disabled'] = 'disabled';
1448: }
1449: $output = $this->hidden($fieldName, $hiddenOptions);
1450: }
1451: unset($options['hiddenField']);
1452:
1453: return $output . $this->Html->useTag('checkbox', $options['name'], array_diff_key($options, array('name' => null)));
1454: }
1455:
1456: 1457: 1458: 1459: 1460: 1461: 1462: 1463: 1464: 1465: 1466: 1467: 1468: 1469: 1470: 1471: 1472: 1473: 1474: 1475: 1476: 1477: 1478: 1479:
1480: public function radio($fieldName, $options = array(), $attributes = array()) {
1481: $attributes = $this->_initInputField($fieldName, $attributes);
1482:
1483: $showEmpty = $this->_extractOption('empty', $attributes);
1484: if ($showEmpty) {
1485: $showEmpty = ($showEmpty === true) ? __d('cake', 'empty') : $showEmpty;
1486: $options = array('' => $showEmpty) + $options;
1487: }
1488: unset($attributes['empty']);
1489:
1490: $legend = false;
1491: if (isset($attributes['legend'])) {
1492: $legend = $attributes['legend'];
1493: unset($attributes['legend']);
1494: } elseif (count($options) > 1) {
1495: $legend = __(Inflector::humanize($this->field()));
1496: }
1497:
1498: $label = true;
1499: if (isset($attributes['label'])) {
1500: $label = $attributes['label'];
1501: unset($attributes['label']);
1502: }
1503:
1504: $separator = null;
1505: if (isset($attributes['separator'])) {
1506: $separator = $attributes['separator'];
1507: unset($attributes['separator']);
1508: }
1509:
1510: $between = null;
1511: if (isset($attributes['between'])) {
1512: $between = $attributes['between'];
1513: unset($attributes['between']);
1514: }
1515:
1516: $value = null;
1517: if (isset($attributes['value'])) {
1518: $value = $attributes['value'];
1519: } else {
1520: $value = $this->value($fieldName);
1521: }
1522:
1523: $disabled = array();
1524: if (isset($attributes['disabled'])) {
1525: $disabled = $attributes['disabled'];
1526: }
1527:
1528: $out = array();
1529:
1530: $hiddenField = isset($attributes['hiddenField']) ? $attributes['hiddenField'] : true;
1531: unset($attributes['hiddenField']);
1532:
1533: if (isset($value) && is_bool($value)) {
1534: $value = $value ? 1 : 0;
1535: }
1536:
1537: $this->_domIdSuffixes = array();
1538: foreach ($options as $optValue => $optTitle) {
1539: $optionsHere = array('value' => $optValue, 'disabled' => false);
1540:
1541: if (isset($value) && strval($optValue) === strval($value)) {
1542: $optionsHere['checked'] = 'checked';
1543: }
1544: $isNumeric = is_numeric($optValue);
1545: if ($disabled && (!is_array($disabled) || in_array((string)$optValue, $disabled, !$isNumeric))) {
1546: $optionsHere['disabled'] = true;
1547: }
1548: $tagName = $attributes['id'] . $this->domIdSuffix($optValue);
1549:
1550: if ($label) {
1551: $labelOpts = is_array($label) ? $label : array();
1552: $labelOpts += array('for' => $tagName);
1553: $optTitle = $this->label($tagName, $optTitle, $labelOpts);
1554: }
1555:
1556: if (is_array($between)) {
1557: $optTitle .= array_shift($between);
1558: }
1559: $allOptions = array_merge($attributes, $optionsHere);
1560: $out[] = $this->Html->useTag('radio', $attributes['name'], $tagName,
1561: array_diff_key($allOptions, array('name' => null, 'type' => null, 'id' => null)),
1562: $optTitle
1563: );
1564: }
1565: $hidden = null;
1566:
1567: if ($hiddenField) {
1568: if (!isset($value) || $value === '') {
1569: $hidden = $this->hidden($fieldName, array(
1570: 'form' => isset($attributes['form']) ? $attributes['form'] : null,
1571: 'id' => $attributes['id'] . '_',
1572: 'value' => '',
1573: 'name' => $attributes['name']
1574: ));
1575: }
1576: }
1577: $out = $hidden . implode($separator, $out);
1578:
1579: if (is_array($between)) {
1580: $between = '';
1581: }
1582: if ($legend) {
1583: $out = $this->Html->useTag('fieldset', '', $this->Html->useTag('legend', $legend) . $between . $out);
1584: }
1585: return $out;
1586: }
1587:
1588: 1589: 1590: 1591: 1592: 1593: 1594: 1595: 1596: 1597: 1598: 1599: 1600: 1601: 1602: 1603: 1604: 1605: 1606: 1607: 1608:
1609: public function __call($method, $params) {
1610: $options = array();
1611: if (empty($params)) {
1612: throw new CakeException(__d('cake_dev', 'Missing field name for FormHelper::%s', $method));
1613: }
1614: if (isset($params[1])) {
1615: $options = $params[1];
1616: }
1617: if (!isset($options['type'])) {
1618: $options['type'] = $method;
1619: }
1620: $options = $this->_initInputField($params[0], $options);
1621: return $this->Html->useTag('input', $options['name'], array_diff_key($options, array('name' => null)));
1622: }
1623:
1624: 1625: 1626: 1627: 1628: 1629: 1630: 1631: 1632: 1633: 1634: 1635:
1636: public function textarea($fieldName, $options = array()) {
1637: $options = $this->_initInputField($fieldName, $options);
1638: $value = null;
1639:
1640: if (array_key_exists('value', $options)) {
1641: $value = $options['value'];
1642: if (!array_key_exists('escape', $options) || $options['escape'] !== false) {
1643: $value = h($value);
1644: }
1645: unset($options['value']);
1646: }
1647: return $this->Html->useTag('textarea', $options['name'], array_diff_key($options, array('type' => null, 'name' => null)), $value);
1648: }
1649:
1650: 1651: 1652: 1653: 1654: 1655: 1656: 1657:
1658: public function hidden($fieldName, $options = array()) {
1659: $options += array('required' => false, 'secure' => true);
1660:
1661: $secure = $options['secure'];
1662: unset($options['secure']);
1663:
1664: $options = $this->_initInputField($fieldName, array_merge(
1665: $options, array('secure' => self::SECURE_SKIP)
1666: ));
1667:
1668: if ($secure === true) {
1669: $this->_secure(true, null, '' . $options['value']);
1670: }
1671:
1672: return $this->Html->useTag('hidden', $options['name'], array_diff_key($options, array('name' => null)));
1673: }
1674:
1675: 1676: 1677: 1678: 1679: 1680: 1681: 1682:
1683: public function file($fieldName, $options = array()) {
1684: $options += array('secure' => true);
1685: $secure = $options['secure'];
1686: $options['secure'] = self::SECURE_SKIP;
1687:
1688: $options = $this->_initInputField($fieldName, $options);
1689: $field = $this->entity();
1690:
1691: foreach (array('name', 'type', 'tmp_name', 'error', 'size') as $suffix) {
1692: $this->_secure($secure, array_merge($field, array($suffix)));
1693: }
1694:
1695: $exclude = array('name' => null, 'value' => null);
1696: return $this->Html->useTag('file', $options['name'], array_diff_key($options, $exclude));
1697: }
1698:
1699: 1700: 1701: 1702: 1703: 1704: 1705: 1706: 1707: 1708: 1709: 1710: 1711:
1712: public function button($title, $options = array()) {
1713: $options += array('type' => 'submit', 'escape' => false, 'secure' => false);
1714: if ($options['escape']) {
1715: $title = h($title);
1716: }
1717: if (isset($options['name'])) {
1718: $name = str_replace(array('[', ']'), array('.', ''), $options['name']);
1719: $this->_secure($options['secure'], $name);
1720: }
1721: return $this->Html->useTag('button', $options, $title);
1722: }
1723:
1724: 1725: 1726: 1727: 1728: 1729: 1730: 1731: 1732: 1733: 1734: 1735: 1736: 1737: 1738: 1739: 1740:
1741: public function postButton($title, $url, $options = array()) {
1742: $out = $this->create(false, array('id' => false, 'url' => $url));
1743: if (isset($options['data']) && is_array($options['data'])) {
1744: foreach (Hash::flatten($options['data']) as $key => $value) {
1745: $out .= $this->hidden($key, array('value' => $value, 'id' => false));
1746: }
1747: unset($options['data']);
1748: }
1749: $out .= $this->button($title, $options);
1750: $out .= $this->end();
1751: return $out;
1752: }
1753:
1754: 1755: 1756: 1757: 1758: 1759: 1760: 1761: 1762: 1763: 1764: 1765: 1766: 1767: 1768: 1769: 1770: 1771: 1772: 1773: 1774: 1775:
1776: public function postLink($title, $url = null, $options = array(), $confirmMessage = false) {
1777: $requestMethod = 'POST';
1778: if (!empty($options['method'])) {
1779: $requestMethod = strtoupper($options['method']);
1780: unset($options['method']);
1781: }
1782: if (!empty($options['confirm'])) {
1783: $confirmMessage = $options['confirm'];
1784: unset($options['confirm']);
1785: }
1786:
1787: $formName = str_replace('.', '', uniqid('post_', true));
1788: $formUrl = $this->url($url);
1789: $formOptions = array(
1790: 'name' => $formName,
1791: 'id' => $formName,
1792: 'style' => 'display:none;',
1793: 'method' => 'post',
1794: );
1795: if (isset($options['target'])) {
1796: $formOptions['target'] = $options['target'];
1797: unset($options['target']);
1798: }
1799:
1800: $this->_lastAction = $formUrl;
1801:
1802: $out = $this->Html->useTag('form', $formUrl, $formOptions);
1803: $out .= $this->Html->useTag('hidden', '_method', array(
1804: 'value' => $requestMethod
1805: ));
1806: $out .= $this->_csrfField();
1807:
1808: $fields = array();
1809: if (isset($options['data']) && is_array($options['data'])) {
1810: foreach (Hash::flatten($options['data']) as $key => $value) {
1811: $fields[$key] = $value;
1812: $out .= $this->hidden($key, array('value' => $value, 'id' => false));
1813: }
1814: unset($options['data']);
1815: }
1816: $out .= $this->secure($fields);
1817: $out .= $this->Html->useTag('formend');
1818:
1819: $url = '#';
1820: $onClick = 'document.' . $formName . '.submit();';
1821: if ($confirmMessage) {
1822: $options['onclick'] = $this->_confirm($confirmMessage, $onClick, '', $options);
1823: } else {
1824: $options['onclick'] = $onClick . ' ';
1825: }
1826: $options['onclick'] .= 'event.returnValue = false; return false;';
1827:
1828: $out .= $this->Html->link($title, $url, $options);
1829: return $out;
1830: }
1831:
1832: 1833: 1834: 1835: 1836: 1837: 1838: 1839: 1840: 1841: 1842: 1843: 1844: 1845: 1846: 1847: 1848: 1849: 1850: 1851: 1852: 1853: 1854: 1855: 1856: 1857: 1858: 1859:
1860: public function submit($caption = null, $options = array()) {
1861: if (!is_string($caption) && empty($caption)) {
1862: $caption = __d('cake', 'Submit');
1863: }
1864: $out = null;
1865: $div = true;
1866:
1867: if (isset($options['div'])) {
1868: $div = $options['div'];
1869: unset($options['div']);
1870: }
1871: $options += array('type' => 'submit', 'before' => null, 'after' => null, 'secure' => false);
1872: $divOptions = array('tag' => 'div');
1873:
1874: if ($div === true) {
1875: $divOptions['class'] = 'submit';
1876: } elseif ($div === false) {
1877: unset($divOptions);
1878: } elseif (is_string($div)) {
1879: $divOptions['class'] = $div;
1880: } elseif (is_array($div)) {
1881: $divOptions = array_merge(array('class' => 'submit', 'tag' => 'div'), $div);
1882: }
1883:
1884: if (isset($options['name'])) {
1885: $name = str_replace(array('[', ']'), array('.', ''), $options['name']);
1886: $this->_secure($options['secure'], $name);
1887: }
1888: unset($options['secure']);
1889:
1890: $before = $options['before'];
1891: $after = $options['after'];
1892: unset($options['before'], $options['after']);
1893:
1894: $isUrl = strpos($caption, '://') !== false;
1895: $isImage = preg_match('/\.(jpg|jpe|jpeg|gif|png|ico)$/', $caption);
1896:
1897: if ($isUrl || $isImage) {
1898: $unlockFields = array('x', 'y');
1899: if (isset($options['name'])) {
1900: $unlockFields = array(
1901: $options['name'] . '_x', $options['name'] . '_y'
1902: );
1903: }
1904: foreach ($unlockFields as $ignore) {
1905: $this->unlockField($ignore);
1906: }
1907: }
1908:
1909: if ($isUrl) {
1910: unset($options['type']);
1911: $tag = $this->Html->useTag('submitimage', $caption, $options);
1912: } elseif ($isImage) {
1913: unset($options['type']);
1914: if ($caption{0} !== '/') {
1915: $url = $this->webroot(Configure::read('App.imageBaseUrl') . $caption);
1916: } else {
1917: $url = $this->webroot(trim($caption, '/'));
1918: }
1919: $url = $this->assetTimestamp($url);
1920: $tag = $this->Html->useTag('submitimage', $url, $options);
1921: } else {
1922: $options['value'] = $caption;
1923: $tag = $this->Html->useTag('submit', $options);
1924: }
1925: $out = $before . $tag . $after;
1926:
1927: if (isset($divOptions)) {
1928: $tag = $divOptions['tag'];
1929: unset($divOptions['tag']);
1930: $out = $this->Html->tag($tag, $out, $divOptions);
1931: }
1932: return $out;
1933: }
1934:
1935: 1936: 1937: 1938: 1939: 1940: 1941: 1942: 1943: 1944: 1945: 1946: 1947: 1948: 1949: 1950: 1951: 1952: 1953: 1954: 1955: 1956: 1957: 1958: 1959: 1960: 1961: 1962: 1963: 1964: 1965: 1966: 1967: 1968: 1969: 1970: 1971: 1972: 1973: 1974: 1975: 1976: 1977: 1978: 1979: 1980: 1981: 1982: 1983: 1984: 1985: 1986: 1987: 1988: 1989: 1990: 1991: 1992: 1993: 1994:
1995: public function select($fieldName, $options = array(), $attributes = array()) {
1996: $select = array();
1997: $style = null;
1998: $tag = null;
1999: $attributes += array(
2000: 'class' => null,
2001: 'escape' => true,
2002: 'secure' => true,
2003: 'empty' => '',
2004: 'showParents' => false,
2005: 'hiddenField' => true,
2006: 'disabled' => false
2007: );
2008:
2009: $escapeOptions = $this->_extractOption('escape', $attributes);
2010: $secure = $this->_extractOption('secure', $attributes);
2011: $showEmpty = $this->_extractOption('empty', $attributes);
2012: $showParents = $this->_extractOption('showParents', $attributes);
2013: $hiddenField = $this->_extractOption('hiddenField', $attributes);
2014: unset($attributes['escape'], $attributes['secure'], $attributes['empty'], $attributes['showParents'], $attributes['hiddenField']);
2015: $id = $this->_extractOption('id', $attributes);
2016:
2017: $attributes = $this->_initInputField($fieldName, array_merge(
2018: (array)$attributes, array('secure' => self::SECURE_SKIP)
2019: ));
2020:
2021: if (is_string($options) && isset($this->_options[$options])) {
2022: $options = $this->_generateOptions($options);
2023: } elseif (!is_array($options)) {
2024: $options = array();
2025: }
2026: if (isset($attributes['type'])) {
2027: unset($attributes['type']);
2028: }
2029:
2030: if (!empty($attributes['multiple'])) {
2031: $style = ($attributes['multiple'] === 'checkbox') ? 'checkbox' : null;
2032: $template = ($style) ? 'checkboxmultiplestart' : 'selectmultiplestart';
2033: $tag = $template;
2034: if ($hiddenField) {
2035: $hiddenAttributes = array(
2036: 'value' => '',
2037: 'id' => $attributes['id'] . ($style ? '' : '_'),
2038: 'secure' => false,
2039: 'form' => isset($attributes['form']) ? $attributes['form'] : null,
2040: 'name' => $attributes['name']
2041: );
2042: $select[] = $this->hidden(null, $hiddenAttributes);
2043: }
2044: } else {
2045: $tag = 'selectstart';
2046: }
2047:
2048: if ($tag === 'checkboxmultiplestart') {
2049: unset($attributes['required']);
2050: }
2051:
2052: if (!empty($tag) || isset($template)) {
2053: $hasOptions = (count($options) > 0 || $showEmpty);
2054:
2055:
2056: if (
2057: (!isset($secure) || $secure) &&
2058: empty($attributes['disabled']) &&
2059: (!empty($attributes['multiple']) || $hasOptions)
2060: ) {
2061: $this->_secure(true, $this->_secureFieldName($attributes));
2062: }
2063: $select[] = $this->Html->useTag($tag, $attributes['name'], array_diff_key($attributes, array('name' => null, 'value' => null)));
2064: }
2065: $emptyMulti = (
2066: $showEmpty !== null && $showEmpty !== false && !(
2067: empty($showEmpty) && (isset($attributes) &&
2068: array_key_exists('multiple', $attributes))
2069: )
2070: );
2071:
2072: if ($emptyMulti) {
2073: $showEmpty = ($showEmpty === true) ? '' : $showEmpty;
2074: $options = array('' => $showEmpty) + $options;
2075: }
2076:
2077: if (!$id) {
2078: $attributes['id'] = Inflector::camelize($attributes['id']);
2079: }
2080:
2081: $select = array_merge($select, $this->_selectOptions(
2082: array_reverse($options, true),
2083: array(),
2084: $showParents,
2085: array(
2086: 'escape' => $escapeOptions,
2087: 'style' => $style,
2088: 'name' => $attributes['name'],
2089: 'value' => $attributes['value'],
2090: 'class' => $attributes['class'],
2091: 'id' => $attributes['id'],
2092: 'disabled' => $attributes['disabled'],
2093: )
2094: ));
2095:
2096: $template = ($style === 'checkbox') ? 'checkboxmultipleend' : 'selectend';
2097: $select[] = $this->Html->useTag($template);
2098: return implode("\n", $select);
2099: }
2100:
2101: 2102: 2103: 2104: 2105: 2106: 2107: 2108: 2109: 2110: 2111: 2112:
2113: public function domIdSuffix($value, $type = 'html4') {
2114: if ($type === 'html5') {
2115: $value = str_replace(array('@', '<', '>', ' ', '"', '\''), '_', $value);
2116: } else {
2117: $value = Inflector::camelize(Inflector::slug($value));
2118: }
2119: $value = Inflector::camelize($value);
2120: $count = 1;
2121: $suffix = $value;
2122: while (in_array($suffix, $this->_domIdSuffixes)) {
2123: $suffix = $value . $count++;
2124: }
2125: $this->_domIdSuffixes[] = $suffix;
2126: return $suffix;
2127: }
2128:
2129: 2130: 2131: 2132: 2133: 2134: 2135: 2136: 2137: 2138: 2139: 2140: 2141: 2142:
2143: public function day($fieldName = null, $attributes = array()) {
2144: $attributes += array('empty' => true, 'value' => null);
2145: $attributes = $this->_dateTimeSelected('day', $fieldName, $attributes);
2146:
2147: if (strlen($attributes['value']) > 2) {
2148: $date = date_create($attributes['value']);
2149: $attributes['value'] = null;
2150: if ($date) {
2151: $attributes['value'] = $date->format('d');
2152: }
2153: } elseif ($attributes['value'] === false) {
2154: $attributes['value'] = null;
2155: }
2156: return $this->select($fieldName . ".day", $this->_generateOptions('day'), $attributes);
2157: }
2158:
2159: 2160: 2161: 2162: 2163: 2164: 2165: 2166: 2167: 2168: 2169: 2170: 2171: 2172: 2173: 2174: 2175: 2176:
2177: public function year($fieldName, $minYear = null, $maxYear = null, $attributes = array()) {
2178: $attributes += array('empty' => true, 'value' => null);
2179: if ((empty($attributes['value']) || $attributes['value'] === true) && $value = $this->value($fieldName)) {
2180: if (is_array($value)) {
2181: $year = null;
2182: extract($value);
2183: $attributes['value'] = $year;
2184: } else {
2185: if (empty($value)) {
2186: if (!$attributes['empty'] && !$maxYear) {
2187: $attributes['value'] = 'now';
2188:
2189: } elseif (!$attributes['empty'] && $maxYear && !$attributes['value']) {
2190: $attributes['value'] = $maxYear;
2191: }
2192: } else {
2193: $attributes['value'] = $value;
2194: }
2195: }
2196: }
2197:
2198: if (strlen($attributes['value']) > 4 || $attributes['value'] === 'now') {
2199: $date = date_create($attributes['value']);
2200: $attributes['value'] = null;
2201: if ($date) {
2202: $attributes['value'] = $date->format('Y');
2203: }
2204: } elseif ($attributes['value'] === false) {
2205: $attributes['value'] = null;
2206: }
2207: $yearOptions = array('value' => $attributes['value'], 'min' => $minYear, 'max' => $maxYear, 'order' => 'desc');
2208: if (isset($attributes['orderYear'])) {
2209: $yearOptions['order'] = $attributes['orderYear'];
2210: unset($attributes['orderYear']);
2211: }
2212: return $this->select(
2213: $fieldName . '.year', $this->_generateOptions('year', $yearOptions),
2214: $attributes
2215: );
2216: }
2217:
2218: 2219: 2220: 2221: 2222: 2223: 2224: 2225: 2226: 2227: 2228: 2229: 2230: 2231: 2232: 2233:
2234: public function month($fieldName, $attributes = array()) {
2235: $attributes += array('empty' => true, 'value' => null);
2236: $attributes = $this->_dateTimeSelected('month', $fieldName, $attributes);
2237:
2238: if (strlen($attributes['value']) > 2) {
2239: $date = date_create($attributes['value']);
2240: $attributes['value'] = null;
2241: if ($date) {
2242: $attributes['value'] = $date->format('m');
2243: }
2244: } elseif ($attributes['value'] === false) {
2245: $attributes['value'] = null;
2246: }
2247: $defaults = array('monthNames' => true);
2248: $attributes = array_merge($defaults, (array)$attributes);
2249: $monthNames = $attributes['monthNames'];
2250: unset($attributes['monthNames']);
2251:
2252: return $this->select(
2253: $fieldName . ".month",
2254: $this->_generateOptions('month', array('monthNames' => $monthNames)),
2255: $attributes
2256: );
2257: }
2258:
2259: 2260: 2261: 2262: 2263: 2264: 2265: 2266: 2267: 2268: 2269: 2270: 2271: 2272: 2273:
2274: public function hour($fieldName, $format24Hours = false, $attributes = array()) {
2275: $attributes += array('empty' => true, 'value' => null);
2276: $attributes = $this->_dateTimeSelected('hour', $fieldName, $attributes);
2277:
2278: if (strlen($attributes['value']) > 2) {
2279: try {
2280: $date = new DateTime($attributes['value']);
2281: if ($format24Hours) {
2282: $attributes['value'] = $date->format('H');
2283: } else {
2284: $attributes['value'] = $date->format('g');
2285: }
2286: } catch (Exception $e) {
2287: $attributes['value'] = null;
2288: }
2289: } elseif ($attributes['value'] === false) {
2290: $attributes['value'] = null;
2291: }
2292:
2293: if ($attributes['value'] > 12 && !$format24Hours) {
2294: $attributes['value'] -= 12;
2295: }
2296: if (($attributes['value'] === 0 || $attributes['value'] === '00') && !$format24Hours) {
2297: $attributes['value'] = 12;
2298: }
2299:
2300: return $this->select(
2301: $fieldName . ".hour",
2302: $this->_generateOptions($format24Hours ? 'hour24' : 'hour'),
2303: $attributes
2304: );
2305: }
2306:
2307: 2308: 2309: 2310: 2311: 2312: 2313: 2314: 2315: 2316: 2317: 2318: 2319: 2320:
2321: public function minute($fieldName, $attributes = array()) {
2322: $attributes += array('empty' => true, 'value' => null);
2323: $attributes = $this->_dateTimeSelected('min', $fieldName, $attributes);
2324:
2325: if (strlen($attributes['value']) > 2) {
2326: $date = date_create($attributes['value']);
2327: $attributes['value'] = null;
2328: if ($date) {
2329: $attributes['value'] = $date->format('i');
2330: }
2331: } elseif ($attributes['value'] === false) {
2332: $attributes['value'] = null;
2333: }
2334: $minuteOptions = array();
2335:
2336: if (isset($attributes['interval'])) {
2337: $minuteOptions['interval'] = $attributes['interval'];
2338: unset($attributes['interval']);
2339: }
2340: return $this->select(
2341: $fieldName . ".min", $this->_generateOptions('minute', $minuteOptions),
2342: $attributes
2343: );
2344: }
2345:
2346: 2347: 2348: 2349: 2350: 2351: 2352: 2353:
2354: protected function _dateTimeSelected($select, $fieldName, $attributes) {
2355: if ((empty($attributes['value']) || $attributes['value'] === true) && $value = $this->value($fieldName)) {
2356: if (is_array($value)) {
2357: $attributes['value'] = isset($value[$select]) ? $value[$select] : null;
2358: } else {
2359: if (empty($value)) {
2360: if (!$attributes['empty']) {
2361: $attributes['value'] = 'now';
2362: }
2363: } else {
2364: $attributes['value'] = $value;
2365: }
2366: }
2367: }
2368: return $attributes;
2369: }
2370:
2371: 2372: 2373: 2374: 2375: 2376: 2377: 2378: 2379: 2380: 2381: 2382: 2383: 2384:
2385: public function meridian($fieldName, $attributes = array()) {
2386: $attributes += array('empty' => true, 'value' => null);
2387: if ((empty($attributes['value']) || $attributes['value'] === true) && $value = $this->value($fieldName)) {
2388: if (is_array($value)) {
2389: $meridian = null;
2390: extract($value);
2391: $attributes['value'] = $meridian;
2392: } else {
2393: if (empty($value)) {
2394: if (!$attributes['empty']) {
2395: $attributes['value'] = date('a');
2396: }
2397: } else {
2398: $date = date_create($attributes['value']);
2399: $attributes['value'] = null;
2400: if ($date) {
2401: $attributes['value'] = $date->format('a');
2402: }
2403: }
2404: }
2405: }
2406:
2407: if ($attributes['value'] === false) {
2408: $attributes['value'] = null;
2409: }
2410: return $this->select(
2411: $fieldName . ".meridian", $this->_generateOptions('meridian'),
2412: $attributes
2413: );
2414: }
2415:
2416: 2417: 2418: 2419: 2420: 2421: 2422: 2423: 2424: 2425: 2426: 2427: 2428: 2429: 2430: 2431: 2432: 2433: 2434: 2435: 2436: 2437: 2438: 2439:
2440: public function dateTime($fieldName, $dateFormat = 'DMY', $timeFormat = '12', $attributes = array()) {
2441: $attributes += array('empty' => true, 'value' => null);
2442: $year = $month = $day = $hour = $min = $meridian = null;
2443:
2444: if (empty($attributes['value'])) {
2445: $attributes = $this->value($attributes, $fieldName);
2446: }
2447:
2448: if ($attributes['value'] === null && $attributes['empty'] != true) {
2449: $attributes['value'] = time();
2450: if (!empty($attributes['maxYear']) && $attributes['maxYear'] < date('Y')) {
2451: $attributes['value'] = strtotime(date($attributes['maxYear'] . '-m-d'));
2452: }
2453: }
2454:
2455: if (!empty($attributes['value'])) {
2456: list($year, $month, $day, $hour, $min, $meridian) = $this->_getDateTimeValue(
2457: $attributes['value'],
2458: $timeFormat
2459: );
2460: }
2461:
2462: $defaults = array(
2463: 'minYear' => null, 'maxYear' => null, 'separator' => '-',
2464: 'interval' => 1, 'monthNames' => true, 'round' => null
2465: );
2466: $attributes = array_merge($defaults, (array)$attributes);
2467: if (isset($attributes['minuteInterval'])) {
2468: $attributes['interval'] = $attributes['minuteInterval'];
2469: unset($attributes['minuteInterval']);
2470: }
2471: $minYear = $attributes['minYear'];
2472: $maxYear = $attributes['maxYear'];
2473: $separator = $attributes['separator'];
2474: $interval = $attributes['interval'];
2475: $monthNames = $attributes['monthNames'];
2476: $round = $attributes['round'];
2477: $attributes = array_diff_key($attributes, $defaults);
2478:
2479: if (!empty($interval) && $interval > 1 && !empty($min)) {
2480: $current = new DateTime();
2481: if ($year !== null) {
2482: $current->setDate($year, $month, $day);
2483: }
2484: if ($hour !== null) {
2485: $current->setTime($hour, $min);
2486: }
2487: $changeValue = $min * (1 / $interval);
2488: switch ($round) {
2489: case 'up':
2490: $changeValue = ceil($changeValue);
2491: break;
2492: case 'down':
2493: $changeValue = floor($changeValue);
2494: break;
2495: default:
2496: $changeValue = round($changeValue);
2497: }
2498: $change = ($changeValue * $interval) - $min;
2499: $current->modify($change > 0 ? "+$change minutes" : "$change minutes");
2500: $format = ($timeFormat == 12) ? 'Y m d h i a' : 'Y m d H i a';
2501: $newTime = explode(' ', $current->format($format));
2502: list($year, $month, $day, $hour, $min, $meridian) = $newTime;
2503: }
2504:
2505: $keys = array('Day', 'Month', 'Year', 'Hour', 'Minute', 'Meridian');
2506: $attrs = array_fill_keys($keys, $attributes);
2507:
2508: $hasId = isset($attributes['id']);
2509: if ($hasId && is_array($attributes['id'])) {
2510:
2511: $attributes['id'] += array(
2512: 'month' => '',
2513: 'year' => '',
2514: 'day' => '',
2515: 'hour' => '',
2516: 'minute' => '',
2517: 'meridian' => ''
2518: );
2519: foreach ($keys as $key) {
2520: $attrs[$key]['id'] = $attributes['id'][strtolower($key)];
2521: }
2522: }
2523: if ($hasId && is_string($attributes['id'])) {
2524:
2525: foreach ($keys as $key) {
2526: $attrs[$key]['id'] = $attributes['id'] . $key;
2527: }
2528: }
2529:
2530: if (is_array($attributes['empty'])) {
2531: $attributes['empty'] += array(
2532: 'month' => true,
2533: 'year' => true,
2534: 'day' => true,
2535: 'hour' => true,
2536: 'minute' => true,
2537: 'meridian' => true
2538: );
2539: foreach ($keys as $key) {
2540: $attrs[$key]['empty'] = $attributes['empty'][strtolower($key)];
2541: }
2542: }
2543:
2544: $selects = array();
2545: foreach (preg_split('//', $dateFormat, -1, PREG_SPLIT_NO_EMPTY) as $char) {
2546: switch ($char) {
2547: case 'Y':
2548: $attrs['Year']['value'] = $year;
2549: $selects[] = $this->year(
2550: $fieldName, $minYear, $maxYear, $attrs['Year']
2551: );
2552: break;
2553: case 'M':
2554: $attrs['Month']['value'] = $month;
2555: $attrs['Month']['monthNames'] = $monthNames;
2556: $selects[] = $this->month($fieldName, $attrs['Month']);
2557: break;
2558: case 'D':
2559: $attrs['Day']['value'] = $day;
2560: $selects[] = $this->day($fieldName, $attrs['Day']);
2561: break;
2562: }
2563: }
2564: $opt = implode($separator, $selects);
2565:
2566: $attrs['Minute']['interval'] = $interval;
2567: switch ($timeFormat) {
2568: case '24':
2569: $attrs['Hour']['value'] = $hour;
2570: $attrs['Minute']['value'] = $min;
2571: $opt .= $this->hour($fieldName, true, $attrs['Hour']) . ':' .
2572: $this->minute($fieldName, $attrs['Minute']);
2573: break;
2574: case '12':
2575: $attrs['Hour']['value'] = $hour;
2576: $attrs['Minute']['value'] = $min;
2577: $attrs['Meridian']['value'] = $meridian;
2578: $opt .= $this->hour($fieldName, false, $attrs['Hour']) . ':' .
2579: $this->minute($fieldName, $attrs['Minute']) . ' ' .
2580: $this->meridian($fieldName, $attrs['Meridian']);
2581: break;
2582: }
2583: return $opt;
2584: }
2585:
2586: 2587: 2588: 2589: 2590: 2591: 2592:
2593: protected function _getDateTimeValue($value, $timeFormat) {
2594: $year = $month = $day = $hour = $min = $meridian = null;
2595: if (is_array($value)) {
2596: extract($value);
2597: if ($meridian === 'pm') {
2598: $hour += 12;
2599: }
2600: return array($year, $month, $day, $hour, $min, $meridian);
2601: }
2602:
2603: if (is_numeric($value)) {
2604: $value = strftime('%Y-%m-%d %H:%M:%S', $value);
2605: }
2606: $meridian = 'am';
2607: $pos = strpos($value, '-');
2608: if ($pos !== false) {
2609: $date = explode('-', $value);
2610: $days = explode(' ', $date[2]);
2611: $day = $days[0];
2612: $month = $date[1];
2613: $year = $date[0];
2614: } else {
2615: $days[1] = $value;
2616: }
2617:
2618: if (!empty($timeFormat)) {
2619: $time = explode(':', $days[1]);
2620:
2621: if ($time[0] >= 12) {
2622: $meridian = 'pm';
2623: }
2624: $hour = $min = null;
2625: if (isset($time[1])) {
2626: $hour = $time[0];
2627: $min = $time[1];
2628: }
2629: }
2630: return array($year, $month, $day, $hour, $min, $meridian);
2631: }
2632:
2633: 2634: 2635: 2636: 2637: 2638: 2639: 2640:
2641: protected function _name($options = array(), $field = null, $key = 'name') {
2642: if ($this->requestType === 'get') {
2643: if ($options === null) {
2644: $options = array();
2645: } elseif (is_string($options)) {
2646: $field = $options;
2647: $options = 0;
2648: }
2649:
2650: if (!empty($field)) {
2651: $this->setEntity($field);
2652: }
2653:
2654: if (is_array($options) && isset($options[$key])) {
2655: return $options;
2656: }
2657:
2658: $entity = $this->entity();
2659: $model = $this->model();
2660: $name = $model === $entity[0] && isset($entity[1]) ? $entity[1] : $entity[0];
2661: $last = $entity[count($entity) - 1];
2662: if (in_array($last, $this->_fieldSuffixes)) {
2663: $name .= '[' . $last . ']';
2664: }
2665:
2666: if (is_array($options)) {
2667: $options[$key] = $name;
2668: return $options;
2669: }
2670: return $name;
2671: }
2672: return parent::_name($options, $field, $key);
2673: }
2674:
2675: 2676: 2677: 2678: 2679: 2680: 2681: 2682: 2683:
2684: protected function _selectOptions($elements = array(), $parents = array(), $showParents = null, $attributes = array()) {
2685: $select = array();
2686: $attributes = array_merge(
2687: array('escape' => true, 'style' => null, 'value' => null, 'class' => null),
2688: $attributes
2689: );
2690: $selectedIsEmpty = ($attributes['value'] === '' || $attributes['value'] === null);
2691: $selectedIsArray = is_array($attributes['value']);
2692:
2693: $this->_domIdSuffixes = array();
2694: foreach ($elements as $name => $title) {
2695: $htmlOptions = array();
2696: if (is_array($title) && (!isset($title['name']) || !isset($title['value']))) {
2697: if (!empty($name)) {
2698: if ($attributes['style'] === 'checkbox') {
2699: $select[] = $this->Html->useTag('fieldsetend');
2700: } else {
2701: $select[] = $this->Html->useTag('optiongroupend');
2702: }
2703: $parents[] = $name;
2704: }
2705: $select = array_merge($select, $this->_selectOptions(
2706: $title, $parents, $showParents, $attributes
2707: ));
2708:
2709: if (!empty($name)) {
2710: $name = $attributes['escape'] ? h($name) : $name;
2711: if ($attributes['style'] === 'checkbox') {
2712: $select[] = $this->Html->useTag('fieldsetstart', $name);
2713: } else {
2714: $select[] = $this->Html->useTag('optiongroup', $name, '');
2715: }
2716: }
2717: $name = null;
2718: } elseif (is_array($title)) {
2719: $htmlOptions = $title;
2720: $name = $title['value'];
2721: $title = $title['name'];
2722: unset($htmlOptions['name'], $htmlOptions['value']);
2723: }
2724:
2725: if ($name !== null) {
2726: $isNumeric = is_numeric($name);
2727: if (
2728: (!$selectedIsArray && !$selectedIsEmpty && (string)$attributes['value'] == (string)$name) ||
2729: ($selectedIsArray && in_array((string)$name, $attributes['value'], !$isNumeric))
2730: ) {
2731: if ($attributes['style'] === 'checkbox') {
2732: $htmlOptions['checked'] = true;
2733: } else {
2734: $htmlOptions['selected'] = 'selected';
2735: }
2736: }
2737:
2738: if ($showParents || (!in_array($title, $parents))) {
2739: $title = ($attributes['escape']) ? h($title) : $title;
2740:
2741: $hasDisabled = !empty($attributes['disabled']);
2742: if ($hasDisabled) {
2743: $disabledIsArray = is_array($attributes['disabled']);
2744: if ($disabledIsArray) {
2745: $disabledIsNumeric = is_numeric($name);
2746: }
2747: }
2748: if (
2749: $hasDisabled &&
2750: $disabledIsArray &&
2751: in_array((string)$name, $attributes['disabled'], !$disabledIsNumeric)
2752: ) {
2753: $htmlOptions['disabled'] = 'disabled';
2754: }
2755: if ($hasDisabled && !$disabledIsArray && $attributes['style'] === 'checkbox') {
2756: $htmlOptions['disabled'] = $attributes['disabled'] === true ? 'disabled' : $attributes['disabled'];
2757: }
2758:
2759: if ($attributes['style'] === 'checkbox') {
2760: $htmlOptions['value'] = $name;
2761:
2762: $tagName = $attributes['id'] . $this->domIdSuffix($name);
2763: $htmlOptions['id'] = $tagName;
2764: $label = array('for' => $tagName);
2765:
2766: if (isset($htmlOptions['checked']) && $htmlOptions['checked'] === true) {
2767: $label['class'] = 'selected';
2768: }
2769:
2770: $name = $attributes['name'];
2771:
2772: if (empty($attributes['class'])) {
2773: $attributes['class'] = 'checkbox';
2774: } elseif ($attributes['class'] === 'form-error') {
2775: $attributes['class'] = 'checkbox ' . $attributes['class'];
2776: }
2777: $label = $this->label(null, $title, $label);
2778: $item = $this->Html->useTag('checkboxmultiple', $name, $htmlOptions);
2779: $select[] = $this->Html->div($attributes['class'], $item . $label);
2780: } else {
2781: if ($attributes['escape']) {
2782: $name = h($name);
2783: }
2784: $select[] = $this->Html->useTag('selectoption', $name, $htmlOptions, $title);
2785: }
2786: }
2787: }
2788: }
2789:
2790: return array_reverse($select, true);
2791: }
2792:
2793: 2794: 2795: 2796: 2797: 2798: 2799:
2800: protected function _generateOptions($name, $options = array()) {
2801: if (!empty($this->options[$name])) {
2802: return $this->options[$name];
2803: }
2804: $data = array();
2805:
2806: switch ($name) {
2807: case 'minute':
2808: if (isset($options['interval'])) {
2809: $interval = $options['interval'];
2810: } else {
2811: $interval = 1;
2812: }
2813: $i = 0;
2814: while ($i < 60) {
2815: $data[sprintf('%02d', $i)] = sprintf('%02d', $i);
2816: $i += $interval;
2817: }
2818: break;
2819: case 'hour':
2820: for ($i = 1; $i <= 12; $i++) {
2821: $data[sprintf('%02d', $i)] = $i;
2822: }
2823: break;
2824: case 'hour24':
2825: for ($i = 0; $i <= 23; $i++) {
2826: $data[sprintf('%02d', $i)] = $i;
2827: }
2828: break;
2829: case 'meridian':
2830: $data = array('am' => 'am', 'pm' => 'pm');
2831: break;
2832: case 'day':
2833: $min = 1;
2834: $max = 31;
2835:
2836: if (isset($options['min'])) {
2837: $min = $options['min'];
2838: }
2839: if (isset($options['max'])) {
2840: $max = $options['max'];
2841: }
2842:
2843: for ($i = $min; $i <= $max; $i++) {
2844: $data[sprintf('%02d', $i)] = $i;
2845: }
2846: break;
2847: case 'month':
2848: if ($options['monthNames'] === true) {
2849: $data['01'] = __d('cake', 'January');
2850: $data['02'] = __d('cake', 'February');
2851: $data['03'] = __d('cake', 'March');
2852: $data['04'] = __d('cake', 'April');
2853: $data['05'] = __d('cake', 'May');
2854: $data['06'] = __d('cake', 'June');
2855: $data['07'] = __d('cake', 'July');
2856: $data['08'] = __d('cake', 'August');
2857: $data['09'] = __d('cake', 'September');
2858: $data['10'] = __d('cake', 'October');
2859: $data['11'] = __d('cake', 'November');
2860: $data['12'] = __d('cake', 'December');
2861: } elseif (is_array($options['monthNames'])) {
2862: $data = $options['monthNames'];
2863: } else {
2864: for ($m = 1; $m <= 12; $m++) {
2865: $data[sprintf("%02s", $m)] = strftime("%m", mktime(1, 1, 1, $m, 1, 1999));
2866: }
2867: }
2868: break;
2869: case 'year':
2870: $current = intval(date('Y'));
2871:
2872: $min = !isset($options['min']) ? $current - 20 : (int)$options['min'];
2873: $max = !isset($options['max']) ? $current + 20 : (int)$options['max'];
2874:
2875: if ($min > $max) {
2876: list($min, $max) = array($max, $min);
2877: }
2878: if (
2879: !empty($options['value']) &&
2880: (int)$options['value'] < $min &&
2881: (int)$options['value'] > 0
2882: ) {
2883: $min = (int)$options['value'];
2884: } elseif (!empty($options['value']) && (int)$options['value'] > $max) {
2885: $max = (int)$options['value'];
2886: }
2887:
2888: for ($i = $min; $i <= $max; $i++) {
2889: $data[$i] = $i;
2890: }
2891: if ($options['order'] !== 'asc') {
2892: $data = array_reverse($data, true);
2893: }
2894: break;
2895: }
2896: $this->_options[$name] = $data;
2897: return $this->_options[$name];
2898: }
2899:
2900: 2901: 2902: 2903: 2904: 2905: 2906: 2907: 2908: 2909: 2910: 2911: 2912: 2913: 2914: 2915: 2916:
2917: protected function _initInputField($field, $options = array()) {
2918: if (isset($options['secure'])) {
2919: $secure = $options['secure'];
2920: unset($options['secure']);
2921: } else {
2922: $secure = (isset($this->request['_Token']) && !empty($this->request['_Token']));
2923: }
2924:
2925: $disabledIndex = array_search('disabled', $options, true);
2926: if (is_int($disabledIndex)) {
2927: unset($options[$disabledIndex]);
2928: $options['disabled'] = true;
2929: }
2930:
2931: $result = parent::_initInputField($field, $options);
2932: if ($this->tagIsInvalid() !== false) {
2933: $result = $this->addClass($result, 'form-error');
2934: }
2935:
2936: if (!empty($result['disabled'])) {
2937: return $result;
2938: }
2939:
2940: if (!isset($result['required']) &&
2941: $this->_introspectModel($this->model(), 'validates', $this->field())
2942: ) {
2943: $result['required'] = true;
2944: }
2945:
2946: if ($secure === self::SECURE_SKIP) {
2947: return $result;
2948: }
2949:
2950: $this->_secure($secure, $this->_secureFieldName($options));
2951: return $result;
2952: }
2953:
2954: 2955: 2956: 2957: 2958: 2959: 2960: 2961: 2962:
2963: protected function _secureFieldName($options) {
2964: if (isset($options['name'])) {
2965: preg_match_all('/\[(.*?)\]/', $options['name'], $matches);
2966: if (isset($matches[1])) {
2967: return $matches[1];
2968: }
2969: }
2970: return null;
2971: }
2972:
2973: 2974: 2975: 2976: 2977: 2978: 2979:
2980: public function inputDefaults($defaults = null, $merge = false) {
2981: if ($defaults !== null) {
2982: if ($merge) {
2983: $this->_inputDefaults = array_merge($this->_inputDefaults, (array)$defaults);
2984: } else {
2985: $this->_inputDefaults = (array)$defaults;
2986: }
2987: }
2988: return $this->_inputDefaults;
2989: }
2990:
2991: }
2992: