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