/mvc/helpers/form
[return to app]1
<?php
2 /**
3 * Form-related helper tools
4 */
5 class formHelper {
6 /**
7 * Internal flag to keep track if a form tag has been opened and not yet closed
8 * @var boolean
9 */
10 private $_formOpen = false;
11
12 /**
13 * Internal form element counter
14 * @var int
15 */
16 private $_inputCounter = array();
17
18 /**
19 * Default value for addBreak
20 * @var Boolean Defaults to true
21 */
22 public $addBreak = true;
23
24 /**
25 * Converts dynamically-assigned array indecies to use an explicitely defined index
26 *
27 * @param string $name
28 * @return string
29 */
30 protected function _indexDynamicArray($name) {
31 $dynamicArrayStart = strpos($name, '[]');
32 if ($dynamicArrayStart) {
33 $prefix = substr($name, 0, $dynamicArrayStart);
34 if (!isset($this->_inputCounter[$prefix])) {
35 $this->_inputCounter[$prefix] = -1;
36 }
37 $name = $prefix . '[' . ++$this->_inputCounter[$prefix] . substr($name, ($dynamicArrayStart + 1));
38 }
39 return $name;
40 }
41
42 /**
43 * Form types that do not change value with user input
44 * @var array
45 */
46 protected $_staticTypes = array('hidden', 'submit', 'button', 'image');
47
48 /**
49 * Sets the standard properties available to all input elements in addition to user-defined properties
50 * Standard properties are: name, value, class, style, id
51 *
52 * @param array $args
53 * @param array $propertyNames Optional, an array of user-defined properties
54 * @return array
55 */
56 protected function _getProperties(array $args, array $propertyNames = array()) {
57 $method = (isset($this->_formOpen['method']) && $this->_formOpen['method'] == 'get' ? $_GET : $_POST);
58 if (isset($args['name']) && (!isset($args['type']) || !in_array($args['type'], $this->_staticTypes))) {
59 $arrayStart = strpos($args['name'], '[');
60 if (!$arrayStart) {
61 if (isset($method[$args['name']])) {
62 $args['value'] = $method[$args['name']];
63 }
64 } else {
65 $name = $this->_indexDynamicArray($args['name']);
66 if (preg_match_all('/\[(.*)\]/', $name, $arrayIndex)) {
67 array_shift($arrayIndex); //dump the 0 index element containing full match string
68 }
69 $name = substr($name, 0, $arrayStart);
70 if (isset($method[$name])) {
71 $args['value'] = $method[$name];
72 if (!isset($args['type']) || $args['type'] != 'checkbox') {
73 foreach ($arrayIndex as $idx) {
74 if (isset($args['value'][current($idx)])) {
75 $args['value'] = $args['value'][current($idx)];
76 } else {
77 unset($args['value']);
78 break;
79 }
80 }
81 }
82 }
83 }
84 }
85 $return = array();
86 $validProperties = array_merge($propertyNames, array('name', 'value', 'class', 'style', 'id'));
87 foreach ($validProperties as $propertyName) {
88 if (isset($args[$propertyName])) {
89 $return[$propertyName] = $args[$propertyName];
90 }
91 }
92 return $return;
93 }
94
95 /**
96 * Begins a form
97 * Includes a safety mechanism to prevent re-opening an already-open form
98 *
99 * @param array $args
100 * @return string
101 */
102 public function open(array $args = array()) {
103 if (!$this->_formOpen) {
104 if (!isset($args['method'])) {
105 $args['method'] = 'post';
106 }
107
108 $this->_formOpen = array('id' => (isset($args['id']) ? $args['id'] : true),
109 'method' => $args['method']);
110
111 if (!isset($args['action'])) {
112 $args['action'] = $_SERVER['REQUEST_URI'];
113 }
114 if (isset($args['upload']) && $args['upload'] && !isset($args['enctype'])) {
115 $args['enctype'] = 'multipart/form-data';
116 }
117 if (isset($args['legend'])) {
118 $legend = $args['legend'];
119 unset($args['legend']);
120 if (!isset($args['title'])) {
121 $args['title'] = $legend;
122 }
123 } else if (isset($args['title'])) {
124 $legend = $args['title'];
125 }
126 if (isset($args['alert'])) {
127 if ($args['alert']) {
128 $alert = (is_array($args['alert']) ? implode('<br />', $args['alert']) : $args['alert']);
129 }
130 unset($args['alert']);
131 }
132 $return = '<form ' . htmlHelper::formatProperties($args) . '>' . PHP_EOL . '<fieldset>' . PHP_EOL;
133 if (isset($legend)) {
134 $return .= '<legend>' . $legend . '</legend>' . PHP_EOL;
135 }
136 if (isset($alert)) {
137 $return .= $this->getErrorMessageContainer((isset($args['id']) ? $args['id'] : 'form'), $alert);
138 }
139 return $return;
140 } else if (DEBUG_MODE) {
141 $errorMsg = 'Invalid usage of ' . __METHOD__ . '() - a form is already open';
142 trigger_error($errorMsg, E_USER_NOTICE);
143 }
144 }
145
146 /**
147 * Closes a form if one is open
148 *
149 * @return string
150 */
151 public function close() {
152 if ($this->_formOpen) {
153 $this->_formOpen = false;
154 return '</fieldset>' . PHP_EOL . '</form>' . PHP_EOL;
155 } else if (DEBUG_MODE) {
156 $errorMsg = 'Invalid usage of ' . __METHOD__ . '() - there is no open form to close';
157 trigger_error($errorMsg, E_USER_NOTICE);
158 }
159 }
160
161 /**
162 * Adds label tags to a form element
163 *
164 * @param array $args
165 * @param str $formElement
166 * @return str
167 */
168 protected function _getLabel(array $args, $formElement) {
169 if (!isset($args['label']) && isset($args['name'])
170 && (!isset($args['type']) || !in_array($args['type'], $this->_staticTypes))) {
171 $args['label'] = ucfirst($args['name']);
172 }
173
174 if (isset($args['label'])) {
175 $label = (!isset($args['htmlok']) || !$args['htmlok'] ? get::xhtmlentities($args['label']) :
$args['label']);
176 if (isset($_POST['errors']) && isset($args['name']) && isset($_POST['errors'][$args['name']])) {
177 $label .= ' ' . $this->getErrorMessageContainer($args['name'], $_POST['errors'][$args['name']]);
178 }
179 $labelFirst = (!isset($args['labelFirst']) || $args['labelFirst']);
180 if (isset($args['id'])) {
181 $label = '<label for="' . $args['id'] . '" id="' . $args['id'] . 'label">' . $label . '</label>';
182 }
183 if (isset($args['addBreak']) && $args['addBreak']) {
184 $label = ($labelFirst ? $label . '<br />' . PHP_EOL : '<br />' . PHP_EOL . $label);
185 }
186 $formElement = ($labelFirst ? $label . $formElement : $formElement . $label);
187 if (!isset($args['id'])) {
188 $formElement = '<label>' . $formElement . '</label>';
189 }
190 }
191 return $formElement;
192 }
193
194 /**
195 * Returns a standardized container to wrap an error message
196 *
197 * @param string $id
198 * @param string $errorMessage Optional, you may want to leave this blank and populate dynamically via
JavaScript
199 * @return string
200 */
201 public function getErrorMessageContainer($id, $errorMessage = '') {
202 return '<span class="errormessage" id="' . $id . 'errorwrapper">'
203 . get::xhtmlentities($errorMessage) . '</span>';
204 }
205
206 /**
207 * Internal counters used by the wysiwygTextarea system
208 * @var int
209 */
210 protected $_wysiwygTextareaCount = 0, $_wysiwygTextareaDefaultInitSent = 0;
211
212 /**
213 * Initializes WYSIWYG system
214 * docs at: http://wiki.moxiecode.com/index.php/TinyMCE:Configuration
215 *
216 * @param array $args Optional
217 * @return string
218 */
219 public function wysiwygTextareaInit(array $args = array()) {
220 $init = array(
221 'theme' => 'advanced',
222 'plugins' => 'spellchecker,xhtmlxtras,searchreplace,advlink,advimage,media,fullscreen',
223 'mode' => 'specific_textareas',
224 'editor_selector' => 'wysiwyg',
225 'theme_advanced_buttons1' => 'bold,italic,|,formatselect,|,'
226 . 'justifyleft,justifycenter,justifyright,justifyfull,|,'
227 . 'bullist,numlist,sub,sup,blockquote,cite,abbr,acronym,|,'
228 . 'indent,outdent,|,link,unlink,|,image,media,hr,charmap,|,code,cleanup,|,'
229 . 'search,replace,|,spellchecker,|,fullscreen',
230 'theme_advanced_buttons2' => '',
231 'theme_advanced_buttons3' => '',
232 'theme_advanced_blockformats' => 'p,h1,h2,h3,h4',
233 'theme_advanced_toolbar_location' => 'top',
234 'skin' => 'o2k7',
235 'extended_valid_elements' => 'a[name|href|target|title|onclick]',
236 'relative_urls' => false
237 );
238 $html = get::helper('html');
239 $initJsObj = $return[] = $html->jsInline('var vorkInitTinyMce = ' . json_encode($init));
240 $init = array_merge($args, $init);
241 if (!isset($args['nocache'])) {
242 $return[] = $html->js('/js/tinymce/tiny_mce_gzip.js');
243 $return[] = $html->jsInline('tinyMCE_GZ.init({theme: "' . $init['theme']
244 . '", plugins: "' . $init['plugins']
245 . '", disk_cache: ' . (isset($init['disk_cache'])
246 ? $init['disk_cache'] : 'true') . '});');
247
248 }
249 $return[] = $html->js('/js/tinymce/tiny_mce.js');
250 return implode(PHP_EOL, $return);
251 }
252
253 /**
254 * Adds WYSIWYG capabilities to a textarea
255 * This is a simplified interface to $this->createWysiwygTextareaParts() and $this->wysiwygTextareaParts
256 *
257 * @param array $args Optional
258 * @return string
259 */
260 public function wysiwygTextarea(array $args = array()) {
261 $return = (!$this->_wysiwygTextareaCount++ ? $this->wysiwygTextareaInit($args) : '');
262 unset($args['disk_cache']); //only used in the init gzip
263 if ($args) {
264 $jsObj = 'vorkTinyMce' . $this->_wysiwygTextareaCount;
265 $js = 'var ' . $jsObj . ' = vorkInitTinyMce;';
266 foreach ($args as $key => $val) {
267 $js .= PHP_EOL . $jsObj . '.' . $key . ' = '
268 . (!in_array($val, array('true', 'false')) ? '"' . $val . '"' : $val) . ';';
269 }
270 $js .= PHP_EOL . 'tinyMCE.init(' . $jsObj . ');';
271 $return .= get::helper('html')->jsInline($js);
272 } else if (!$this->_wysiwygTextareaDefaultInitSent++) {
273 $return .= get::helper('html')->jsInline('tinyMCE.init(vorkInitTinyMce);');
274 }
275 return $return;
276 }
277
278 /**
279 * Sanitizes a string for use as an ID by swapping brackets with underscores
280 *
281 * @param string $str
282 * @return string
283 */
284 protected function _getValidId($str) {
285 return str_replace(array('[', ']'), '_', $str);
286 }
287
288 /**
289 * Used for text, textarea (standard and WYSIWYG,) hidden, password, file, button, image and submit
290 *
291 * Valid args are any properties valid within an HTML input as well as label
292 *
293 * @param array $args
294 * @return string
295 */
296 public function input(array $args) {
297 $args['type'] = (isset($args['type']) ? $args['type'] : 'text');
298
299 switch ($args['type']) {
300 case 'select':
301 return $this->select($args);
302 break;
303 case 'checkbox':
304 return $this->checkboxes($args);
305 break;
306 case 'radio':
307 return $this->radios($args);
308 break;
309 }
310
311 if ($args['type'] == 'textarea' && isset($args['maxlength'])) {
312 if (!isset($args['id']) && isset($args['name'])) {
313 $args['id'] = $this->_getValidId($args['name']);
314 }
315 if (isset($args['id'])) {
316 $maxlength = $args['maxlength'];
317 }
318 unset($args['maxlength']);
319 }
320
321 if ($args['type'] == 'submit' && !isset($args['class'])) {
322 $args['class'] = $args['type'];
323 }
324
325 $takeFocus = (isset($args['focus']) && $args['focus'] && $args['type'] != 'hidden');
326 if ($takeFocus && !isset($args['id'])) {
327 if (isset($args['name'])) {
328 $args['id'] = $this->_getValidId($args['name']);
329 } else {
330 $takeFocus = false;
331 if (DEBUG_MODE) {
332 $errorMsg = 'Either name or id is required to use the focus option on a form input';
333 trigger_error($errorMsg, E_USER_NOTICE);
334 }
335 }
336 }
337
338 if (isset($args['wysiwyg']) && $args['wysiwyg']) {
339 $args['class'] = (!isset($args['class']) ? 'wysiwyg' : $args['class'] . ' wysiwyg');
340 }
341 $properties = $this->_getProperties($args, array('type', 'maxlength'));
342
343 if ($args['type'] == 'image') {
344 $properties['src'] = $args['src'];
345 $properties['alt'] = (isset($args['alt']) ? $args['alt'] : '');
346 $optionalProperties = array('height', 'width');
347 foreach ($optionalProperties as $optionalProperty) {
348 if (isset($args[$optionalProperty])) {
349 $properties[$optionalProperty] = $args[$optionalProperty];
350 }
351 }
352 }
353
354 if (!class_exists('htmlHelper')) {
355 get::helper('html');
356 }
357 if ($args['type'] != 'textarea') {
358 $return[] = '<input ' . htmlHelper::formatProperties($properties) . ' />' . PHP_EOL;
359 } else {
360 unset($properties['type']);
361 if (isset($properties['value'])) {
362 $value = $properties['value'];
363 unset($properties['value']);
364 }
365 if (isset($args['preview']) && $args['preview'] && !isset($properties['id'])) {
366 $properties['id'] = 'textarea_' . rand(100, 999);
367 }
368 $properties['rows'] = (isset($args['rows']) ? $args['rows'] : 13);
369 $properties['cols'] = (isset($args['cols']) ? $args['cols'] : 55);
370 $return[] = '<textarea ' . htmlHelper::formatProperties($properties);
371 if (isset($maxlength)) {
372 $return[] = ' onkeyup="document.getElementById(\''
373 . $properties['id'] . 'errorwrapper\').innerHTML = (this.value.length > '
374 . $maxlength . ' ? \'Form content exceeds maximum length of '
375 . $maxlength . ' characters\' : \'Length: \' + this.value.length + \' (maximum: '
376 . $maxlength . ' characters)\')"';
377 }
378 $return[] = '>';
379 if (isset($value)) {
380 $return[] = get::htmlentities($value, null, null, true); //double-encode allowed
381 }
382 $return[] = '</textarea>' . PHP_EOL;
383 if (isset($args['wysiwyg']) && $args['wysiwyg']) {
384 if (!is_array($args['wysiwyg'])) {
385 $args['wysiwyg'] = array();
386 }
387 $return[] = $this->wysiwygTextarea($args['wysiwyg']);
388 }
389 if (isset($maxlength) && (!isset($args['validatedInput']) || !$args['validatedInput'])) {
390 $return[] = $this->getErrorMessageContainer($properties['id']);
391 }
392 }
393 if (!isset($args['addBreak'])) {
394 $args['addBreak'] = $this->addBreak;
395 }
396 if ($takeFocus) {
397 $html = get::helper('html');
398 $return[] = $html->jsInline($html->jsTools(true) . 'dom("' . $args['id'] . '").focus();');
399 }
400 if (isset($args['preview']) && $args['preview']) {
401 $js = 'document.writeln(\'<div class="htmlpreviewlabel">'
402 . '<label for="livepreview_' . $properties['id'] . '">Preview:</label></div>'
403 . '<div id="livepreview_' . $properties['id'] . '" class="htmlpreview"></div>\');' . PHP_EOL
404 . 'if (dom("livepreview_' . $properties['id'] . '")) {' . PHP_EOL
405 . ' var updateLivePreview_' . $properties['id'] . ' = '
406 . 'function() {dom("livepreview_' . $properties['id'] . '").innerHTML = '
407 . 'dom("' . $properties['id'] . '").value};' . PHP_EOL
408 . ' dom("' . $properties['id'] . '").onkeyup = updateLivePreview_' . $properties['id'] . ';'
409 . ' updateLivePreview_' . $properties['id'] . '();' . PHP_EOL
410 . '}';
411 if (!isset($html)) {
412 $html = get::helper('html');
413 }
414 $return[] = $html->jsInline($html->jsTools(true) . $js);
415 }
416 return $this->_getLabel($args, implode($return));
417 }
418
419 /**
420 * Returns an input that is validated using the Validator package
421 *
422 * @param array $args
423 * @return string
424 */
425 public function validatedInput(array $args) {
426 $args['validatedInput'] = true;
427 $errorMessage = '';
428 if (isset(Validator::$errors[$this->_formOpen['id']][$args['id']])) {
429 $errorMessage = Validator::$errors[$this->_formOpen['id']][$args['id']];
430 }
431 return $this->input($args) . $this->getErrorMessageContainer($args['id'], $errorMessage);
432 }
433
434 /**
435 * Returns a form select element
436 *
437 * $args = array(
438 * 'name' => '',
439 * 'multiple' => true,
440 * 'leadingOptions' => array(),
441 * 'optgroups' => array('group 1' => array('label' => 'g1o1', 'value' => 'grp 1 opt 1'),
442 * 'group 2' => array(),),
443 * 'options' => array('value1' => 'text1', 'value2' => 'text2', 'value3' => 'text3'),
444 * 'value' => array('value2', 'value3') //if (multiple==false) 'value' => (str) 'value3'
445 * );
446 *
447 * @param array $args
448 * @return str
449 */
450 public function select(array $args) {
451 if (!isset($args['id'])) {
452 $args['id'] = $this->_getValidId($args['name']);
453 }
454 if (isset($args['multiple']) && $args['multiple']) {
455 $args['multiple'] = 'multiple';
456 if (substr($args['name'], -2) != '[]') {
457 $args['name'] .= '[]';
458 }
459 }
460 $properties = $this->_getProperties($args, array('multiple'));
461 $values = (isset($properties['value']) ? $properties['value'] : null);
462 unset($properties['value']);
463 if (!is_array($values)) {
464 $values = ($values != '' ? array($values) : array());
465 }
466 $return = '<select ' . htmlHelper::formatProperties($properties) . '>' . PHP_EOL;
467 if (isset($args['prependBlank']) && $args['prependBlank']) {
468 $return .= '<option value=""></option>' . PHP_EOL;
469 }
470
471 if (isset($args['leadingOptions'])) {
472 $useValues = (key($args['leadingOptions']) !== 0
473 || (isset($args['useValue']) && $args['useValue']));
474 foreach ($args['leadingOptions'] as $value => $text) {
475 if (!$useValues) {
476 $value = $text;
477 }
478 $return .= '<option value="' . get::htmlentities($value) . '">'
479 . get::htmlentities($text) . '</option>' . PHP_EOL;
480 }
481 }
482
483 if (isset($args['optgroups'])) {
484 foreach ($args['optgroups'] as $groupLabel => $optgroup) {
485 $return .= '<optgroup label="' . get::htmlentities($groupLabel) . '">' . PHP_EOL;
486 foreach ($optgroup as $value => $label) {
487 $return .= '<option value="' . get::htmlentities($value) . '"';
488 if (isset($label)) {
489 $return .= ' label="' . get::htmlentities($label) . '"';
490 }
491 if (in_array($value, $values)) {
492 $return .= ' selected="selected"';
493 }
494 $return .= '>' . get::htmlentities($label) . '</option>' . PHP_EOL;
495 }
496 $return .= '</optgroup>' . PHP_EOL;
497 }
498 }
499
500 if (isset($args['options'])) {
501 $useValues = (key($args['options']) !== 0 || (isset($args['useValue']) && $args['useValue']));
502 foreach ($args['options'] as $value => $text) {
503 if (!$useValues) {
504 $value = $text;
505 }
506 $return .= '<option value="' . get::htmlentities($value) . '"';
507 if (in_array($value, $values)) {
508 $return .= ' selected="selected"';
509 }
510 $return .= '>' . get::htmlentities($text) . '</option>' . PHP_EOL;
511 }
512 }
513 $return .= '</select>' . PHP_EOL;
514 if (!isset($args['addBreak'])) {
515 $args['addBreak'] = $this->addBreak;
516 }
517 $return = $this->_getLabel($args, $return);
518 if (isset($args['error'])) {
519 $return .= $this->getErrorMessageContainer($args['id'], '<br />' . $args['error']);
520 }
521 return $return;
522 }
523
524 /**
525 * Cache containing individual radio, checkbox and dateSelect-selector elements in an array
526 * @var array
527 */
528 public $radios = array(), $checkboxes = array(), $dateSelect = array();
529
530 /**
531 * Returns a set of radio form elements
532 *
533 * array(
534 * 'name' => '',
535 * 'value' => '',
536 * 'id' => '',
537 * 'legend' => '',
538 * 'options' => array('value1' => 'text1', 'value2' => 'text2', 'value3' => 'text3'), // if just one option
exists this can be a string
539 * 'options' => array('text1', 'text2', 'text3'), //also acceptable (cannot do half this, half above syntax)
540 * )
541 *
542 * @param array $args
543 * @return str
544 */
545 public function radios(array $args) {
546 $id = (isset($args['id']) ? $args['id'] : $this->_getValidId($args['name']));
547 $properties = $this->_getProperties($args);
548 if (isset($properties['value'])) {
549 $checked = $properties['value'];
550 unset($properties['value']);
551 }
552 $properties['type'] = (isset($args['type']) ? $args['type'] : 'radio');
553 if (!empty($args['options']) && !is_array($args['options'])) {
554 $args['options'] = (isset($args['label']) ? array($args['options'] => $args['label']) :
array($args['options']));
555 $args['addFieldset'] = false;
556 }
557 $useValues = (key($args['options']) !== 0 || (isset($args['useValue']) && $args['useValue']));
558 foreach ($args['options'] as $value => $text) {
559 if (!$useValues) {
560 $value = $text;
561 }
562 $properties['id'] = $id . '_' . $this->_getValidId(preg_replace('/\W/', '', $value));
563 $properties['value'] = $value;
564 if (isset($checked) &&
565 ((($properties['type'] == 'radio' || !is_array($checked)) && $value == $checked)
566 || ($properties['type'] == 'checkbox' && is_array($checked) && in_array($value, $checked)))) {
567 $properties['checked'] = 'checked';
568 $rowClass = (!isset($properties['class']) ? 'checked' : $properties['class'] . ' checked');
569 }
570 $labelFirst = (isset($args['labelFirst']) ? $args['labelFirst'] : false);
571 $labelArgs = array('label' => $text, 'id' => $properties['id'], 'labelFirst' => $labelFirst);
572 if (isset($args['htmlok'])) {
573 $labelArgs['htmlok'] = $args['htmlok'];
574 }
575 $input = '<input ' . htmlHelper::formatProperties($properties) . ' />';
576 $row = $this->_getLabel($labelArgs, $input);
577 if (isset($rowClass)) {
578 $row = '<span class="' . $rowClass . '">' . $row . '</span>';
579 }
580 $radios[] = $row;
581 unset($properties['checked'], $rowClass);
582 }
583 $this->{$properties['type'] == 'radio' ? 'radios' : 'checkboxes'} = $radios;
584 $break = (!isset($args['addBreak']) ? '<br />' . PHP_EOL : $args['addBreak']);
585 $addFieldset = (isset($args['addFieldset']) ? $args['addFieldset'] : ((isset($args['label']) &&
$args['label']) || count($args['options']) > 1));
586 if ($addFieldset) {
587 $return = '<fieldset id="' . $id . '">' . PHP_EOL;
588 if (isset($args['label'])) {
589 $return .= '<legend>' . get::xhtmlentities($args['label']) . '</legend>' . PHP_EOL;
590 }
591 $return .= implode($break, $radios) . '</fieldset>' . PHP_EOL;
592 } else {
593 $return = implode($break, $radios);
594 }
595 if (isset($_POST['errors']) && isset($_POST['errors'][$id])) {
596 $return = $this->getErrorMessageContainer($id, $_POST['errors'][$id]) . $return;
597 }
598 return $return;
599 }
600
601 /**
602 * Returns a set of checkbox form elements
603 *
604 * This method essentially extends the getRadios method and uses an identical signature except
605 * that $args['value'] can also accept an array of values to be checked.
606 *
607 * @param array $args
608 * @return str
609 */
610 public function checkboxes(array $args) {
611 $args['type'] = 'checkbox';
612 if (isset($args['value']) && !is_array($args['value'])) {
613 $args['value'] = array($args['value']);
614 }
615 $nameParts = explode('[', $args['name']);
616 if (!isset($args['id'])) {
617 $args['id'] = $this->_getValidId($nameParts[0]);
618 }
619 if (!isset($nameParts[1]) && count($args['options']) > 1) {
620 $args['name'] .= '[]';
621 }
622 return $this->radios($args);
623 }
624
625 /**
626 * Months of the year in the format commonly used when entering credit cards
627 * @var array
628 */
629 public $months = array(1 => '01 - January', '02 - February', '03 - March', '04 - April',
630 '05 - May', '06 - June', '07 - July', '08 - August',
631 '09 - September', '10 - October', '11 - November', '12 - December');
632
633 /**
634 * Creates a Date selection box
635 *
636 * @param array $args
637 * @return string
638 */
639 public function dateSelect(array $args) {
640 $includeTime = ((isset($args['time']) && $args['time'])
641 || isset($args['hour']) || isset($args['minute']) || isset($args['mil']));
642 $includeDate = (!isset($args['date']) || $args['date'] || !$includeTime /* must show something */);
643
644 if (!isset($args['addBreak'])) {
645 $args['addBreak'] = false;
646 }
647
648 $dateParts = ($includeDate ? array('month' => 'm', 'day' => 'j', 'year' => 'Y') : array());
649 if ($includeTime) {
650 $dateParts['hour'] = 'h';
651 $dateParts['minute'] = 'i';
652 $isMil = (isset($args['mil']) && $args['mil']);
653 if (!isset($args['ampm']) && isset($args['pmam'])) {
654 $args['ampm'] = $args['pmam'];
655 }
656 if (!$isMil) {
657 $dateParts['ampm'] = 'p';
658 }
659 if (!isset($args['hour']['options'])) {
660 $args['hour']['options'] = (!$isMil ? range(1, 12) : range(0, 23));
661 }
662 if (!isset($args['minute']['options'])) {
663 if (isset($args['minute']['increment'])) {
664 switch ($args['minute']['increment']) {
665 case 5:
666 $minutes = range(10, 55, 5);
667 array_unshift($minutes, '00', '05');
668 break;
669 case 10:
670 $minutes = range(10, 50, 10);
671 array_unshift($minutes, '00');
672 break;
673 case 15:
674 $minutes = array(00, 15, 30, 45);
675 break;
676 case 20:
677 $minutes = array(00, 20, 40);
678 break;
679 case 30:
680 $minutes = array(00, 30);
681 break;
682 }
683 } else {
684 $minutes = range(0, 59);
685 }
686 foreach ($minutes as $x) {
687 $args['minute']['options'][] = str_pad($x, 2, '0', STR_PAD_LEFT);
688 }
689 }
690 if (!isset($args['hour']['label'])) {
691 $args['hour']['label'] = 'Time';
692 }
693 if (!isset($args['minute']['label'])) {
694 $args['minute']['label'] = ':';
695 }
696 if (!$isMil) {
697 if (!isset($args['ampm']['options'])) {
698 $args['ampm']['options'] = array('AM', 'PM');
699 }
700 if (!isset($args['ampm']['label'])) {
701 $args['ampm']['label'] = '';
702 }
703 }
704 if (isset($args['ampm']['value'])) {
705 $args['ampm']['value'] = strtoupper($args['ampm']['value']);
706 }
707 }
708
709 if ($includeDate) {
710 if (!isset($args['month']['options'])) {
711 $selectArgs['month']['options'] = $this->months;
712 }
713
714 $selectArgs['day']['options'] = range(1, 31);
715
716 $datePart = 'year';
717 if (!isset($args[$datePart]['start'])) {
718 $args[$datePart]['start'] = date($dateParts[$datePart]);
719 }
720 if (!isset($args['year']['end'])) {
721 $args[$datePart]['end'] = ($args[$datePart]['start'] - 100);
722 }
723 $selectArgs['year']['options'] = range(current($args[$datePart]), next($args[$datePart]));
724 }
725
726 $method = (isset($this->_formOpen['method']) && $this->_formOpen['method'] == 'get' ? $_GET : $_POST);
727 foreach ($dateParts as $dateType => $unixCode) {
728 $selectArgs[$dateType]['name'] = $args['name'] . '[' . $dateType . ']';
729 $selectArgs[$dateType]['id'] = $this->_getValidId($args['name']) . '_' . $dateType;
730 if (isset($args[$dateType])) {
731 $selectArgs[$dateType] = array_merge($args[$dateType], $selectArgs[$dateType]);
732 }
733 if (!isset($selectArgs[$dateType]['label'])) {
734 $selectArgs[$dateType]['label'] = ucfirst($dateType);
735 }
736 if (isset($method[$args['name']][$dateType])) {
737 $selectArgs[$dateType]['value'] = $method[$args['name']][$dateType];
738 } else if (isset($args['value'][$dateType])) {
739 $selectArgs[$dateType]['value'] = $args['value'][$dateType];
740 }
741 $this->dateSelect[] = $this->select(array_merge($args, $selectArgs[$dateType]));
742 }
743 $return = '<fieldset class="dateselect';
744 if (isset($args['class'])) {
745 $return .= ' ' . $args['class'];
746 }
747 $return .= '"';
748 if (isset($args['id'])) {
749 $return .= ' id="' . $args['id'] . '"';
750 }
751 $return .= '>';
752 if (isset($args['label'])) {
753 $return .= '<legend>' . get::htmlentities($args['label']) . '</legend>' . PHP_EOL;
754 }
755 $return .= implode($this->dateSelect) . '</fieldset>' . PHP_EOL;
756 return $return;
757 }
758
759 /**
760 * Opens up shorthand usage of form elements like $form->file() and $form->submit()
761 * The $legacyNames section keeps legacy naming convention working. New applications can safely remove this
section.
762 *
763 * @param string $name
764 * @param array $args
765 * @return mixed
766 */
767 public function __call($name, array $args) {
768 $inputShorthand = array('text', 'textarea', 'password', 'file', 'hidden', 'submit', 'button', 'image');
769 if (in_array($name, $inputShorthand)) {
770 if (!is_array($args[0]) && $args[0]) { //shortcut strings
771 $defaultKey = 'name';
772 if ($name == 'submit' && !isset($args[1])) {
773 $defaultKey = 'value';
774 }
775 $args[0] = array($defaultKey => $args[0]);
776 if (isset($args[1]) && !is_array($args[1]) && $args[1]) {
777 $args[0][$name != 'image' ? 'value' : 'src'] = $args[1];
778 }
779 }
780 $args[0]['type'] = $name;
781 return $this->input($args[0]);
782 }
783
784 $legacyNames = array('getFormOpen' => 'open', 'getFormClose' => 'close',
785 'getInput' => 'input', 'getValidatedInput' => 'validatedInput', 'getRadios' =>
'radios',
786 'getSelect' => 'select', 'getDateSelect' => 'dateSelect', 'getCheckboxes' =>
'checkboxes');
787 if (isset($legacyNames[$name])) {
788 return call_user_func_array(array($this, $legacyNames[$name]), $args);
789 } else {
790 trigger_error('Call to undefined method ' . __CLASS__ . '::' . $name . '()', E_USER_ERROR);
791 }
792 }
793 }