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