Overview
Packages
Classes
1: <?php
2:
3: /**
4: * Onion Framework - Vytváranie formulárov
5: *
6: * Copyright (c) 2011 Jano Gašpar (http://webstranky.net)
7: *
8: * @author Jano Gašpar
9: * @copyright Copyright (c) 2011 Jano Gašpar
10: * @package Onion::UI
11: **/
12:
13: class Form implements Iterator, Countable, ArrayAccess
14: {
15: private $app;
16:
17:
18: /**
19: * @var string adresa, kam odoslať formulár
20: */
21: private $action;
22:
23:
24: /**
25: * @var string kotva ktorá sa má pridať k adrese na odoslanie
26: */
27: private $anchor;
28:
29:
30: /**
31: * @var string #id
32: */
33: public $css_id;
34:
35:
36: /**
37: * @var string #class
38: */
39: public $css_class;
40:
41:
42: /**
43: * @var string metóda odoslania formulára
44: */
45: private $method;
46:
47: /**
48: * @var string kódovanie odoslaných dát
49: */
50: private $enctype;
51:
52:
53: /**
54: * @var int maximálna veľkosť odoslaných súborov
55: */
56: private $max_file_size;
57:
58:
59: /**
60: * @var string token na identifikáciu formulára
61: */
62: private $token;
63:
64:
65: /**
66: * @var array aktuálna položka formulára
67: */
68: private $current_item;
69:
70:
71: /**
72: * @var array položky formulára
73: */
74: private $items;
75:
76:
77: /**
78: * @var int východzia hotnota atribútu "cols" elementu "textarea"
79: */
80: private $cols = 50;
81:
82:
83: /**
84: * @var int východzia hotnota atribútu "rows" elementu "textarea"
85: */
86: private $rows = 20;
87:
88:
89: /**
90: * @var array tlačidlá formulára
91: */
92: private $buttons = array();
93:
94:
95: /**
96: * @var bool identifikácia validity všetkých položiek formulára
97: */
98: private $is_valid = FALSE;
99:
100:
101: /**
102: * @var array východzie chybové hlásenia
103: */
104: public $error_messages = array(
105: 'required' => 'This item is required!',
106: 'email' => 'This item must be a valid e-mail address!',
107: 'url' => 'This item must be a valid url!',
108: 'number' => 'This item must be a real number!',
109: 'integer' => 'This item must be an integer number!',
110: 'alpha' => 'This item must be a text with alpanumeic characters!',
111: 'min_len' => 'Táto položka musí mať najmenej %d znakov!',
112: 'max_len' => 'Táto položka musí mať najviac %d znakov!',
113: 'len' => 'Táto položka musí mať presne %d znakov!',
114: 'regexp' => 'Táto položka musí mať presne daný formát!',
115: 'range' => 'Táto položka musí byť v intervale %d - %d!',
116: 'min' => 'Táto položka musí byť číslo väčšie ako %d!',
117: 'max' => 'Táto položka musí byť číslo menšie ako %d!',
118: 'callback' => '!!CALBACK!!',
119: 'equal_to' => 'Táto položka musí byť zhodná s položkou %s!',
120: 'date' => 'Táto položka musí byť dátum vo formáte RRRR-MM-DD, alebo DD. MM. RRRR!',
121:
122: 'files_upload_error' => 'Uploading of the file(s) to the server failed!',
123: 'files_type_error' => 'One or more files is not of the allowed type! The allowed file types are %s.',
124: 'files_size_error' => 'One or more files exceeded the allowed size! The maximum allowed size of a file is %f kb.',
125: );
126:
127:
128: /**
129: * @var array mapa validačných pravidiel a funkcií
130: */
131: private $rules = array(
132: 'email' => array('Validate', 'email'),
133: 'url' => array('Validate', 'url'),
134: 'integer' => array('Validate', 'integer'),
135: 'number' => array('Validate', 'number'),
136: 'alpha' => array('Validate', 'alpha'),
137: 'min_len' => array('Validate', 'min_length'),
138: 'max_len' => array('Validate', 'max_length'),
139: 'eq_len' => array('Validate', 'equal_length'),
140: 'regexp' => array('Validate', 'regexp'),
141: 'range' => array('Validate', 'range'),
142: 'min' => array('Validate', 'min_size'),
143: 'max' => array('Validate', 'max_size'),
144: 'date' => array('Validate', 'date'),
145: 'required' => array('Form', 'validate_required'),
146: 'callback' => array('Form', 'validate_callback'),
147: 'equal_to' => array('Form', 'validate_equal_to'),
148: 'file_type' => array('Form', 'validate_file_type'),
149: );
150:
151:
152: /**
153: * @var int
154: */
155: private $pointer = 0;
156:
157:
158: /**
159: * Konštruktor
160: *
161: * @param string identifikátor formulára
162: * @return object Form pre fluent interface
163: */
164: function __construct($app, $form_id)
165: {
166: $this->app = $app;
167:
168: $this->set_action();
169:
170: //token sa generuje nanovo pre každú reláciu (session)
171: $token = md5(uniqid('', TRUE));
172: if (isset($_SESSION['form']['token'][$form_id]) === TRUE) {
173: $token = $_SESSION['form']['token'][$form_id];
174: }
175: $this->token = $_SESSION['form']['token'][$form_id] = $token;
176:
177: //token sa odosiela s každým formulárom v položke token
178: $this->add_item('hidden', 'token')
179: ->value($token);
180:
181: //detekcia maximálnej veľkosti odosielaných súborov z nastavení PHP
182: $max_file_size_1 = Utils::to_bytes(ini_get('post_max_size'));
183: $max_file_size_2 = Utils::to_bytes(ini_get('upload_max_filesize'));
184: $this->max_file_size = max($max_file_size_1, $max_file_size_2);
185:
186: return $this;
187: }
188:
189:
190: /**
191: * Nastavovanie atribútov položiek formulára pomocuu preťažovania
192: *
193: * @param string meno atribútu
194: * @param mixed hodnota atribútu
195: * @return object Form pre fluent interface
196: */
197: final public function __call($attribute, $value)
198: {
199: if (isset($value[0]) === FALSE) {
200: $value = '';
201:
202: } else {
203: $value = $value[0];
204: }
205:
206: $this->current_item[$attribute] = $value;
207:
208: return $this;
209: }
210:
211:
212: /**
213: * Metóda volaná pri prístupe k objektu ako k reťazcu
214: * @return object Html s formulárom
215: */
216: final public function __tostring()
217: {
218: return $this->render();
219: }
220:
221:
222: /**
223: * Metóda na nastavenie metódy odoslania dát a cieľovej adresy
224: *
225: * @param string metóda odoslania dát post/get
226: * @param string cieľová adresa formulára
227: * @return object Form pre fluent interface
228: */
229: public function set_action($method = 'post', $url = NULL)
230: {
231: if (empty($url) === TRUE) {
232: $url = $this->app->request->uri;
233: }
234:
235: $this->action = $url;
236: $this->method = strtolower($method);
237:
238: return $this;
239: }
240:
241:
242: /**
243: * Metóda na vytvorenie nového prvku formulára, prvok je v $this->current_item
244: *
245: * @param string typ prvku (text, textarea, password, submit, radio, select, checkbox, file, hidden
246: * @param string názov prvku
247: * @return object Form pre fluent interface
248: */
249: public function add_item($type, $name)
250: {
251: if (empty($this->current_item['label']) === FALSE) {
252: $label = $this->current_item['label'];
253:
254: } else {
255: $label = ucfirst(strtolower($name));
256: }
257:
258: if (empty($this->current_item['fieldset']) === FALSE) {
259: $fieldset = $this->current_item['fieldset'];
260:
261: } else {
262: $fieldset = '!';
263: }
264:
265: $this->save_prev_item();
266:
267: $this->current_item = array(
268: 'type' => $type,
269: 'name' => $name,
270: 'fieldset' => $fieldset,
271: 'value' => '',
272: 'label' => $label,
273: 'rules' => array(),
274: 'id' => NULL,
275: 'css' => array(),
276: 'attributes' => array(),
277: );
278:
279: if ($type === 'html') {
280: $this->current_item['name'] = md5($name);
281: $this->current_item['value'] = $name;
282: }
283:
284: return $this;
285: }
286:
287:
288: public function attribute($attribute, $value)
289: {
290: $this->current_item['attributes'][$attribute] = $value;
291: return $this;
292: }
293:
294:
295: /**
296: * Metóda na vytvorenie nového tlačidla formulára
297: *
298: * @param array vlastnosti tlačidla 'type', 'value', 'name', 'on_click'
299: * @return object Form pre fluent interface
300: */
301: public function add_button($button) {
302: $this->buttons[] = $button;
303: return $this;
304: }
305:
306:
307: /**
308: * Metóda na vytvorenie novej skupiny prvkov, fieldsetu, v prípade že názov začína výkričníkom miesto tagu "fieldset" sa použije "div"
309: *
310: * @param string vlastnosti tlačidla 'type', 'value', 'name'
311: * @return object Form pre fluent interface
312: */
313: public function fieldset($fieldset)
314: {
315: if ($fieldset === FALSE) {
316: $fieldset = '!' . uniqid();
317: }
318:
319: $this->current_item['fieldset'] = $fieldset;
320:
321: return $this;
322: }
323:
324:
325: /**
326: * Metóda na priradenie popisu (label) k prvku
327: *
328: * @param string text popisu, ak začína výkričníkom nebude sa vykresľovať
329: * @return object Form pre fluent interface
330: */
331: public function label($label)
332: {
333: if ($label === FALSE) {
334: $label = '!' . uniqid();
335: }
336:
337: $this->current_item['label'] = $label;
338:
339: return $this;
340: }
341:
342:
343: /**
344: * Metóda na vykreslenie formulára
345: *
346: * @return object Html s formulárom
347: */
348: public function render()
349: {
350: $this->save_prev_item();
351:
352: $anchor = '';
353: if ($this->anchor !== NULL) {
354: $anchor = '#' . $this->anchor;
355: }
356:
357: $form = Html::element('form')
358: ->action($this->action . $anchor)
359: ->method($this->method)
360: ->class($this->css_class)
361: ->id($this->css_id);
362:
363: $hidden_items = $form->create('p')
364: ->class('hiddens');
365:
366: $items_html = array();
367:
368: $this->validate();
369:
370: foreach ($this->items as $key => $item) {
371: $item['key'] = $key;
372:
373: $html = Html::element('span');
374:
375: $html->class[] = 'item';
376:
377: if (empty($item['rules']) === FALSE) {
378: foreach ($item['rules'] as $rule) {
379: $html->class[] = $rule[0];
380: }
381: }
382:
383: if (isset($item['error']) === TRUE) {
384: $html->create('strong')
385: ->class('error')
386: ->set_text($item['error']);
387: }
388:
389: if (isset($item['note']) === TRUE) {
390: $html->create('em')
391: ->class('note')
392: ->set_text($item['note']);
393: }
394:
395: $item_html = $this->render_item($item);
396:
397: if ($item['type'] === 'html') {
398: $item_html = NULL;
399: $html = $item['value'];
400:
401: } else {
402: $this->render_item($item);
403: }
404:
405: if ($item['type'] === 'hidden') {
406: $hidden_items->add($item_html);
407: continue;
408: }
409:
410: $html->insert(0, $item_html);
411:
412: $items_html[$item['fieldset']][$item['label']][$item['name']]['data'] = $item;
413: $items_html[$item['fieldset']][$item['label']][$item['name']]['html'] = $html;
414: }
415:
416: $form->enctype($this->enctype);
417:
418: $fieldsets_counter = 0;
419: $rows_counter = 0;
420:
421: foreach ($items_html as $legend_text => $fieldset) {
422: if ($legend_text[0] === '!') {
423: $fieldset_html = $form->create('div');
424:
425: if ($legend_text <> '!') {
426: $fieldset_html->create('h2')
427: ->set_text(substr($legend_text, 1));
428: }
429:
430: } else {
431: $fieldset_html = $form->create('fieldset');
432:
433: $fieldset_html->create('legend')
434: ->set_text($legend_text);
435:
436: $fieldset_html->class[] = Strings::webalize($legend_text);
437: }
438:
439: $fieldset_html->class[] = 'fieldset';
440: $fieldset_html->class[] = 'fieldset-' . $fieldsets_counter;
441:
442: foreach ($fieldset as $label_text => $fieldset_items) {
443: $row_html = $fieldset_html->create('p');
444:
445: $first_item = reset($fieldset_items);
446: if (empty($first_item['data']['id']) === FALSE) {
447: $id = $first_item['data']['id'];
448:
449: } else {
450: $id = $this->css_id . '-row-' . $rows_counter;
451: }
452:
453: $row_html->class[] = 'row-' . $rows_counter;
454:
455: if (empty($label_text) === FALSE
456: AND $label_text[0] !== '!') {
457:
458: $row_html->create('label')
459: ->set_text($label_text)
460: ->for($id);
461: }
462:
463: $subitems_count = 0;
464: foreach ($fieldset_items as $fieldset_item) {
465: $o = $fieldset_item['html']->get_children(0);
466: if (is_object($o) === TRUE) {
467: $o->id($id);
468: }
469:
470: $fieldset_item['html']->class[] = 'item';
471: $fieldset_item['html']->class[] = 'item-' . $subitems_count;
472:
473: $row_html->add($fieldset_item['html']);
474:
475: if ($fieldset_item['data']['type'] !== 'html') {
476: $subitems_count++;
477: }
478:
479: if (isset($fieldset_item['data']['id']) === TRUE) {
480: $row_html->id('row-' . $fieldset_item['data']['id']);
481: }
482:
483: if (isset($fieldset_item['data']['class']) === TRUE) {
484: $row_html->class[] = 'row-' . $fieldset_item['data']['class'];
485: }
486: }
487:
488: if ($subitems_count > 1) {
489: $row_html->class[] = 'items';
490: $row_html->class[] = 'items-' . $subitems_count;
491:
492: $fieldset_items[] = array(
493: 'html' => Html::element('span')
494: ->class('cleaner'),
495: );
496: }
497:
498: $rows_counter++;
499: }
500:
501: $fieldsets_counter++;
502: }
503:
504: // Vykreslenie tlačidiel
505: $buttons_html = $form->create('p')
506: ->class('buttons');
507:
508: foreach ($this->buttons as $button) {
509: $type = 'submit';
510:
511: if (isset($button['type']) === TRUE) {
512: $type = $button['type'];
513: }
514:
515: $buttons_html->create('input')
516: ->type($type)
517: ->value($button['value'])
518: ->name($button['name']);
519: }
520:
521: if ($this->is_submitted() === TRUE) {
522: return $this->on_submit($form);
523: }
524:
525: return $form->render();
526: }
527:
528:
529: private function render_item($item, $only_html = TRUE)
530: {
531: switch ($item['type']) {
532: case 'text':
533: $item_html = $this->render_text_input($item);
534: break;
535:
536: case 'textarea':
537: $item_html = $this->render_textarea($item);
538: break;
539:
540: case 'password':
541: $item_html = $this->render_text_input($item);
542: break;
543:
544: case 'submit':
545: $item_html = $this->render_text_input($item);
546: break;
547:
548: case 'radio':
549: $item_html = $this->render_radio($item);
550: break;
551:
552: case 'select':
553: $item_html = $this->render_select($item);
554: break;
555:
556: case 'checkbox':
557: $item_html = $this->render_checkbox($item);
558: break;
559:
560: case 'file':
561: $item_html = $this->render_file($item);
562: break;
563:
564: case 'hidden':
565: $item_html = $this->render_hidden($item);
566: break;
567:
568: case 'html':
569: $item_html = $item['value'];
570: break;
571: }
572:
573: if (isset($item['id']) === TRUE) {
574: $item_html->id($item['id']);
575: }
576:
577: if (isset($item['class']) === TRUE) {
578: $item_html->class[] = $item['class'];
579: }
580:
581: foreach ($item['attributes'] as $attribute => $value) {
582: $item_html->$attribute = $value;
583: }
584:
585: if ($only_html === TRUE) {
586: return $item_html;
587: }
588:
589: $out = array();
590:
591: $out['html'] = $item_html;
592:
593: $out['note'] = NULL;
594: if (isset($item['note']) === TRUE) {
595: $out['note'] = $item['note'];
596: }
597:
598: $out['error'] = NULL;
599: if (isset($item['error']) === TRUE) {
600: $out['error'] = $item['error'];
601: }
602:
603: $out['label'] = $item['label'];
604: if ($item['label'][0] === '!') {
605: $out['label'] = substr($item['label'], 1);
606: }
607:
608: $out['name'] = $item['name'];
609:
610: $out['fieldset'] = $item['fieldset'];
611: if ($item['fieldset'][0] === '!') {
612: $out['fieldset'] = substr($item['fieldset'], 1);
613: }
614:
615: return $out;
616: }
617:
618:
619: /**
620: * Metóda na spustenie akcie "on_submit"
621: *
622: * @param object inštancia triedy Html s formulárom
623: * @return string vykreslený objekt Html
624: */
625: private function on_submit($form) {
626: foreach ($this->buttons as $button) {
627: if ($this->is_submitter($button['name']) === FALSE
628: OR empty($button['on_click']) === TRUE) {
629: continue;
630: }
631:
632: $arguments = array($this->get_values(), $form);
633: if (count($button['on_click']) === 4) {
634: $args = (array) array_pop($button['on_click']);
635: $arguments = array_merge($arguments, $args);
636: }
637:
638: $on_valid_form = TRUE;
639: if (count($button['on_click']) === 3) {
640: $on_valid_form = array_pop($button['on_click']);
641: }
642:
643: if (($this->is_valid === TRUE
644: AND $on_valid_form === TRUE)
645: OR $on_valid_form === FALSE) {
646:
647: $form = call_user_func_array($button['on_click'], $arguments);
648: }
649: }
650:
651: return $form->render();
652: }
653:
654:
655: /**
656: * Metóda na uloženie aktuálneho prvku do poľa s prvkami formulára
657: * a vytvorenie nového prázdneho aktuálneho prvku
658: *
659: * @return void
660: */
661: private function save_prev_item()
662: {
663: if (empty($this->current_item) === FALSE) {
664: if (isset($this->current_item['fieldset']) === FALSE) {
665: $this->current_item['fieldset'] = '_';
666: }
667:
668: $this->items[$this->current_item['name']] = $this->current_item;
669: $this->current_item = array();
670: }
671: }
672:
673:
674: /**
675: * Metóda na pridanie validačného pravidla
676: *
677: * @param string názov pravidla, použije sa na výber funkcie z tabuľky
678: * @param string text chybového hlásenia
679: * @param mixed ďalšie parametre pre validačnú funkciu
680: * @return object Form pre fluent interface
681: */
682: public function add_rule() {
683: $arguments = func_get_args();
684:
685: if (empty($arguments) === TRUE) {
686: return FALSE;
687: }
688:
689: $rule = array_shift($arguments);
690:
691: $message = NULL;
692: if (empty($arguments) === FALSE) {
693: $message = array_shift($arguments);
694: }
695:
696: $this->current_item['rules'][] = array($rule, $message, $arguments);
697:
698: return $this;
699: }
700:
701:
702: /**
703: * Metóda na získanie aktuálnych hodnôt prvkov formulára
704: *
705: * @return array hodnoty odoslané formulárom
706: */
707: function get_values() {
708: $values = array();
709:
710: foreach ($this->items as $item) {
711: if ($item['type'] === 'html') {
712: continue;
713: }
714:
715: $keys = preg_split('/(\[)|(\]\[)|(\])/', $item['name'], -1, PREG_SPLIT_NO_EMPTY);
716:
717: if (count($keys) === 1) {
718: $values[$item['name']] = $item['value'];
719:
720: } else {
721: $v = &$values;
722: foreach ($keys as $key) {
723: $v= &$v[$key];
724: }
725:
726: $v = $item['value'];
727: }
728: }
729:
730: unset($values['token']);
731:
732: return $values;
733: }
734:
735:
736: /**
737: * Metóda na vykreslenie prvku input text
738: *
739: * @param array vlastnosti prvku
740: * @return object inštancia triedy Html s prvkom
741: */
742: public function render_text_input($item)
743: {
744: $html = Html::element('input')
745: ->type($item['type'])
746: ->name($item['name'])
747: ->value($item['value']);
748:
749: $size = $this->cols;
750: if (isset($item['size']) === TRUE) {
751: $size = $item['size'];
752: }
753: $html->size($size);
754:
755: $length = NULL;
756:
757: if (isset($item['rules']['eq_len']) === TRUE) {
758: $length = (int) $item['rules']['eq_len'];
759: }
760:
761: if (isset($item['rules']['max_len']) === TRUE) {
762: $length = (int) $item['rules']['max_len'];
763: }
764:
765: $html->maxlength($length);
766:
767: return $html;
768: }
769:
770:
771: /**
772: * Metóda na vykreslenie prvku input hidden
773: *
774: * @param array vlastnosti prvku
775: * @return object inštancia triedy Html s prvkom
776: */
777: public function render_hidden($item)
778: {
779: $html = Html::element('input')
780: ->type($item['type'])
781: ->name($item['name'])
782: ->value($item['value']);
783:
784: return $html;
785: }
786:
787:
788: /**
789: * Metóda na vykreslenie prvku textarea
790: *
791: * @param array vlastnosti prvku
792: * @return object inštancia triedy Html s prvkom
793: */
794: public function render_textarea($item)
795: {
796: $html = Html::element('textarea')
797: ->name($item['name'])
798: ->set_text($item['value']);
799:
800: $cols = $this->cols;
801: if (isset($item['cols']) == TRUE) {
802: $cols = $item['cols'];
803: }
804: $html->cols($cols);
805:
806: $rows = $this->rows;
807: if (isset($item['rows']) == TRUE) {
808: $rows = $item['rows'];
809: }
810: $html->rows($rows);
811:
812: return $html;
813: }
814:
815:
816: /**
817: * Metóda na vykreslenie prvku select
818: *
819: * @param array vlastnosti prvku
820: * @return object inštancia triedy Html s prvkom
821: */
822: public function render_select($item)
823: {
824: $html = Html::element('select')
825: ->name($item['name']);
826:
827: if (isset($item['disabled']) === TRUE) {
828: $html->disabled($item['disabled']);
829: }
830:
831: if (isset($item['multiple']) === TRUE) {
832: $html->multiple($item['multiple']);
833: }
834:
835: if (isset($item['size']) === TRUE) {
836: $html->size($item['size']);
837: }
838:
839: foreach ($item['values'] as $key => $option) {
840: if (is_array($option) === TRUE) {
841: if (empty($option) === TRUE) {
842: continue;
843: }
844:
845: $optgroup_html = $html->create('optgroup')
846: ->label($key);
847:
848: $optgroup = $option;
849: foreach ($optgroup as $key => $option) {
850: $optgroup_html->create('option')
851: ->value($key)
852: ->set_text($option)
853: ->selected($key == $item['value']);
854: }
855:
856: } else {
857: $html->create('option')
858: ->value($key)
859: ->set_text($option)
860: ->selected($key == $item['value']);
861: }
862: }
863:
864: return $html;
865: }
866:
867:
868: /**
869: * Metóda na vykreslenie prvku input checkbox
870: *
871: * @param array vlastnosti prvku
872: * @return object inštancia triedy Html s prvkom
873: */
874: public function render_checkbox($item)
875: {
876: $html = Html::element('input')
877: ->type('checkbox')
878: ->name($item['name']);
879:
880: $html->checked(empty($item['value']) === FALSE);
881:
882: return $html;
883: }
884:
885:
886: /**
887: * Metóda na vykreslenie prvku input file
888: *
889: * @param array vlastnosti prvku
890: * @return object inštancia triedy Html s prvkom
891: */
892: public function render_file($item)
893: {
894: $max_file_size = $this->max_file_size;
895: if (isset($item['rules']['maxsize']) == TRUE) {
896: $max_file_size = Utils::to_bytes($item['rules']['maxsize']);
897: }
898:
899: $html = Html::element();
900:
901: $html->create('input')
902: ->type('hidden')
903: ->name('MAX_FILE_SIZE')
904: ->value($max_file_size);
905:
906: $files = 1;
907: $brackets = '';
908: if (empty($item['files']) === FALSE
909: AND is_numeric($item['files']) === TRUE) {
910:
911: $files = $item['files'];
912: $brackets = '[]';
913: }
914:
915: $browser = Visitor::get_browser_info();
916:
917: if ($browser['name'] === 'msie'
918: AND $browser['version'] < 8) {
919:
920: while ($files > 0) {
921: $html->create('input')
922: ->name($item['name'] . $brackets)
923: ->type('file');
924: $files--;
925: }
926:
927: } else {
928: $input = $html->create('input')
929: ->name($item['name'] . $brackets)
930: ->type('file');
931:
932: if ($files > 1) {
933: $input->multiple(TRUE);
934: }
935: }
936:
937: $this->enctype = 'multipart/form-data';
938:
939: return $html;
940: }
941:
942:
943: /**
944: * Metóda na vykreslenie prvku input radio
945: *
946: * @param array vlastnosti prvku
947: * @return object inštancia triedy Html s prvkom
948: */
949: public function render_radio($item)
950: {
951: $html = Html::element();
952:
953: if (isset($item['id']) === TRUE) {
954: $html->id($item['id']);
955: }
956:
957: $counter = 0;
958: foreach ($item['values'] as $radio_value => $label_text) {
959: $id = $item['name'] . '-' . $counter;
960:
961: $html->create('label')
962: ->set_text($label_text)
963: ->for($id);
964:
965: $radio_html = $html->create('input')
966: ->type('radio')
967: ->name($item['name'])
968: ->value($radio_value);
969:
970: if (isset($item['disabled']) === TRUE) {
971: $radio_html->disabled($item['disabled']);
972: }
973:
974: $radio_html->id($id);
975:
976: if ($item['value'] == $radio_value) {
977: $radio_html->checked('checked');
978: }
979:
980: $counter++;
981: }
982:
983: return $html;
984: }
985:
986:
987: public function open()
988: {
989: $anchor = '';
990: if ($this->anchor !== NULL) {
991: $anchor = '#' . $this->anchor;
992: }
993:
994: $out = '<form action="' . $this->action . $anchor . '" method="' . $this->method . '"';
995:
996: if (empty($this->css_class) === FALSE) {
997: $out .= ' class="' . $this->css_class . '"';
998: }
999:
1000: if (empty($this->css_id) === FALSE) {
1001: $out .= ' id="' . $this->css_id . '"';
1002: }
1003:
1004: $out .= '>';
1005:
1006: echo $out;
1007: }
1008:
1009:
1010: public function close()
1011: {
1012: echo '</form>';
1013: }
1014:
1015:
1016: /**
1017: * Metóda na zistenie či aktuána požiadavka (request) bol odoslnie aktuálneho formulára
1018: *
1019: * @return bool
1020: */
1021: public function is_submitted()
1022: {
1023: if ($this->app->request->method !== $this->method) {
1024: return FALSE;
1025: }
1026:
1027: if ($this->app->request->get_current_method_data('token') !== $this->token) {
1028: return FALSE;
1029: }
1030:
1031: return TRUE;
1032: }
1033:
1034:
1035: /**
1036: * Metóda na zistenie tlačidla ktorým bol formlár odoslaný
1037: *
1038: * @return string|FALSE meno odosielacieho tlačidla, alebo FALSE, ak formulár nebol odoslaný, alebo sa nepodarilo určiť ktoré tlačidlo to bolo
1039: */
1040: public function submitted_by()
1041: {
1042: if ($this->is_submitted() === FALSE) {
1043: return FALSE;
1044: }
1045:
1046: foreach ($this->buttons as $button) {
1047: if ($this->app->request->get_current_method_data($button['name']) !== NULL) {
1048: return $button['name'];
1049: }
1050: }
1051:
1052: return FALSE;
1053: }
1054:
1055:
1056: /**
1057: * Metóda na overenie či tlačidlo bolo odosielacie
1058: *
1059: * @param string meno tlačidla
1060: * @return string
1061: */
1062: public function is_submitter($name) {
1063: if ($this->is_submitted() === FALSE) {
1064: return FALSE;
1065: }
1066:
1067: if ($this->app->request->get_current_method_data($name) !== NULL) {
1068: return TRUE;
1069: }
1070:
1071: return FALSE;
1072: }
1073:
1074:
1075: /**
1076: * Metóda na získanie aktuálnej hodnoty položky, buď odoslanú, alebo predvolenú ak formulár ešte nebol odoslaný
1077: *
1078: * @param string meno položky
1079: * @return mixed
1080: */
1081: private function get_item_value($item)
1082: {
1083: $value = NULL;
1084:
1085: if ($item['type'] === 'file') {
1086: $value = Arrays::get_value($this->app->request->files, $item['name']);
1087:
1088: } else {
1089: if ($this->is_submitted() === TRUE) {
1090: $keys = preg_split('/(\[)|(\]\[)|(\])/', $item['name'], -1, PREG_SPLIT_NO_EMPTY);
1091: if (count($keys) === 1) {
1092: $value = $this->app->request->get_current_method_data($item['name']);
1093:
1094: } else {
1095: $value = $this->app->request->get_current_method_data();
1096: $value = Arrays::get_value($value, $keys);
1097: }
1098:
1099: if ($item['type'] === 'checkbox') {
1100: $value = ($value === 'on');
1101: }
1102: }
1103: }
1104:
1105: if ($value === NULL) {
1106: $value = $item['value'];
1107: }
1108:
1109: return $value;
1110: }
1111:
1112:
1113: /**
1114: * Metóda na overenie odoslaných hodnôt formulára
1115: *
1116: * @return bool
1117: */
1118: public function validate()
1119: {
1120: if ($this->is_submitted() === FALSE) {
1121: $this->is_valid = FALSE;
1122: return FALSE;
1123: }
1124:
1125: $valid = TRUE;
1126:
1127: foreach ($this->items as $key => &$item) {
1128: $item['value'] = $this->get_item_value($item);
1129:
1130: if (empty($item['rules']) === TRUE) {
1131: continue;
1132: }
1133:
1134: $valid_item = TRUE;
1135:
1136: $required = FALSE;
1137:
1138: foreach ($item['rules'] as $rule) {
1139: $rule_name = $rule[0];
1140: $message = $rule[1];
1141: $arguments = array_merge(array($item['value']), $rule[2]);
1142:
1143: if ($rule_name === 'required') {
1144: $required = TRUE;
1145: }
1146:
1147: $function = $this->rules[$rule_name];
1148:
1149: if (empty($message) === TRUE) {
1150: $message = $this->error_messages[$rule_name];
1151: }
1152:
1153: if (empty($message) === TRUE) {
1154: $message = 'ERROR';
1155: }
1156:
1157: if (call_user_func_array($function, $arguments) === FALSE) {
1158: $valid_item = FALSE;
1159: $item['error'] = $message;
1160: break;
1161: }
1162: }
1163:
1164: if (Validate::is_empty($item['value']) === TRUE
1165: AND $required === FALSE
1166: AND $rule_name !== 'callback') {
1167:
1168: $item['error'] = NULL;
1169: $valid_item = TRUE;
1170: }
1171:
1172: if ($valid_item === FALSE) {
1173: $valid = FALSE;
1174: }
1175: }
1176:
1177: $this->is_valid = $valid;
1178:
1179: return $valid;
1180: }
1181:
1182:
1183: /**
1184: * Metóda na overenie hodnoty položky pomocou vlastnej funkcie
1185: *
1186: * @param array metóda na overenie
1187: * @param mixed hodnota na overenie
1188: * @param mixed doplnkové argumenty pre overovaciu funkciu
1189: * @return string|FALSE hodnota alebo FALSE ak overovanie neprejde
1190: */
1191: public function validate_callback() {
1192: $arguments = func_get_args();
1193: $func = array_splice($arguments, 1, 1);
1194:
1195: return call_user_func_array($func[0], $arguments);
1196: }
1197:
1198:
1199: /**
1200: * Metóda na overenie či hodnota je totožná s hodnotou inej položky
1201: *
1202: * @param string hodnota
1203: * @param string meno položky s ktorej hodnotou sa má hodnota aktuálnej položky porovnať
1204: * @return bool
1205: */
1206: public function validate_equal_to($value, $item) {
1207: return ($value === $this->app->request->get_current_method_data($item));
1208: }
1209:
1210:
1211: /**
1212: * Metóda na overenie či hodnota je totožná s hodnotou inej položky
1213: *
1214: * @param string hodnota
1215: * @param string meno položky s ktorej hodnotou sa má hodnota aktuálnej položky porovnať
1216: * @return bool
1217: */
1218: public function validate_required($value) {
1219: return (Validate::is_empty($value) === FALSE);
1220: }
1221:
1222:
1223: /**
1224: * Metóda na overenie či hodnota je súbor v požadovanom formáte
1225: *
1226: * @param object SuperArray
1227: * @param array|string pole prípon, alebo prípona
1228: * @return bool
1229: */
1230: public function validate_file_type($value, $filetypes) {
1231: if (isset($value[0]) === FALSE) {
1232: return TRUE;
1233: }
1234:
1235: $filetypes = (array) $filetypes;
1236: return (in_array($value[0]['extension'], $filetypes));
1237: }
1238:
1239:
1240: /**
1241: * Nastavenie #id a kotvy
1242: *
1243: * @param string názov #id
1244: * @param bool povolenie nastavenia kotvy
1245: * @return object Form pre fluent interface
1246: */
1247: public function css_id($css_id, $set_anchor = FALSE)
1248: {
1249: $this->css_id = $css_id;
1250:
1251: if ($set_anchor === TRUE) {
1252: $this->anchor = $css_id;
1253: }
1254: return $this;
1255: }
1256:
1257:
1258: /**
1259: * Nastavenie css triedy
1260: *
1261: * @param string názov triedy
1262: * @return object Form pre fluent interface
1263: */
1264: public function css_class($css_class)
1265: {
1266: $this->css_class = $css_class;
1267: return $this;
1268: }
1269:
1270:
1271: /**
1272: * Nastavenie kotvy ktorá sa má pridať k adrese cieľa formulára
1273: *
1274: * @param string názov kotvy
1275: * @return object Form pre fluent interface
1276: */
1277: public function anchor($anchor)
1278: {
1279: $this->anchor = $anchor;
1280: return $this;
1281: }
1282:
1283:
1284: /**
1285: * Rewinds the iterator to the first element.
1286: * @return void
1287: */
1288: public function rewind()
1289: {
1290: return reset($this->items);
1291: }
1292:
1293:
1294: /**
1295: * Returns the key of the current element.
1296: * @return mixed
1297: */
1298: public function key()
1299: {
1300: return key($this->items);
1301: }
1302:
1303:
1304: /**
1305: * Returns the current element.
1306: * @return mixed
1307: */
1308: public function current()
1309: {
1310: $item = current($this->items);
1311:
1312: return $this->render_item($item, FALSE);
1313: }
1314:
1315:
1316:
1317: /**
1318: * Moves forward to next element.
1319: * @return void
1320: */
1321: public function next()
1322: {
1323: $item = next($this->items);
1324:
1325: if ($item === FALSE) {
1326: return FALSE;
1327: }
1328:
1329: return $this->render_item($item, FALSE);
1330: }
1331:
1332:
1333:
1334: /**
1335: * Checks if there is a current element after calls to rewind() or next().
1336: * @return bool
1337: */
1338: public function valid()
1339: {
1340: return key($this->items) !== null;
1341: }
1342:
1343:
1344:
1345: /**
1346: * Required by the Countable interface.
1347: * @return int
1348: */
1349: public function count()
1350: {
1351: return count($this->items);
1352: }
1353:
1354:
1355: public function offsetSet($pointer, $value)
1356: {
1357: }
1358:
1359:
1360: public function offsetExists($pointer)
1361: {
1362: return isset($this->items[$pointer]);
1363: }
1364:
1365:
1366: public function offsetUnset($pointer)
1367: {
1368: }
1369:
1370:
1371: public function offsetGet($pointer)
1372: {
1373: $item = $this->items[$pointer];
1374:
1375: return $this->render_item($item, FALSE);
1376: }
1377: }
1378: