1: <?php
2: namespace Module\FormBuilder;
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: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131:
132: class Form {
133: 134: 135: 136:
137: public $id;
138:
139: 140: 141: 142:
143: public $class;
144:
145: 146: 147: 148:
149: public $action;
150:
151: 152: 153: 154:
155: public $method;
156:
157: 158: 159: 160:
161: public $validate = true;
162:
163: 164: 165: 166:
167: private $fieldsets;
168:
169: 170: 171: 172:
173: public function __construct($json) {
174: $data = \json_decode(str_replace('\\', '\\\\', $json));
175:
176: if (!is_object($data)) {
177: var_dump($json);
178: throw new \Exception('There is an error in your JSON. Cannot continue.');
179: }
180:
181: if (!isset($data->action)) {
182: $data->action = "#";
183: }
184:
185: if (!isset($data->method)) {
186: $data->method = "POST";
187: }
188:
189: $this->action = $data->action;
190: $this->method = $data->method;
191:
192: if (isset($data->id)) {
193: $this->id = $data->id;
194: }
195:
196: if (isset($data->class)) {
197: $this->class = $data->class;
198: }
199:
200: if (isset($data->validate)) {
201: $this->validate = $data->validate;
202: }
203:
204: foreach ($data->fieldsets as $fieldset) {
205: $this->fieldsets[] = new FormBuilderFieldset($fieldset);
206: }
207: }
208:
209: 210: 211: 212:
213: public function submitted() {
214: if ($_SERVER['REQUEST_METHOD'] == $this->method) {
215: if (strtoupper($this->method) === "POST") {
216: $id = $_POST['frmID'];
217: } else {
218: $id = $_GET['frmID'];
219: }
220:
221: if ($id == $this->id) {
222: return true;
223: }
224: }
225:
226: return false;
227: }
228:
229: 230: 231: 232:
233: public function validate() {
234: $errors = array();
235:
236: foreach($this->fieldsets as $fieldset) {
237: $error = $fieldset->validate();
238: if (is_array($error)) {
239: $errors = array_merge($errors, $error);
240: }
241: }
242:
243: return (count($errors) == 0) ? true : $errors;
244: }
245:
246: 247: 248: 249:
250: public function render() {
251: $validate = (!$this->validate) ? "novalidate" : "";
252: $buffer = array();
253: $buffer[] = "<form id=\"{$this->id}\" class=\"{$this->class}\" action=\"{$this->action}\" method=\"{$this->method}\" {$validate}>";
254: $buffer[] = "<input type=\"hidden\" name=\"frmID\" id=\"frmID\" value=\"{$this->id}\">";
255:
256: foreach($this->fieldsets as $fieldset) {
257: $buffer[] = $fieldset->render($this->validate && $this->submitted());
258: }
259:
260: $buffer[] = "</form>";
261:
262: return implode(" ", $buffer);
263: }
264:
265: 266: 267: 268:
269: public function getDataMap() {
270: $formData = array();
271:
272: foreach ($this->fieldsets as $fieldset) {
273: if (is_array($fieldset->getDataMap())) {
274: $formData = array_merge($formData, $fieldset->getDataMap());
275: }
276: }
277:
278: return $formData;
279: }
280: }
281:
282: 283: 284: 285:
286: class FormBuilderField {
287:
288:
289: 290: 291: 292:
293: public $name;
294:
295: 296: 297: 298:
299: public $label;
300:
301: 302: 303: 304:
305: public $type;
306:
307:
308:
309: 310: 311: 312:
313: public $rules;
314:
315: 316: 317: 318:
319: public $values = array();
320:
321: 322: 323: 324:
325: public $placeholder;
326:
327: 328: 329: 330:
331: public $track;
332:
333: 334: 335: 336:
337: public $autofocus;
338:
339: 340: 341: 342:
343: public $dataMap;
344:
345: 346: 347: 348:
349: public $class;
350:
351: 352: 353: 354:
355: public $disabled = false;
356:
357: 358: 359: 360:
361: public function __construct($object) {
362: if (!isset($object->type)) {
363: $object->type = "text";
364: }
365:
366: if (!isset($object->name)) {
367: throw new \Exception('FormBuilderField: Name is manditory.');
368: }
369:
370: $this->name = $object->name;
371: $this->track = @$object->track;
372: $this->label = @$object->label;
373: $this->type = $object->type;
374:
375: if (isset($object->label)) {
376: $this->label = $object->label;
377: }
378:
379: if (isset($object->dataMap)) {
380: $this->dataMap = $object->dataMap;
381: }
382:
383: if (isset($object->class)) {
384: $this->class = $object->class;
385: }
386:
387: if (isset($object->disabled)) {
388: $this->disabled = $object->disabled;
389: }
390:
391: if (isset($object->placeholder)) {
392: $this->placeholder = $object->placeholder;
393: }
394:
395: if (isset($object->autofocus)) {
396: $this->autofocus = $object->autofocus;
397: }
398:
399: if (isset($object->rules)) {
400: $this->rules = $object->rules;
401: }
402:
403: if (isset($object->errors)) {
404: $this->errors = $object->errors;
405: }
406:
407:
408: if (isset($object->values)) {
409: $this->values = $object->values;
410: } elseif (isset($object->value)) {
411: $this->values[] = $object->value;
412: }
413: }
414:
415: 416: 417: 418: 419: 420: 421:
422: private function validateDate($date, $format = 'Y-m-d H:i:s') {
423: $d = \DateTime::createFromFormat($format, $date);
424: return $d && $d->format($format) == $date;
425: }
426:
427: 428: 429: 430:
431: public function render($validate) {
432:
433: $errors = ($validate) ? $this->validate() : "";
434:
435: $disabled = ($this->disabled) ? "disabled " : "";
436: $track = (@isset($this->track)) ? "data-track=\"{$this->track}\" " : "";
437: $autofocus = ($this->autofocus) ? "autofocus " : "";
438: $placeholder = ($this->placeholder) ? "placeholder='{$this->placeholder}' " : "";
439:
440:
441: $required = (@$this->rules->required) ? "required " : "";
442: $equalTo = (@isset($this->rules->equalTo)) ? "equalTo='#{$this->rules->equalTo}' " : "";
443: $minLength = (@isset($this->rules->minLength)) ? "minlength='{$this->rules->minLength}'' " : "";
444: $maxLength = (@isset($this->rules->maxLength)) ? "maxlength='{$this->rules->maxLength}'' " : "";
445: $digits = (@$this->rules->digits) ? "digits " : "";
446: $email = (@$this->rules->email) ? "email " : "";
447: $date = (@$this->rules->date) ? "date " : "";
448:
449:
450: $rules = "{$track}{$required}{$minLength}{$maxLength}{$equalTo}{$disabled}{$autofocus}{$placeholder}{$digits}{$email}{$date}";
451:
452: if (is_array($errors)) {
453: $this->class = $this->class . " error";
454: }
455:
456: if (count($this->values) == 0) {
457: $this->values[0]= "";
458: }
459:
460: $buffer = array();
461:
462: switch ($this->type) {
463: case 'copy':
464: if (isset($this->label)) {
465: $buffer[] = "<label for=\"{$this->name}\">{$this->label}</label>";
466: }
467:
468: $buffer[] = $this->values[0];
469: break;
470: case 'textbox':
471: if (isset($this->label)) {
472: $buffer[] = "<label for=\"{$this->name}\">{$this->label}</label>";
473: }
474:
475: $buffer[] = "<textbox {$rules} id=\"{$this->name}\" name=\"{$this->name}\" class=\"{$this->class}\">";
476: $buffer[] = "{$this->values[0]}";
477: $buffer[] = "</textbox>";
478: break;
479: case 'select':
480: if (isset($this->label)) {
481: $buffer[] = "<label for=\"{$this->name}\">{$this->label}</label>";
482: }
483:
484: $buffer[] = "<select {$rules} id=\"{$this->name}\" name=\"{$this->name}\" class=\"{$this->class}\">";
485:
486: foreach($this->values as $option) {
487: $disabledField = "";
488: $selected = "";
489:
490: if (isset($option->disabled)) {
491: $disabledField = ($option->disabled) ? "disabled" : "";
492: }
493:
494: if (isset($option->selected)) {
495: $selected = ($option->selected) ? "selected" : "";
496: }
497:
498: $buffer[] = "<option {$disabledField} {$selected} value=\"{$option->value}\">{$option->name}</option>";
499: }
500:
501: $buffer[] = "</select>";
502: break;
503: case 'radio':
504: if (isset($this->label)) {
505: $buffer[] = "<label for=\"{$this->name}\">{$this->label}</label>";
506: }
507:
508: $buffer[] = "<ul class=\"radios {$this->class}\">";
509:
510: foreach($this->values as $option) {
511: $track = (@isset($option->track)) ? "data-track=\"{$option->track}\" " : "";
512: $disabledField = "";
513: $selected = "";
514:
515: if (isset($option->disabled)) {
516: $disabledField = ($option->disabled) ? "disabled " : "";
517: }
518:
519: if (isset($option->selected)) {
520: $selected = ($option->selected) ? "checked " : "";
521: }
522:
523: $buffer[] = "<li>";
524: $buffer[] = "<input {$track} {$rules} {$selected} type=\"radio\" id=\"{$option->id}\" name=\"{$this->name}\" class=\"{$this->class}\" value=\"{$option->value}\">";
525:
526: if (isset($option->label)) {
527: $buffer[] = "<label for='{$option->id}'>{$option->label}</label>";
528: }
529:
530: $buffer[] = "</li>";
531: }
532: $buffer[] = "</ul>";
533:
534: break;
535: case 'checkbox':
536: $selected = "";
537:
538: if (isset($this->selected)) {
539: $selected = ($this->selected) ? "checked " : "";
540: }
541:
542: $buffer[] = "<input {$rules} {$selected} type=\"{$this->type}\" id=\"{$this->name}\" name=\"{$this->name}\" class=\"{$this->class}\" value=\"{$this->values[0]}\">";
543:
544: if (isset($this->label)) {
545: $buffer[] = "<label for=\"{$this->name}\">{$this->label}</label>";
546: }
547: break;
548: default:
549: if (isset($this->label)) {
550: $buffer[] = "<label for=\"{$this->name}\">{$this->label}</label>";
551: }
552: $buffer[] = "<input {$rules} type=\"{$this->type}\" id=\"{$this->name}\" name=\"{$this->name}\" class=\"{$this->class}\" value=\"{$this->values[0]}\">";
553: }
554:
555: if (is_array($errors)) {
556: foreach($errors as $error) {
557: $buffer[] = "<label class=\"error\" for=\"{$this->name}\">{$error}</label>";
558: }
559: }
560:
561: return implode(" ", $buffer);
562: }
563:
564: 565: 566: 567:
568: public function validate() {
569: $errors = array();
570:
571:
572: switch ($this->type) {
573: case 'submit':
574: break;
575: case 'select':
576: case 'radio':
577: if (!empty($_POST[$this->name])) {
578: foreach($this->values as $key => $object) {
579: $this->values[$key]->selected = ($_POST[$this->name] == $object->value) ? true : false;
580: }
581: }
582: break;
583: case 'checkbox':
584: if (!empty($_POST[$this->name])) {
585: $this->selected = ($_POST[$this->name] == $this->values[0]) ? true : false;
586: }
587: break;
588: default:
589: if (!empty($_POST[$this->name])) {
590: $this->values[0] = $_POST[$this->name];
591: } else {
592: unset($this->values[0]);
593: }
594: }
595:
596: if (is_object($this->rules)) {
597: foreach ($this->rules as $rule => $value) {
598: switch($rule) {
599: case 'required':
600: if ($value != false) {
601: if (count($this->values) == 0) {
602: if (isset($this->errors->$rule)) {
603: $errors[] = $this->errors->$rule;
604: } else {
605: $errors[] = "'{$this->label}' is a required field.";
606: }
607: }
608: }
609: break;
610: case 'lengthMax':
611: if ($value != false) {
612: if (isset($this->values[0])) {
613: if (strlen($this->values[0]) >= $value) {
614: if (isset($this->errors->$rule)) {
615: $errors[] = $this->errors->$rule;
616: } else {
617: $errors[] = "'{$this->label}' should be a maximum of {$value} characters.";
618: }
619: }
620: }
621: }
622: break;
623: case 'lengthMin':
624: if ($value != false) {
625: if (strlen($this->values[0]) <= $value) {
626: if (isset($this->errors->$rule)) {
627: $errors[] = $this->errors->$rule;
628: } else {
629: $errors[] = "'{$this->label}' should be a minimum of {$value} characters.";
630: }
631: }
632: }
633: break;
634: case 'digits':
635: if ($value != false) {
636: if (!filter_var($this->values[0], FILTER_VALIDATE_FLOAT)) {
637: if (isset($this->errors->$rule)) {
638: $errors[] = $this->errors->$rule;
639: } else {
640: $errors[] = "'{$this->label}' is not a valid number.";
641: }
642: }
643: }
644: break;
645: case 'email':
646: if ($value != false) {
647: if (count($this->values) == 0) {
648: $this->values[0] = NULL;
649: } else {
650: if (!filter_var($this->values[0], FILTER_VALIDATE_EMAIL)) {
651: if (isset($this->errors->$rule)) {
652: $errors[] = $this->errors->$rule;
653: } else {
654: $errors[] = "'{$this->label}' is not a valid email address.";
655: }
656: }
657: }
658: }
659: break;
660: case 'date':
661: if (count($this->values) == 0) {
662: $this->values[0] = NULL;
663: }
664:
665: if (!$this->validateDate($this->values[0], 'm/d/Y')) {
666: if (isset($this->errors->$rule)) {
667: $errors[] = $this->errors->$rule;
668: } else {
669: $errors[] = "'{$this->label}' is not a valid date (mm/dd/yyyy).";
670: }
671: }
672: break;
673: case 'equal':
674: case 'equalTo':
675: if ($value != false) {
676: if (count($this->values) == 0) {
677: $this->values[0] = NULL;
678: }
679:
680: if ($this->values[0] != $_POST[$value]) {
681: if (isset($this->errors->$rule)) {
682: $errors[] = $this->errors->$rule;
683: } else {
684: $errors[] = "'{$this->label}' does not match '{$value}'.";
685: }
686: }
687: }
688: break;
689: }
690: }
691: }
692:
693: return $errors;
694: }
695:
696: 697: 698: 699:
700: public function getDataMap() {
701: if (isset($this->dataMap)) {
702: switch($this->type) {
703: case 'select':
704: foreach ($this->values as $option) {
705: if ($option->selected) {
706: return array(
707: $this->dataMap => $option->value
708: );
709: }
710: }
711: break;
712: default:
713: if (count($this->values) == 0) {
714: $this->values[0] = NULL;
715: }
716:
717: return array(
718: $this->dataMap => $this->values[0]
719: );
720: }
721: }
722: }
723: }
724:
725: 726: 727: 728:
729: class FormBuilderFieldset {
730: 731: 732: 733:
734: public $class;
735:
736: 737: 738: 739:
740: public $legend;
741:
742: 743: 744: 745:
746: private $fields;
747:
748: 749: 750: 751:
752: public function __construct($object) {
753: if (isset($object->class)) {
754: $this->class = $object->class;
755: }
756:
757: if (isset($object->legend)) {
758: $this->legend = $object->legend;
759: }
760:
761:
762: foreach ($object->fields as $field) {
763: $this->fields[] = new FormBuilderField($field);
764: }
765: }
766:
767: 768: 769: 770: 771:
772: public function render($validate) {
773: $buffer = array();
774: $buffer[] = "<fieldset class=\"{$this->class}\">";
775:
776: if (isset($this->legend)) {
777: $buffer[] = "<legend>{$this->legend}</legend>";
778: }
779:
780: $buffer[] = "<ul>";
781:
782: foreach($this->fields as $field) {
783: $buffer[] = "<li>" . $field->render($validate) . "</li>";
784: }
785:
786: $buffer[] = "</ul>";
787: $buffer[] = "</fieldset>";
788:
789: return implode(" ", $buffer);
790: }
791:
792: 793: 794: 795:
796: public function validate() {
797: $errors = array();
798:
799: foreach($this->fields as $field) {
800: $error = $field->validate();
801: if (is_array($error)) {
802: $errors = array_merge($errors, $error);
803: }
804: }
805:
806: return $errors;
807: }
808:
809: 810: 811: 812:
813: public function getDataMap() {
814: $fieldsetData = array();
815:
816: foreach ($this->fields as $field) {
817: if (is_array($field->getDataMap())) {
818: $fieldsetData = array_merge($fieldsetData, $field->getDataMap());
819: }
820: }
821:
822: return $fieldsetData;
823: }
824: }
825:
826: 827: 828:
829: class States {
830: function jsonArray($placeholder="State") {
831: return '[
832: {
833: "name": "' . $placeholder . '",
834: "disabled": true,
835: "selected": true,
836: "value": ""
837: }, {
838: "name" : "AL",
839: "value": "Alabama"
840: }, {
841: "name" : "AK",
842: "value": "Alaska"
843: }, {
844: "name" : "AZ",
845: "value": "Arizona"
846: }, {
847: "name" : "AR",
848: "value": "Arkansas"
849: }, {
850: "name" : "CA",
851: "value": "California"
852: }, {
853: "name" : "CO",
854: "value": "Colorado"
855: }, {
856: "name" : "CT",
857: "value": "Connecticut"
858: }, {
859: "name" : "DE",
860: "value": "Delaware"
861: }, {
862: "name" : "DC",
863: "value": "District Of Columbia"
864: }, {
865: "name" : "FL",
866: "value": "Florida"
867: }, {
868: "name" : "GA",
869: "value": "Georgia"
870: }, {
871: "name" : "HI",
872: "value": "Hawaii"
873: }, {
874: "name" : "ID",
875: "value": "Idaho"
876: }, {
877: "name" : "IL",
878: "value": "Illinois"
879: }, {
880: "name" : "IN",
881: "value": "Indiana"
882: }, {
883: "name" : "IA",
884: "value": "Iowa"
885: }, {
886: "name" : "KS",
887: "value": "Kansas"
888: }, {
889: "name" : "KY",
890: "value": "Kentucky"
891: }, {
892: "name" : "LA",
893: "value": "Louisiana"
894: }, {
895: "name" : "ME",
896: "value": "Maine"
897: }, {
898: "name" : "MD",
899: "value": "Maryland"
900: }, {
901: "name" : "MA",
902: "value": "Massachusetts"
903: }, {
904: "name" : "MI",
905: "value": "Michigan"
906: }, {
907: "name" : "MN",
908: "value": "Minnesota"
909: }, {
910: "name" : "MS",
911: "value": "Mississippi"
912: }, {
913: "name" : "MO",
914: "value": "Missouri"
915: }, {
916: "name" : "MT",
917: "value": "Montana"
918: }, {
919: "name" : "NE",
920: "value": "Nebraska"
921: }, {
922: "name" : "NV",
923: "value": "Nevada"
924: }, {
925: "name" : "NH",
926: "value": "New Hampshire"
927: }, {
928: "name" : "NJ",
929: "value": "New Jersey"
930: }, {
931: "name" : "NM",
932: "value": "New Mexico"
933: }, {
934: "name" : "NY",
935: "value": "New York"
936: }, {
937: "name" : "NC",
938: "value": "North Carolina"
939: }, {
940: "name" : "ND",
941: "value": "North Dakota"
942: }, {
943: "name" : "OH",
944: "value": "Ohio"
945: }, {
946: "name" : "OK",
947: "value": "Oklahoma"
948: }, {
949: "name" : "OR",
950: "value": "Oregon"
951: }, {
952: "name" : "PA",
953: "value": "Pennsylvania"
954: }, {
955: "name" : "RI",
956: "value": "Rhode Island"
957: }, {
958: "name" : "SC",
959: "value": "South Carolina"
960: }, {
961: "name" : "SD",
962: "value": "South Dakota"
963: }, {
964: "name" : "TN",
965: "value": "Tennessee"
966: }, {
967: "name" : "TX",
968: "value": "Texas"
969: }, {
970: "name" : "UT",
971: "value": "Utah"
972: }, {
973: "name" : "VT",
974: "value": "Vermont"
975: }, {
976: "name" : "VA",
977: "value": "Virginia"
978: }, {
979: "name" : "WA",
980: "value": "Washington"
981: }, {
982: "name" : "WV",
983: "value": "West Virginia"
984: }, {
985: "name" : "WI",
986: "value": "Wisconsin"
987: }, {
988: "name" : "WY",
989: "value": "Wyomin"
990: }
991: ]';
992: }
993: }