├── .gitignore ├── .htaccess ├── README.md ├── composer.json ├── examples ├── ajax_contact.php ├── ajax_url.php ├── batch.php ├── bulk.php ├── components ├── contact.php ├── databags.php ├── dates.php ├── events.php ├── file_plupload.php ├── footer.php ├── forms.php ├── header.php ├── igorescobar ├── index.php ├── locations.php ├── multistep.php ├── nestables.php ├── object_form.php ├── plupload.php ├── recaptchalib.php ├── repeatable.php └── showall.php └── src ├── classes ├── Form.php ├── FormBuilder.php ├── abstracts │ ├── base │ │ ├── Element.php │ │ ├── Field.php │ │ └── FieldsContainer.php │ ├── containers │ │ ├── FieldsContainerMultiple.php │ │ └── SortableContainer.php │ └── fields │ │ ├── Action.php │ │ ├── Captcha.php │ │ ├── Clickable.php │ │ ├── ComposedField.php │ │ ├── FieldMultivalues.php │ │ └── Optionable.php ├── accessories │ ├── FormValues.php │ ├── NotificationsBag.php │ ├── OrderedFunctions.php │ └── SessionBag.php ├── containers │ ├── Accordion.php │ ├── BulkTable.php │ ├── Fieldset.php │ ├── Nestable.php │ ├── Repeatable.php │ ├── SeamlessContainer.php │ ├── Sortable.php │ ├── SortableTable.php │ ├── TableContainer.php │ ├── Tabs.php │ └── TagContainer.php ├── exceptions │ └── FormException.php ├── fields │ ├── Autocomplete.php │ ├── Button.php │ ├── Checkbox.php │ ├── Checkboxes.php │ ├── Color.php │ ├── Colorpicker.php │ ├── Datalist.php │ ├── Date.php │ ├── Datepicker.php │ ├── Dateselect.php │ ├── Datetime.php │ ├── Datetimeselect.php │ ├── Email.php │ ├── File.php │ ├── Geolocation.php │ ├── Gmaplocation.php │ ├── Hidden.php │ ├── ImageButton.php │ ├── ImageCaptcha.php │ ├── Leafletlocation.php │ ├── Markup.php │ ├── Maskedfield.php │ ├── MathCaptcha.php │ ├── Multiselect.php │ ├── Number.php │ ├── Optgroup.php │ ├── Option.php │ ├── Otp.php │ ├── Password.php │ ├── Plupload.php │ ├── Progressbar.php │ ├── Radios.php │ ├── Range.php │ ├── Recaptcha.php │ ├── Reset.php │ ├── Select.php │ ├── Selectmenu.php │ ├── Slider.php │ ├── Spinner.php │ ├── Submit.php │ ├── Switchbox.php │ ├── Tel.php │ ├── Textarea.php │ ├── Textfield.php │ ├── Time.php │ ├── Timeselect.php │ ├── Tinymce.php │ ├── Url.php │ └── Value.php └── traits │ ├── Containers.php │ ├── Processors.php │ ├── Tools.php │ └── Validators.php ├── fonts └── Lato-Regular.ttf ├── interfaces ├── FieldInterface.php └── FieldsContainerInterface.php ├── php_forms_api_bootstrap.php └── php_forms_api_defines.php /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | composer.lock 3 | docs 4 | vendor 5 | *.sublime-projectcompletions 6 | *.sublime-project 7 | *.sublime-workspace 8 | *.sublime-classdb 9 | examples/googlekeys.php 10 | .php_cs.cache 11 | -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | php_value xdebug.var_display_max_depth 20 2 | php_value xdebug.var_display_max_children 256 3 | php_value xdebug.var_display_max_data 1024 4 | 5 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "degami/php-forms-api", 3 | "description": "A simple to use Forms API for generating, validating and processing forms in PHP", 4 | "type": "library", 5 | "keywords": ["forms", "PHP", "API"], 6 | "homepage": "https://github.com/degami/php-forms-api", 7 | 8 | "license": "MIT", 9 | "authors": [ 10 | { 11 | "name": "degami@github.com", 12 | "homepage": "https://github.com/degami/php-forms-api" 13 | } 14 | ], 15 | "require": { 16 | "php": ">=7.2", 17 | "ext-json": "*", 18 | "ext-gd": "*", 19 | "degami/basics": "dev-master", 20 | "components/jqueryui": "1.12.*", 21 | "igorescobar/jquery-mask-plugin": "*" 22 | }, 23 | "autoload": { 24 | "files": [ 25 | "src/php_forms_api_defines.php", 26 | "src/php_forms_api_bootstrap.php" 27 | ], 28 | "psr-4": { 29 | "Degami\\PHPFormsApi\\": "src/classes", 30 | "Degami\\PHPFormsApi\\Interfaces\\": "src/interfaces", 31 | "Degami\\PHPFormsApi\\Traits\\": "src/classes/traits", 32 | "Degami\\PHPFormsApi\\Abstracts\\Base\\": "src/classes/abstracts/base", 33 | "Degami\\PHPFormsApi\\Abstracts\\Containers\\": "src/classes/abstracts/containers", 34 | "Degami\\PHPFormsApi\\Abstracts\\Fields\\": "src/classes/abstracts/fields", 35 | "Degami\\PHPFormsApi\\Accessories\\": "src/classes/accessories", 36 | "Degami\\PHPFormsApi\\Containers\\": "src/classes/containers", 37 | "Degami\\PHPFormsApi\\Fields\\": "src/classes/fields", 38 | "Degami\\PHPFormsApi\\Exceptions\\": "src/classes/exceptions" 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /examples/ajax_contact.php: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | 15 | Example contact form 16 | 17 | 18 | 19 | 20 |

Example Form

21 |
22 | To list | 23 | Go back 24 |
25 |
26 | render('html');?> 27 | 28 | 29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /examples/ajax_url.php: -------------------------------------------------------------------------------- 1 | process(); 11 | 12 | // Submit function to call when the form is submitted and passes validation. 13 | // This is where you would send the email (using PHP mail function) 14 | // as this is not a real example I'm just outputting the values for now. 15 | function contactform_ajax_submit(&$form) 16 | { 17 | $form_values = $form->getValues(); 18 | return $form_values; 19 | //var_dump($form->get_triggering_element()); 20 | // Reset the form if you want it to display again. 21 | // $form->reset(); 22 | } 23 | 24 | if ($form->isSubmitted()) : 25 | print json_encode(array( 'html' => '

Thanks for submitting the form.

'.print_r($form->getSubmitResults('contactform_ajax_submit'), true).'
', 'js' => '' , 'is_submitted' => true )); 26 | else : 27 | print $form->render(/* 'json' */); 28 | endif; 29 | -------------------------------------------------------------------------------- /examples/batch.php: -------------------------------------------------------------------------------- 1 | render(); 13 | } else { 14 | ?> 15 | 16 | 17 | 18 | Example contact form 19 | 20 | 21 | 22 | 23 |

Batch Operation Form

24 |
25 | To list | 26 | Go back 27 |
28 |
29 | render('html');?> 30 | 31 | 32 |
33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /examples/bulk.php: -------------------------------------------------------------------------------- 1 | getValues()->toArray(); 15 | // $form->add_highlight('Bulk operation done!'); 16 | // $form->reset(); 17 | 18 | return $form_values; 19 | } 20 | 21 | // function my_contactform_form_alter($form){ 22 | // $form->get_field('fieldset')->remove_field('message'); 23 | // } 24 | 25 | $form = FAPI\FormBuilder::getForm('bulkform'); 26 | ?> 27 | 28 | 29 | 30 | Example contact form 31 | 32 | 33 | 38 | 39 | 40 | 41 |

Example Form

42 |
43 | To list | 44 | Go back 45 |
46 |
47 |
process(); ?>
48 | isSubmitted()) : ?> 49 | 50 |

Thanks for submitting the form.

51 |
getSubmitResults());?>
52 | 53 | render(); ?> 54 | 55 | 56 | 57 |
58 | 59 | 60 | -------------------------------------------------------------------------------- /examples/components: -------------------------------------------------------------------------------- 1 | ../vendor/components -------------------------------------------------------------------------------- /examples/contact.php: -------------------------------------------------------------------------------- 1 | 'border: solid 1px #f00;']; 13 | // } 14 | // function my_textfield_field_render_output_alter(&$html){ 15 | // $html = 'aaa'.$html; 16 | // } 17 | // function __($str){ 18 | // return "__ $str __"; 19 | // } 20 | // Submit function to call when the form is submitted and passes validation. 21 | // This is where you would send the email (using PHP mail function) 22 | // as this is not a real example I'm just outputting the values for now. 23 | function my_very_own_contactform_submit(&$form, &$form_state) 24 | { 25 | $form_values = $form->getValues(); 26 | $out = []; 27 | foreach ($form_values->fieldset as $key => $value) { 28 | $out[$key] = $value; 29 | } 30 | return $out; 31 | return implode( 32 | ' - ', 33 | [ 34 | $form_values->fieldset->name, 35 | $form_values->fieldset->email, 36 | $form_values->fieldset->message, 37 | ] 38 | ); 39 | return $form_values; 40 | 41 | $form->addHighlight('Message sent!'); 42 | print_r($form_values); 43 | //var_dump($form->get_triggering_element()); 44 | // Reset the form if you want it to display again. 45 | $form->reset(); 46 | } 47 | 48 | // function my_contactform_form_alter($form){ 49 | // $form->get_field('fieldset')->remove_field('message'); 50 | // } 51 | 52 | // i just want another form_id for my form 53 | $form = FAPI\FormBuilder::getForm('contactform', 'my_very_own_contactform'); 54 | ?> 55 | 56 | 57 | 58 | Example contact form 59 | 60 | 61 | 66 | 67 | 68 | 69 |

Example Form

70 |
71 | To list | 72 | Go back 73 |
74 |
75 |
process(); ?>
76 | isSubmitted()) : ?> 77 | 78 |

Thanks for submitting the form.

79 |
getSubmitResults());?>
80 |
getValues());?>
81 | 82 | render(); ?> 83 | 84 | 85 | 86 |
87 | 88 | 89 | -------------------------------------------------------------------------------- /examples/databags.php: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | Example session bag 14 | 15 | 16 | 17 | 18 |

Example Form

19 |
20 | To list | 21 | Go back 22 |
23 |
24 |
add(
39 | //    $val
40 | //);
41 | if (isset($_GET['add'])) {
42 |     $bag->counter = isset($bag->counter) ? $bag->counter+1 : 0;
43 |     $bag->more = ['datas' => 0, 'load2' => 2, 'load' => ['count' => null] ];
44 |     $bag['more']['datas']=5;
45 |     $bag['more']['load']['count']=22;
46 | }
47 | //var_dump($val);
48 | var_dump($bag->toArray());
49 | ?>
50 | 
51 |
52 | 53 | 54 | -------------------------------------------------------------------------------- /examples/dates.php: -------------------------------------------------------------------------------- 1 | getValues(); 15 | return $form_values->toArray(); 16 | //var_dump($form->get_triggering_element()); 17 | // Reset the form if you want it to display again. 18 | // $form->reset(); 19 | } 20 | 21 | $form = FAPI\FormBuilder::getForm('datesform'); 22 | ?> 23 | 24 | 25 | 26 | Example dates form 27 | 28 | 29 | 30 | 31 |

Dates Form

32 |
33 | To list | 34 | Go back 35 |
36 |
37 |
process(); ?>
38 | isSubmitted()) : ?> 39 | 40 |
getSubmitResults());?>
41 |

Thanks for submitting the form.

42 | 43 | render(); ?> 44 | 45 | 46 | 47 |
48 | 49 | 50 | -------------------------------------------------------------------------------- /examples/events.php: -------------------------------------------------------------------------------- 1 | getValues(); 15 | //var_dump($form->get_triggering_element()); 16 | // Reset the form if you want it to display again. 17 | // $form->reset(); 18 | return $form_values->toArray(); 19 | } 20 | 21 | $form = FAPI\FormBuilder::getForm('eventsform'); 22 | 23 | if (isset($_REQUEST['partial'])) { 24 | print $form->render(); 25 | } else { 26 | ?> 27 | 28 | 29 | 30 | Example contact form 31 | 32 | 33 | 34 | 35 | 36 |

Events Form

37 |
38 | To list | 39 | Go back 40 |
41 |
42 |
process(); ?>
43 | isSubmitted()) : ?> 44 | 45 |
getSubmitResults());?>
46 |

Thanks for submitting the form.

47 | 48 | render(); ?> 49 | 50 | 51 | 52 |
53 | 54 | 55 | allocatedSize); 5 | if (defined('PHP_FORMS_API_DEBUG')) : 6 | $has_session = FAPI\FormBuilder::sessionPresent(); 7 | if ($has_session) : ?> 8 |
9 |
Session Info
10 |
toArray());// print_r($form); ?>
11 |
12 | 13 |
function body
14 |
getDefinitionBody();?>
15 | clear(); 11 | // session_destroy(); 12 | // session_start(); 13 | } 14 | ?> 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 236 | -------------------------------------------------------------------------------- /examples/igorescobar: -------------------------------------------------------------------------------- 1 | ../vendor/igorescobar -------------------------------------------------------------------------------- /examples/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 55 | 56 | 57 |

php-forms-api

58 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /examples/locations.php: -------------------------------------------------------------------------------- 1 | '); 6 | } 7 | if (!defined('MAPBOX_API_KEY')) { 8 | define('MAPBOX_API_KEY', ''); 9 | } 10 | 11 | // if sessions are enabled then the form uses a token for extra security against CSRF 12 | require_once '../vendor/autoload.php'; 13 | include_once "forms.php"; 14 | use Degami\PHPFormsApi as FAPI; 15 | 16 | session_start(); 17 | 18 | // Submit function to call when the form is submitted and passes validation. 19 | // This is where you would send the email (using PHP mail function) 20 | // as this is not a real example I'm just outputting the values for now. 21 | function locationsform_submit(&$form) 22 | { 23 | $form_values = $form->getValues(); 24 | return $form_values; 25 | //var_dump($form->get_triggering_element()); 26 | // Reset the form if you want it to display again. 27 | // $form->reset(); 28 | } 29 | 30 | $form = FAPI\FormBuilder::getForm('locationsform'); 31 | ?> 32 | 33 | 34 | 35 | Example locations form 36 | 37 | 38 | 39 | 40 | 41 | 44 | 47 | 48 | 49 | 50 |

Locations Form

51 |
52 | To list | 53 | Go back 54 |
55 |
56 |
process(); ?>
57 | isSubmitted()) : ?> 58 | 59 |
getSubmitResults());?>
60 |

Thanks for submitting the form.

61 | 62 | 63 | 64 | 65 | 66 |
67 | 68 | 69 | -------------------------------------------------------------------------------- /examples/multistep.php: -------------------------------------------------------------------------------- 1 | getValues()->toArray(); 15 | // print_r($form); 16 | // get submission triggering element 17 | //var_dump($form->get_triggering_element()); 18 | return $form_values; 19 | // Reset the form if you want it to display again. 20 | // $form->reset(); 21 | } 22 | 23 | $form = FAPI\FormBuilder::getForm('multistepform'); 24 | ?> 25 | 26 | 27 | 28 | Example multistep form 29 | 30 | 31 | 32 | 33 | 40 | 41 | 42 | 43 |

Example Multistep Form

44 |
45 | To list | 46 | Go back 47 |
48 |
49 |
process(); ?>
50 | isSubmitted()) : ?> 51 | 52 |

Thanks for submitting the form.

53 |
getSubmitResults());?>
54 | 55 | render(); ?> 56 | 57 | 58 | 59 |
60 | 61 | 62 | -------------------------------------------------------------------------------- /examples/nestables.php: -------------------------------------------------------------------------------- 1 | 0 && (strlen("".$string)%$length) == 0) ? true : '%t length must be multiple of '.$length; 15 | } 16 | 17 | 18 | function nestableform_submit(&$form) 19 | { 20 | $form_values = $form->getValues(); 21 | // print_r($form); 22 | // get submission triggering element 23 | 24 | // var_dump($form->get_triggering_element()); 25 | return $form_values; 26 | // Reset the form if you want it to display again. 27 | // $form->reset(); 28 | } 29 | 30 | $form = FAPI\FormBuilder::getForm('nestableform'); 31 | 32 | ?> 33 | 34 | 35 | 36 | Example Nestable form 37 | 38 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 |

Example Nestable form

53 |
54 | To list | 55 | Go back 56 |
57 |
58 |
process(); ?>
59 | isSubmitted()) : ?> 60 | 61 |

Thanks for submitting the form.

62 |
getSubmitResults());?>
63 | 64 | render(); ?> 65 | 66 | 67 | 68 |
69 | 70 | 71 | -------------------------------------------------------------------------------- /examples/object_form.php: -------------------------------------------------------------------------------- 1 | getValues()->toArray(); 12 | $form->addHighlight('Object submitted.'); 13 | return $form_values; 14 | } 15 | 16 | class MyClass 17 | { 18 | 19 | public $id; 20 | public $name; 21 | public $surname; 22 | public $birthday; 23 | public $number; 24 | 25 | public function __construct($name, $surname, $birthday, $number) 26 | { 27 | $this->id = 1; 28 | $this->name = $name; 29 | $this->surname = $surname; 30 | $this->birthday = $birthday; 31 | $this->number = $number; 32 | } 33 | } 34 | 35 | $classObject = new MyClass('Mirko', 'De Grandis', new \DateTime('1980-01-12'), 1); 36 | $form = FAPI\FormBuilder::objectForm($classObject); 37 | 38 | ?> 39 | 40 | 41 | 42 | Example object form 43 | 44 | 45 | 46 | 47 |

Example objectForm

48 |
49 | To list | 50 | Go back 51 |
52 |
53 |
process(); ?>
54 | isSubmitted()) : ?> 55 | 56 |

Thanks for submitting the form.

57 |
getSubmitResults());?>
58 | 59 | render(); ?> 60 | 61 | 62 | 63 |
64 | 65 | 66 | -------------------------------------------------------------------------------- /examples/plupload.php: -------------------------------------------------------------------------------- 1 | getValues(); 15 | if (is_array($form_values['files_upload']) && count($form_values['files_upload'])>0) { 16 | print $value->temppath . " => ".getcwd() . DIRECTORY_SEPARATOR . $value->name."\n"; 17 | rename($value->temppath, getcwd() . DIRECTORY_SEPARATOR . $value->name); 18 | } 19 | } 20 | 21 | $form = FAPI\FormBuilder::getForm('pluploadform'); 22 | 23 | 24 | ?> 25 | 26 | 27 | 28 | PLUpload Form 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 |

PLUpload Form

39 |
40 | To list | 41 | Go back 42 |
43 |
44 |
process(); ?>
45 | isSubmitted()) : ?> 46 | 47 |

Thanks for submitting the form.

48 | 49 | render(); ?> 50 | 51 | 52 | 53 |
54 | 55 | 56 | -------------------------------------------------------------------------------- /examples/repeatable.php: -------------------------------------------------------------------------------- 1 | getValues()->toArray(); 19 | return $form_values; 20 | } 21 | 22 | // function my_contactform_form_alter($form){ 23 | // $form->get_field('fieldset')->remove_field('message'); 24 | // } 25 | 26 | $form = FAPI\FormBuilder::getForm('repeatableform'); 27 | ?> 28 | 29 | 30 | 31 | Example contact form 32 | 33 | 34 | 35 | 40 | 41 | 42 | 43 |

Example Form

44 |
45 | To list | 46 | Go back 47 |
48 |
49 |
process(); ?>
50 | isSubmitted()) : ?> 51 | 52 |

Thanks for submitting the form.

53 |
getSubmitResults());?>
54 |
getValues());?>
55 | 56 | render(); ?> 57 | 58 | 59 | 60 |
61 | 62 | 63 | -------------------------------------------------------------------------------- /examples/showall.php: -------------------------------------------------------------------------------- 1 | 0 && (strlen("".$string)%$length) == 0) ? true : '%t length must be multiple of '.$length; 15 | } 16 | 17 | 18 | function showall_submit(&$form) 19 | { 20 | $form_values = serialize($form->getValues()); 21 | // print_r($form); 22 | // get submission triggering element 23 | 24 | // var_dump($form->get_triggering_element()); 25 | return $form_values; 26 | // Reset the form if you want it to display again. 27 | // $form->reset(); 28 | } 29 | 30 | function showall_validate(&$form) 31 | { 32 | $form_values = $form->getValues(); 33 | if ($form_values['fieldset']['name'] == 'aaa' && $form_values['tabs']['slider']==2) { 34 | return "You shall not pass!!!"; 35 | } 36 | 37 | return true; 38 | } 39 | $form = FAPI\FormBuilder::getForm('showallform'); 40 | 41 | ?> 42 | 43 | 44 | 45 | Example Show them all form 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 62 | 63 | 64 | 65 |

Example Show them all form

66 |
67 | To list | 68 | Go back 69 |
70 |
71 |
process(); ?>
72 | isSubmitted()) : ?> 73 | 74 |

Thanks for submitting the form.

75 |
getSubmitResults());?>
76 | 77 | render(); ?> 78 | 79 | 80 | 81 |
82 | 83 | 84 | -------------------------------------------------------------------------------- /src/classes/abstracts/containers/SortableContainer.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELD CONTAINERS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Abstracts\Containers; 17 | 18 | use Degami\PHPFormsApi\Abstracts\Base\Field; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\PHPFormsApi\Abstracts\Base\FieldsContainer; 21 | 22 | /** 23 | * an abstract sortable field container 24 | * 25 | * @abstract 26 | */ 27 | abstract class SortableContainer extends FieldsContainerMultiple 28 | { 29 | 30 | /** 31 | * sort handle position (left/right) 32 | * 33 | * @var string 34 | */ 35 | protected $handle_position = 'left'; 36 | 37 | /** 38 | * deltas array ( used for sorting ) 39 | * 40 | * @var array 41 | */ 42 | protected $deltas = []; 43 | 44 | /** 45 | * Get handle position (left/right) 46 | * 47 | * @return string handle position 48 | */ 49 | public function getHandlePosition(): string 50 | { 51 | return $this->handle_position; 52 | } 53 | 54 | /** 55 | * Return form elements values into this element 56 | * 57 | * @return mixed form values 58 | */ 59 | public function getValues() 60 | { 61 | $output = []; 62 | 63 | $fields_with_delta = $this->getFieldsWithDelta(); 64 | usort($fields_with_delta, [__CLASS__, 'orderbyDelta']); 65 | 66 | foreach ($fields_with_delta as $name => $info) { 67 | $field = $info['field']; 68 | /** @var Field $field */ 69 | if ($field->isAValue() == true) { 70 | $output[$name] = $field->getValues(); 71 | if (is_array($output[$name]) && empty($output[$name])) { 72 | unset($output[$name]); 73 | } 74 | } 75 | } 76 | return $output; 77 | } 78 | 79 | /** 80 | * Process (set) the fields value 81 | * 82 | * @param mixed $values value to set 83 | */ 84 | public function processValue($values) 85 | { 86 | foreach ($this->getFields() as $name => $field) { 87 | /** @var Field $field */ 88 | $partitionindex = $this->getPartitionIndex($field->getName()); 89 | 90 | if ($field instanceof FieldsContainer) { 91 | $this->getField($name)->processValue($values); 92 | } elseif (($requestValue = static::traverseArray($values, $field->getName())) != null) { 93 | $this->getField($name)->processValue($requestValue); 94 | } 95 | 96 | $this->deltas[$name] = isset($values[$this->getHtmlId().'-delta-'.$partitionindex]) ? 97 | $values[$this->getHtmlId().'-delta-'.$partitionindex] : 98 | 0; 99 | } 100 | } 101 | 102 | /** 103 | * Get an array of fields with the relative delta (ordering) information 104 | * 105 | * @return array fields with delta 106 | */ 107 | private function getFieldsWithDelta(): array 108 | { 109 | $out = []; 110 | foreach ($this->getFields() as $key => $field) { 111 | $out[$key]=['field'=> $field,'delta'=>$this->deltas[$key]]; 112 | } 113 | return $out; 114 | } 115 | 116 | /** 117 | * order elements by delta property 118 | * 119 | * @param array $a first element 120 | * @param array $b second element 121 | * @return integer order 122 | */ 123 | private static function orderbyDelta($a, $b): int 124 | { 125 | if ($a['delta']==$b['delta']) { 126 | return 0; 127 | } 128 | return ($a['delta']>$b['delta']) ? 1:-1; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/classes/abstracts/fields/Action.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Abstracts\Fields; 17 | 18 | use Degami\PHPFormsApi\Form; 19 | use Degami\PHPFormsApi\Abstracts\Base\Field; 20 | 21 | /** 22 | * The "actionable" field element class (a button, a submit or a reset) 23 | * 24 | * @abstract 25 | */ 26 | abstract class Action extends Field 27 | { 28 | 29 | /** 30 | * "use jqueryui button method on this element" flag 31 | * 32 | * @var boolean 33 | */ 34 | protected $js_button = false; 35 | 36 | /** 37 | * {@inheritdoc} 38 | * 39 | * @param Form $form form object 40 | */ 41 | public function preRender(Form $form) 42 | { 43 | if ($this->pre_rendered == true) { 44 | return; 45 | } 46 | if ($this->js_button == true) { 47 | $id = $this->getHtmlId(); 48 | $this->addJs("\$('#{$id}','#{$form->getId()}').button();"); 49 | } 50 | parent::preRender($form); 51 | } 52 | 53 | /** 54 | * {@inheritdoc} 55 | * 56 | * @return boolean this is not a value 57 | */ 58 | public function isAValue(): bool 59 | { 60 | return false; 61 | } 62 | 63 | /** 64 | * validate function 65 | * 66 | * @return boolean this field is always valid 67 | */ 68 | public function isValid(): bool 69 | { 70 | return true; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/classes/abstracts/fields/Captcha.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Abstracts\Fields; 17 | 18 | use Degami\PHPFormsApi\Form; 19 | use Degami\PHPFormsApi\FormBuilder; 20 | use Degami\PHPFormsApi\Abstracts\Base\Field; 21 | 22 | /** 23 | * The captcha field class 24 | */ 25 | abstract class Captcha extends Field 26 | { 27 | 28 | /** 29 | * "already validated" flag 30 | * 31 | * @var boolean 32 | */ 33 | protected $already_validated = false; 34 | 35 | /** 36 | * {@inheritdoc} 37 | * 38 | * @param mixed $values value to set 39 | */ 40 | public function processValue($values) 41 | { 42 | parent::processValue($values); 43 | if (isset($values['already_validated'])) { 44 | $this->already_validated = $values['already_validated']; 45 | } 46 | } 47 | 48 | /** 49 | * Check if element is already validated 50 | * 51 | * @return boolean TRUE if element has already been validated 52 | */ 53 | public function isAlreadyValidated(): bool 54 | { 55 | return $this->already_validated; 56 | } 57 | 58 | /** 59 | * {@inheritdoc} 60 | * 61 | * @return boolean this is not a value 62 | */ 63 | public function isAValue(): bool 64 | { 65 | return false; 66 | } 67 | 68 | /** 69 | * {@inheritdoc} 70 | * 71 | * @param Form $form form object 72 | */ 73 | public function afterValidate(Form $form) 74 | { 75 | $session_value =$this->getValues(); 76 | $session_value['already_validated'] = $this->isAlreadyValidated(); 77 | 78 | if (FormBuilder::sessionPresent()) { 79 | $this->getSessionBag()->ensurePath("/{$form->getId()}/steps/{$form->getCurrentStep()}"); 80 | $this->getSessionBag()->{$form->getId()}->steps->{$form->getCurrentStep()}->{$this->getName()} = $session_value; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/classes/abstracts/fields/Clickable.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Abstracts\Fields; 17 | 18 | use Degami\PHPFormsApi\Abstracts\Base\Field; 19 | 20 | /** 21 | * The "clickable" field element (a button or a submit ) 22 | * 23 | * @abstract 24 | */ 25 | abstract class Clickable extends Action 26 | { 27 | 28 | /** 29 | * "this element was clicked" flag 30 | * 31 | * @var boolean 32 | */ 33 | protected $clicked = false; 34 | 35 | /** 36 | * Class constructor 37 | * 38 | * @param array $options build options 39 | * @param ?string $name field name 40 | */ 41 | public function __construct($options = [], ?string $name = null) 42 | { 43 | parent::__construct($options, $name); 44 | if (isset($options['value'])) { 45 | $this->value = $options['value']; 46 | } 47 | $this->clicked = false; 48 | } 49 | 50 | /** 51 | * Check if this button was clicked 52 | * 53 | * @return boolean if this element was clicked 54 | */ 55 | public function getClicked(): bool 56 | { 57 | return $this->clicked; 58 | } 59 | 60 | /** 61 | * {@inheritdoc} 62 | * 63 | * @param mixed $value value to set 64 | */ 65 | public function processValue($value) 66 | { 67 | parent::processValue($value); 68 | $this->clicked = true; 69 | } 70 | 71 | /** 72 | * reset this element 73 | */ 74 | public function resetField() : Field 75 | { 76 | $this->clicked = false; 77 | return parent::resetField(); 78 | } 79 | 80 | /** 81 | * {@inheritdoc} 82 | * 83 | * @return boolean this is a value 84 | */ 85 | public function isAValue() : bool 86 | { 87 | return true; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/classes/abstracts/fields/ComposedField.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Abstracts\Fields; 17 | 18 | use Degami\Basics\Traits\ToolsTrait as BasicToolsTrait; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\PHPFormsApi\Containers\TagContainer; 21 | use Degami\PHPFormsApi\Abstracts\Base\Field; 22 | use Degami\Basics\Html\TagElement; 23 | 24 | /** 25 | * The composed field class 26 | */ 27 | abstract class ComposedField extends TagContainer 28 | { 29 | use BasicToolsTrait; 30 | 31 | /** 32 | * {@inheritdoc} 33 | * 34 | * @return boolean this is a value 35 | */ 36 | public function isAValue() : bool 37 | { 38 | return true; 39 | } 40 | 41 | /** 42 | * on_add_return overload 43 | * 44 | * @return string 'parent' 45 | */ 46 | public function onAddReturn() : string 47 | { 48 | return 'parent'; 49 | } 50 | 51 | 52 | /** 53 | * Return subfields name 54 | * 55 | * @param string $subfieldName 56 | * @return string 57 | */ 58 | protected function getSubfieldName(string $subfieldName): string 59 | { 60 | return $this->getName() . (preg_match("/.*?\[.*?\]$/", $this->getName()) ? '['.$subfieldName.']' : '_'.$subfieldName); 61 | } 62 | 63 | 64 | /** 65 | * Process subfield value 66 | * 67 | * @param array $values 68 | * @param Field $subfield 69 | * @param string $subfieldName 70 | */ 71 | protected function processSubfieldsValues(array $values, Field $subfield, string $subfieldName) 72 | { 73 | $subfield->processValue(static::traverseArray($values, $this->getSubfieldName($subfieldName))); 74 | } 75 | 76 | /** 77 | * {@inheritdoc} 78 | * 79 | * @param Form $form form object 80 | * 81 | * @return string|TagElement the element html 82 | */ 83 | public function renderField(Form $form) 84 | { 85 | $id = $this->getHtmlId(); 86 | 87 | $this->tag = 'div'; 88 | 89 | $required = ($this->validate->hasValue('required')) ? '*' : ''; 90 | $requiredafter = $requiredbefore = $required; 91 | if ($this->required_position == 'before') { 92 | $requiredafter = ''; 93 | $requiredbefore = $requiredbefore.' '; 94 | } else { 95 | $requiredbefore = ''; 96 | $requiredafter = ' '.$requiredafter; 97 | } 98 | 99 | if (!empty($this->title) && $this->tooltip == true && !in_array('title', array_keys($this->attributes))) { 100 | $this->attributes['title'] = strip_tags($this->getText($this->title).$required); 101 | } 102 | 103 | $tag = new TagElement([ 104 | 'tag' => $this->tag, 105 | 'id' => $id, 106 | 'attributes' => $this->attributes, 107 | ]); 108 | 109 | if (!empty($this->title)) { 110 | if ($this->tooltip == false) { 111 | $this->label_class .= " label-" .$this->getElementClassName(); 112 | $this->label_class = trim($this->label_class); 113 | 114 | $tag_label = new TagElement([ 115 | 'tag' => 'label', 116 | 'attributes' => [ 117 | 'for' => $id, 118 | 'class' => $this->label_class, 119 | 'text' => $requiredbefore 120 | ], 121 | ]); 122 | $tag_label->addChild($this->getText($this->title)); 123 | $tag_label->addChild($requiredafter); 124 | $tag->addChild($tag_label); 125 | } else { 126 | $id = $this->getHtmlId(); 127 | $form->addJs("\$('#{$id}','#{$form->getId()}').tooltip();"); 128 | } 129 | } 130 | 131 | foreach (get_object_vars($this) as $name => &$property) { 132 | if ($property instanceof Field) { 133 | if ($name == 'parent') { 134 | continue; 135 | } 136 | $tag->addChild($property->renderHTML($form)); 137 | } 138 | } 139 | 140 | return $tag; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/classes/abstracts/fields/FieldMultivalues.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Abstracts\Fields; 17 | 18 | use Degami\PHPFormsApi\Abstracts\Base\Field; 19 | use Degami\PHPFormsApi\Fields\Option; 20 | use Degami\PHPFormsApi\Fields\Optgroup; 21 | use Degami\PHPFormsApi\Abstracts\Fields\Optionable; 22 | 23 | /** 24 | * The multivalues field class (a select, a radios or a checkboxes group) 25 | * 26 | * @abstract 27 | */ 28 | abstract class FieldMultivalues extends Field 29 | { 30 | /** 31 | * options array 32 | * 33 | * @var array 34 | */ 35 | protected $options = []; 36 | 37 | /** 38 | * Adds an option to options array 39 | * 40 | * @param mixed $option option 41 | */ 42 | public function addOption($option) 43 | { 44 | $this->options[] = $option; 45 | } 46 | 47 | /** 48 | * Get elements options array by reference 49 | * 50 | * @return array element options 51 | */ 52 | public function &getOptions(): array 53 | { 54 | return $this->options; 55 | } 56 | 57 | /** 58 | * Check if key is present into haystack 59 | * 60 | * @param mixed $needle element to find 61 | * @param array $haystack where to find it 62 | * @return boolean TRUE if element is found 63 | */ 64 | public static function hasKey($needle, array $haystack): bool 65 | { 66 | foreach ($haystack as $key => $value) { 67 | if ($value instanceof Option) { 68 | if ($value->getKey() == $needle) { 69 | return true; 70 | } 71 | } elseif ($value instanceof Optgroup) { 72 | if ($value->optionsHasKey($needle) == true) { 73 | return true; 74 | } 75 | } elseif ($needle == $key) { 76 | return true; 77 | } elseif (FieldMultivalues::isForeacheable($value) && FieldMultivalues::hasKey($needle, $value) == true) { 78 | return true; 79 | } 80 | } 81 | return false; 82 | } 83 | 84 | /** 85 | * Check if key is present into element options 86 | * 87 | * @param mixed $needle element to find 88 | * @return boolean TRUE if element is found 89 | */ 90 | public function optionsHasKey($needle): bool 91 | { 92 | return FieldMultivalues::hasKey($needle, $this->options); 93 | } 94 | 95 | /** 96 | * {@inheritdoc} 97 | * 98 | * @return boolean TRUE if element is valid 99 | */ 100 | public function isValid(): bool 101 | { 102 | $titlestr = (!empty($this->title)) ? $this->title : (!empty($this->name) ? $this->name : $this->id); 103 | 104 | if (!is_array($this->value) && !empty($this->value)) { 105 | $check = $this->optionsHasKey($this->value); 106 | $this->addError(str_replace("%t", $titlestr, $this->getText("%t: Invalid choice")), __FUNCTION__); 107 | 108 | if (!$check) { 109 | return false; 110 | } 111 | } elseif (FieldMultivalues::isForeacheable($this->value)) { 112 | $check = true; 113 | foreach ($this->value as $key => $value) { 114 | $check &= $this->optionsHasKey($value); 115 | } 116 | if (!$check) { 117 | $this->addError(str_replace("%t", $titlestr, $this->getText("%t: Invalid choice")), __FUNCTION__); 118 | 119 | if ($this->stop_on_first_error) { 120 | return false; 121 | } 122 | } 123 | } 124 | return parent::isValid(); 125 | } 126 | 127 | /** 128 | * {@inheritdoc} 129 | * 130 | * @return boolean this is a value 131 | */ 132 | public function isAValue(): bool 133 | { 134 | return true; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/classes/abstracts/fields/Optionable.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Abstracts\Fields; 17 | 18 | use Degami\PHPFormsApi\Abstracts\Base\Element; 19 | 20 | /** 21 | * The optionable field class 22 | */ 23 | abstract class Optionable extends Element 24 | { 25 | /** 26 | * option label 27 | * 28 | * @var string 29 | */ 30 | protected $label; 31 | 32 | /** 33 | * Get the element label 34 | * 35 | * @return mixed the element label 36 | */ 37 | public function getLabel(): string 38 | { 39 | return $this->label; 40 | } 41 | 42 | /** 43 | * Set the element label 44 | * 45 | * @param mixed $label element label 46 | * @return self 47 | */ 48 | public function setLabel($label): Optionable 49 | { 50 | $this->label = $label; 51 | 52 | return $this; 53 | } 54 | 55 | /** 56 | * Class constructor 57 | * 58 | * @param string $label label 59 | * @param array $options options array 60 | */ 61 | public function __construct(string $label, array $options) 62 | { 63 | parent::__construct(); 64 | $this->setLabel($label); 65 | 66 | $this->setClassProperties($options); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/classes/accessories/FormValues.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### ACCESSORIES #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Accessories; 17 | 18 | use Degami\Basics\MultiLevelDataBag; 19 | 20 | /** 21 | * A class to hold form fields submitted values 22 | */ 23 | class FormValues extends MultiLevelDataBag 24 | { 25 | /** 26 | * onChange hook 27 | */ 28 | public function onChange() 29 | { 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/classes/accessories/NotificationsBag.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### ACCESSORIES #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Accessories; 17 | 18 | use Degami\Basics\MultiLevelDataBag; 19 | 20 | /** 21 | * A class to hold notifications 22 | */ 23 | 24 | class NotificationsBag extends MultiLevelDataBag 25 | { 26 | /** 27 | * render notifications 28 | * 29 | * @param string the notification group 30 | * 31 | * @return string the notification list html 32 | */ 33 | public function renderHTML($group = null): string 34 | { 35 | if ($group == null) { 36 | $out = ""; 37 | foreach ($this->keys() as $group) { 38 | if (($this->{$group} instanceof NotificationsBag && $this->{$group}->count() > 0) || 39 | (is_array($this->{$group}) && count($this->{$group}) > 0) 40 | ) { 41 | $out .= "
  • ". 42 | implode("
  • ", $this->{$group}->toArray()). 43 | "
  • "; 44 | } else { 45 | $out .= "
  • ".$this->{$group}."
  • "; 46 | } 47 | } 48 | return $out; 49 | } 50 | if (!isset($this->{$group}) || $this->{$group}->count() == 0) { 51 | return ''; 52 | } 53 | return "
  • ". 54 | implode( 55 | "
  • ", 56 | $this->{$group}->toArray() 57 | ). 58 | "
  • "; 59 | } 60 | 61 | /** 62 | * onChange hook 63 | */ 64 | public function onChange() 65 | { 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/classes/accessories/OrderedFunctions.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### ACCESSORIES #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Accessories; 17 | 18 | use Degami\Basics\DataBag; 19 | 20 | /** 21 | * class for maintaining ordered list of functions 22 | */ 23 | class OrderedFunctions extends DataBag 24 | { 25 | 26 | /** @var null|string sort function name */ 27 | private $sort_callback = null; 28 | 29 | /** @var string type */ 30 | private $type; 31 | 32 | /** @var array|null */ 33 | protected array $dataelement_data = []; 34 | 35 | /** 36 | * Class constructor 37 | * 38 | * @param array $array initially contained elements 39 | * @param string $type type of elements 40 | * @param callable $sort_callback sort callback name 41 | */ 42 | public function __construct(array $array, string $type, $sort_callback = null) 43 | { 44 | parent::__construct($array); 45 | $this->type = $type; 46 | $this->sort_callback = $sort_callback; 47 | $this->sort(); 48 | } 49 | 50 | /** 51 | * sort elements 52 | */ 53 | public function sort() 54 | { 55 | foreach ($this->dataelement_data as &$value) { 56 | if (is_string($value)) { 57 | $value = strtolower(trim($value)); 58 | } elseif (is_array($value) && isset($value[$this->type])) { 59 | $value[$this->type] = strtolower(trim($value[$this->type])); 60 | } 61 | } 62 | 63 | $this->dataelement_data = array_unique($this->dataelement_data, SORT_REGULAR); 64 | 65 | if (!empty($this->sort_callback) && is_callable($this->sort_callback)) { 66 | usort($this->dataelement_data, $this->sort_callback); 67 | } 68 | } 69 | 70 | /** 71 | * rewind pointer position 72 | */ 73 | public function rewind() : void 74 | { 75 | parent::rewind(); 76 | $this->sort(); 77 | } 78 | 79 | /** 80 | * Check if element is present 81 | * 82 | * @param mixed $value value to search 83 | * @return bool TRUE if $value was found 84 | */ 85 | public function hasValue($value): bool 86 | { 87 | return in_array($value, $this->getValues()); 88 | } 89 | 90 | /** 91 | * Check if key is in the array keys 92 | * 93 | * @param int $key key to search 94 | * @return bool TRUE if key was found 95 | */ 96 | public function hasKey(int $key): bool 97 | { 98 | return in_array($key, array_keys($this->dataelement_data)); 99 | } 100 | 101 | /** 102 | * Return element values 103 | * 104 | * @return mixed element values 105 | */ 106 | public function getValues(): array 107 | { 108 | $out = []; 109 | foreach ($this->dataelement_data as $key => $value) { 110 | if (is_array($value) && isset($value[$this->type])) { 111 | $out[] = $value[$this->type]; 112 | } else { 113 | $out[] = $value; 114 | } 115 | } 116 | return $out; 117 | } 118 | 119 | /** 120 | * Adds a new element to array elements 121 | * 122 | * @param mixed $value element to add 123 | * @return self 124 | */ 125 | public function addElement($value): OrderedFunctions 126 | { 127 | $this->dataelement_data[] = $value; 128 | $this->sort(); 129 | 130 | return $this; 131 | } 132 | 133 | /** 134 | * removes an element from array elements 135 | * 136 | * @param mixed $value element to remove 137 | * @return self 138 | */ 139 | public function removeElement($value): OrderedFunctions 140 | { 141 | $this->dataelement_data = array_diff($this->dataelement_data, [$value]); 142 | $this->sort(); 143 | 144 | return $this; 145 | } 146 | 147 | /** 148 | * Element to array 149 | * 150 | * @return array element to array 151 | */ 152 | public function toArray(): array 153 | { 154 | return $this->dataelement_data; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/classes/accessories/SessionBag.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### ACCESSORIES #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Accessories; 17 | 18 | use Degami\Basics\MultiLevelDataBag; 19 | use Degami\PHPFormsApi\FormBuilder; 20 | 21 | /** 22 | * A class to hold session values 23 | */ 24 | 25 | class SessionBag extends MultiLevelDataBag 26 | { 27 | 28 | /** 29 | * Class constructor 30 | * 31 | * @param mixed $data data to add 32 | * @param MultiLevelDataBag $parent parent node 33 | */ 34 | public function __construct($data = [], $parent = null) 35 | { 36 | if (!$parent && isset($_SESSION[self::getSessionIdentifier()])) { 37 | $data = unserialize($_SESSION[self::getSessionIdentifier()]); 38 | } 39 | parent::__construct($data, $parent); 40 | } 41 | 42 | /** 43 | * stores data to session 44 | */ 45 | public function onChange() 46 | { 47 | $_SESSION[self::getSessionIdentifier()] = serialize($this->toArray()); 48 | } 49 | 50 | /** 51 | * Get session identified 52 | * 53 | * @return string 54 | */ 55 | public static function getSessionIdentifier(): ?string 56 | { 57 | static $session_identifier = null; 58 | if (!$session_identifier) { 59 | if (isset($_SESSION['sessionbag_identifier'])) { 60 | return $_SESSION['sessionbag_identifier']; 61 | } 62 | $session_identifier = 'SESS_'.uniqid(); 63 | $_SESSION['sessionbag_identifier'] = $session_identifier; 64 | } 65 | return $session_identifier; 66 | } 67 | 68 | /** 69 | * {@inheritdoc} 70 | */ 71 | public function clear() : self 72 | { 73 | parent::clear(); 74 | if (FormBuilder::sessionPresent()) { 75 | session_destroy(); 76 | session_start(); 77 | } 78 | return $this; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/classes/containers/Accordion.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELD CONTAINERS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Containers; 17 | 18 | use Degami\PHPFormsApi\Abstracts\Base\Field; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\PHPFormsApi\Abstracts\Containers\FieldsContainerMultiple; 21 | use Degami\Basics\Html\TagElement; 22 | 23 | /** 24 | * an accordion field container 25 | */ 26 | class Accordion extends FieldsContainerMultiple 27 | { 28 | 29 | /** @var string height style */ 30 | protected $height_style = 'auto'; 31 | 32 | /** @var integer active tab */ 33 | protected $active = '0'; 34 | 35 | /** @var boolean collapsible */ 36 | protected $collapsible = false; 37 | 38 | 39 | /** 40 | * {@inheritdoc} 41 | * 42 | * @param Form $form form object 43 | */ 44 | public function preRender(Form $form) 45 | { 46 | if ($this->pre_rendered == true) { 47 | return; 48 | } 49 | $id = $this->getHtmlId(); 50 | $collapsible = ($this->collapsible) ? 'true':'false'; 51 | $this->addJs( 52 | "\$('#{$id}','#{$form->getId()}').accordion({ 53 | heightStyle: \"{$this->height_style}\", 54 | active: {$this->active}, 55 | collapsible: {$collapsible} 56 | });" 57 | ); 58 | 59 | parent::preRender($form); 60 | } 61 | 62 | /** 63 | * {@inheritdoc} 64 | * 65 | * @param Form $form form object 66 | * 67 | * @return string the element html 68 | */ 69 | public function renderField(Form $form) 70 | { 71 | $id = $this->getHtmlId(); 72 | $tag = new TagElement([ 73 | 'tag' => 'div', 74 | 'id' => $id, 75 | 'attributes' => $this->attributes, 76 | ]); 77 | 78 | foreach ($this->partitions as $accordionindex => $accordion) { 79 | $insertorder = array_flip($this->insert_field_order[$accordionindex]); 80 | $weights = []; 81 | $order = []; 82 | 83 | $partition_fields = $this->getPartitionFields($accordionindex); 84 | 85 | foreach ($partition_fields as $key => $elem) { 86 | /** @var Field $elem */ 87 | $weights[$key] = $elem->getWeight(); 88 | $order[$key] = $insertorder[$key]; 89 | } 90 | if (count($partition_fields) > 0) { 91 | array_multisort($weights, SORT_ASC, $order, SORT_ASC, $partition_fields); 92 | } 93 | $tag->addChild(new TagElement([ 94 | 'tag' => 'h3', 95 | 'text' => $this->getText($this->partitions[$accordionindex]['title']), 96 | 'attributes' => [ 97 | 'class' => 'tabel '.( 98 | $this->partitionHasErrors($accordionindex, $form) ? 99 | 'has-errors' : '' 100 | ) 101 | ], 102 | ])); 103 | $inner = new TagElement([ 104 | 'tag' => 'div', 105 | 'id' => $id.'-tab-inner-'.$accordionindex, 106 | 'attributes' => [ 107 | 'class' => 'tab-inner'.( 108 | $this->partitionHasErrors($accordionindex, $form) ? 109 | ' has-errors' : '' 110 | ) 111 | ], 112 | ]); 113 | foreach ($partition_fields as $name => $field) { 114 | /** @var Field $field */ 115 | $inner->addChild($field->renderHTML($form)); 116 | } 117 | $tag->addChild($inner); 118 | } 119 | 120 | return $tag; 121 | } 122 | 123 | /** 124 | * Adds a new accordion 125 | * 126 | * @param string $title accordion title 127 | * @return self 128 | */ 129 | public function addAccordion($title): Accordion 130 | { 131 | return $this->addPartition($title); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/classes/containers/Fieldset.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELD CONTAINERS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Containers; 17 | 18 | use Degami\PHPFormsApi\Abstracts\Base\Field; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\PHPFormsApi\Abstracts\Base\FieldsContainer; 21 | use Degami\Basics\Html\TagElement; 22 | 23 | /** 24 | * a fieldset field container 25 | */ 26 | class Fieldset extends FieldsContainer 27 | { 28 | 29 | /** 30 | * collapsible flag 31 | * 32 | * @var boolean 33 | */ 34 | protected $collapsible = false; 35 | 36 | /** 37 | * collapsed flag 38 | * 39 | * @var boolean 40 | */ 41 | protected $collapsed = false; 42 | 43 | /** 44 | * inner div attributes 45 | * 46 | * @var array 47 | */ 48 | protected $inner_attributes = []; 49 | 50 | /** 51 | * {@inheritdoc} 52 | * 53 | * @param Form $form form object 54 | */ 55 | public function preRender(Form $form) 56 | { 57 | static $js_collapsible_added = false; 58 | if ($this->pre_rendered == true) { 59 | return; 60 | } 61 | 62 | if (!isset($this->attributes['class'])) { 63 | $this->attributes['class'] = ''; 64 | } 65 | if ($this->collapsible) { 66 | $this->attributes['class'] .= ' collapsible'; 67 | if ($this->collapsed) { 68 | $this->attributes['class'] .= ' collapsed'; 69 | } else { 70 | $this->attributes['class'] .= ' expanded'; 71 | } 72 | 73 | if (!$js_collapsible_added) { 74 | $this->addJs( 75 | " 76 | \$('fieldset.collapsible').find('legend:not(\".collapsible-attached\")').css({'cursor':'pointer'}).click(function(evt){ 77 | evt.preventDefault(); 78 | var \$this = \$(this); 79 | \$this.parent().find('.fieldset-inner').toggle( 'blind', {}, 500, function(){ 80 | if(\$this.parent().hasClass('expanded')){ 81 | \$this.parent().removeClass('expanded').addClass('collapsed'); 82 | }else{ 83 | \$this.parent().removeClass('collapsed').addClass('expanded'); 84 | } 85 | }); 86 | }).addClass('collapsible-attached'); 87 | \$('fieldset.collapsible.collapsed .fieldset-inner').hide();" 88 | ); 89 | $js_collapsible_added = true; 90 | } 91 | } 92 | 93 | parent::preRender($form); 94 | } 95 | 96 | /** 97 | * {@inheritdoc} 98 | * 99 | * @param Form $form form object 100 | * 101 | * @return TagElement the element html 102 | */ 103 | public function renderField(Form $form) 104 | { 105 | $id = $this->getHtmlId(); 106 | 107 | $insertorder = array_flip($this->insert_field_order); 108 | $weights = []; 109 | $order = []; 110 | foreach ($this->getFields() as $key => $elem) { 111 | /** @var Field $elem */ 112 | $weights[$key] = $elem->getWeight(); 113 | $order[$key] = $insertorder[$key]; 114 | } 115 | if (count($this->getFields()) > 0) { 116 | array_multisort($weights, SORT_ASC, $order, SORT_ASC, $this->getFields()); 117 | } 118 | 119 | $tag = new TagElement([ 120 | 'tag' => 'fieldset', 121 | 'id' => $id, 122 | 'attributes' => $this->attributes, 123 | ]); 124 | if (!empty($this->title)) { 125 | $tag->addChild(new TagElement([ 126 | 'tag' => 'legend', 127 | 'text' => $this->getText($this->title), 128 | ])); 129 | } 130 | 131 | $inner_attributes = $this->inner_attributes; 132 | if (!isset($inner_attributes['class'])) { 133 | $inner_attributes['class'] = ''; 134 | } 135 | $inner_attributes['class'] .= ' fieldset-inner'; 136 | $inner_attributes['class'] = trim($inner_attributes['class']); 137 | 138 | $inner = new TagElement([ 139 | 'tag' => 'div', 140 | 'attributes' => $inner_attributes, 141 | ]); 142 | foreach ($this->getFields() as $name => $field) { 143 | /** @var Field $field */ 144 | $inner->addChild($field->renderHTML($form)); 145 | } 146 | 147 | $tag->addChild($inner); 148 | return $tag; 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/classes/containers/SeamlessContainer.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELD CONTAINERS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Containers; 17 | 18 | use Degami\PHPFormsApi\Abstracts\Base\Field; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\PHPFormsApi\Abstracts\Base\FieldsContainer; 21 | 22 | /** 23 | * an hidden field container 24 | */ 25 | class SeamlessContainer extends FieldsContainer 26 | { 27 | 28 | /** 29 | * {@inheritdoc} 30 | * 31 | * @param Form $form form object 32 | * 33 | * @return string the element html 34 | */ 35 | public function renderField(Form $form): string 36 | { 37 | $output = ""; 38 | 39 | $insertorder = array_flip($this->insert_field_order); 40 | $weights = []; 41 | $order = []; 42 | foreach ($this->getFields() as $key => $elem) { 43 | /** @var Field $elem */ 44 | $weights[$key] = $elem->getWeight(); 45 | $order[$key] = $insertorder[$key]; 46 | } 47 | if (count($this->getFields()) > 0) { 48 | array_multisort($weights, SORT_ASC, $order, SORT_ASC, $this->getFields()); 49 | } 50 | foreach ($this->getFields() as $name => $field) { 51 | /** @var Field $field */ 52 | $output .= $field->renderHTML($form); 53 | } 54 | 55 | return $output; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/classes/containers/Sortable.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELD CONTAINERS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Containers; 17 | 18 | use Degami\Basics\Html\BaseElement; 19 | use Degami\PHPFormsApi\Abstracts\Base\Field; 20 | use Degami\PHPFormsApi\Abstracts\Base\FieldsContainer; 21 | use Degami\PHPFormsApi\Exceptions\FormException; 22 | use Degami\PHPFormsApi\Form; 23 | use Degami\PHPFormsApi\Abstracts\Containers\SortableContainer; 24 | use Degami\Basics\Html\TagElement; 25 | 26 | /** 27 | * a sortable field container 28 | */ 29 | class Sortable extends SortableContainer 30 | { 31 | 32 | /** 33 | * {@inheritdoc} 34 | * 35 | * @param string $name field name 36 | * @param mixed $field field to add, can be an array or a field subclass 37 | * @throws FormException 38 | */ 39 | public function addField(string $name, $field) : Field 40 | { 41 | //force every field to have its own tab. 42 | $this->deltas[$name] = count($this->getFields()); 43 | return parent::addField($name, $field, $this->deltas[$name]); 44 | } 45 | 46 | /** 47 | * {@inheritdoc} 48 | * 49 | * @param string $name field name 50 | */ 51 | public function removeField(string $name) : FieldsContainer 52 | { 53 | parent::removeField($name, $this->deltas['name']); 54 | unset($this->deltas[$name]); 55 | return $this; 56 | } 57 | 58 | /** 59 | * {@inheritdoc} 60 | * 61 | * @param Form $form form object 62 | */ 63 | public function preRender(Form $form) 64 | { 65 | if ($this->pre_rendered == true) { 66 | return; 67 | } 68 | $id = $this->getHtmlId(); 69 | $this->addJs( 70 | "\$('#{$id}','#{$form->getId()}').sortable({ 71 | placeholder: \"ui-state-highlight\", 72 | stop: function( event, ui ) { 73 | \$(this).find('input[type=hidden][name*=\"sortable-delta-\"]').each(function(index,elem){ 74 | \$(elem).val(index); 75 | }); 76 | } 77 | });" 78 | ); 79 | 80 | parent::preRender($form); 81 | } 82 | 83 | /** 84 | * {@inheritdoc} 85 | * 86 | * @param Form $form form object 87 | * 88 | * @return string|BaseElement the element html 89 | */ 90 | public function renderField(Form $form) 91 | { 92 | $id = $this->getHtmlId(); 93 | 94 | $handle_position = trim(strtolower($this->getHandlePosition())); 95 | 96 | $tag = new TagElement([ 97 | 'tag' => 'div', 98 | 'id' => $id, 99 | 'attributes' => $this->attributes, 100 | ]); 101 | 102 | foreach ($this->partitions as $partitionindex => $tab) { 103 | $insertorder = array_flip($this->insert_field_order[$partitionindex]); 104 | $weights = []; 105 | $order = []; 106 | 107 | $partition_fields = $this->getPartitionFields($partitionindex); 108 | foreach ($partition_fields as $key => $elem) { 109 | /** @var Field $elem */ 110 | $weights[$key] = $elem->getWeight(); 111 | $order[$key] = $insertorder[$key]; 112 | } 113 | if (count($partition_fields) > 0) { 114 | array_multisort($weights, SORT_ASC, $order, SORT_ASC, $partition_fields); 115 | } 116 | 117 | $inner = new TagElement([ 118 | 'tag' => 'div', 119 | 'id' => $id.'-sortable-'.$partitionindex, 120 | 'attributes' => ['class' => 'tab-inner ui-state-default'], 121 | ]); 122 | 123 | $tag->addChild($inner); 124 | 125 | if ($handle_position != 'right') { 126 | $inner->addChild(new TagElement([ 127 | 'tag' => 'span', 128 | 'attributes' => [ 129 | 'class' => 'ui-icon ui-icon-arrowthick-2-n-s', 130 | 'style' => 'display: inline-block;' 131 | ], 132 | ])); 133 | } 134 | 135 | $inner_inline = new TagElement([ 136 | 'tag' => 'div', 137 | 'attributes' => ['style' => 'display: inline-block;'], 138 | ]); 139 | $inner->addChild($inner_inline); 140 | 141 | foreach ($partition_fields as $name => $field) { 142 | /** @var Field $field */ 143 | $inner_inline->addChild($field->renderHTML($form)); 144 | } 145 | $inner_inline->addChild(new TagElement([ 146 | 'tag' => 'input', 147 | 'type' => 'hidden', 148 | 'name' => $id.'-delta-'.$partitionindex, 149 | 'value' => $partitionindex, 150 | 'has_close' => false, 151 | ])); 152 | if ($handle_position == 'right') { 153 | $inner_inline->addChild(new TagElement([ 154 | 'tag' => 'span', 155 | 'attributes' => [ 156 | 'class' => 'ui-icon ui-icon-arrowthick-2-n-s', 157 | 'style' => 'display: inline-block;float: right;' 158 | ], 159 | ])); 160 | } 161 | } 162 | return $tag; 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/classes/containers/Tabs.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELD CONTAINERS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Containers; 17 | 18 | use Degami\PHPFormsApi\Abstracts\Base\Field; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\PHPFormsApi\Abstracts\Containers\FieldsContainerMultiple; 21 | use Degami\Basics\Html\TagElement; 22 | 23 | /** 24 | * a "tabbed" field container 25 | */ 26 | class Tabs extends FieldsContainerMultiple 27 | { 28 | 29 | /** 30 | * {@inheritdoc} 31 | * 32 | * @param Form $form form object 33 | */ 34 | public function preRender(Form $form) 35 | { 36 | if ($this->pre_rendered == true) { 37 | return; 38 | } 39 | $id = $this->getHtmlId(); 40 | $this->addJs("\$('#{$id}','#{$form->getId()}').tabs();"); 41 | 42 | parent::preRender($form); 43 | } 44 | 45 | /** 46 | * {@inheritdoc} 47 | * 48 | * @param Form $form form object 49 | * 50 | * @return string the element html 51 | */ 52 | public function renderField(Form $form) 53 | { 54 | $id = $this->getHtmlId(); 55 | 56 | $tag = new TagElement([ 57 | 'tag' => 'div', 58 | 'id' => $id, 59 | 'attributes' => $this->attributes, 60 | ]); 61 | 62 | $tab_links = new TagElement(['tag' => 'ul']); 63 | $tag->addChild($tab_links); 64 | 65 | foreach ($this->partitions as $tabindex => $tab) { 66 | $insertorder = array_flip($this->insert_field_order[$tabindex]); 67 | $weights = []; 68 | $order = []; 69 | 70 | $partition_fields = $this->getPartitionFields($tabindex); 71 | 72 | foreach ($partition_fields as $key => $elem) { 73 | /** @var Field $elem */ 74 | $weights[$key] = $elem->getWeight(); 75 | $order[$key] = $insertorder[$key]; 76 | } 77 | if (count($this->getPartitionFields($tabindex)) > 0) { 78 | array_multisort($weights, SORT_ASC, $order, SORT_ASC, $partition_fields); 79 | } 80 | 81 | $tab_links->addChild(new TagElement([ 82 | 'tag' => 'li', 83 | 'attributes' => ['class' => 'tabel '.($this->partitionHasErrors($tabindex, $form) ? 'has-errors' : '')], 84 | 'text' => "". 85 | $this->getText($this->partitions[$tabindex]['title'])."" 86 | ])); 87 | 88 | $inner = new TagElement([ 89 | 'tag' => 'div', 90 | 'id' => $id.'-tab-inner-'.$tabindex, 91 | 'attributes' => [ 92 | 'class' => 'tab-inner'.($this->partitionHasErrors($tabindex, $form) ? ' has-errors' : '') 93 | ], 94 | ]); 95 | 96 | foreach ($partition_fields as $name => $field) { 97 | /** @var Field $field */ 98 | $inner->addChild($field->renderHTML($form)); 99 | } 100 | $tag->addChild($inner); 101 | } 102 | 103 | return $tag; 104 | } 105 | 106 | /** 107 | * Add a new tab 108 | * 109 | * @param string $title tab title 110 | * @return self 111 | */ 112 | public function addTab(string $title): Tabs 113 | { 114 | return $this->addPartition($title); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/classes/containers/TagContainer.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELD CONTAINERS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Containers; 17 | 18 | use Degami\PHPFormsApi\Abstracts\Base\Field; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\PHPFormsApi\Abstracts\Base\FieldsContainer; 21 | use Degami\Basics\Html\TagElement; 22 | 23 | /** 24 | * a field container that can specify container's html tag 25 | */ 26 | class TagContainer extends FieldsContainer 27 | { 28 | /** 29 | * container html tag 30 | * 31 | * @var string 32 | */ 33 | protected $tag = 'div'; 34 | 35 | /** 36 | * Class constructor 37 | * 38 | * @param array $options build options 39 | * @param string $name field name 40 | */ 41 | public function __construct($options = [], $name = null) 42 | { 43 | parent::__construct($options, $name); 44 | 45 | if ($this->attributes['class'] == 'tag_container') { // if set to the default 46 | $this->attributes['class'] = $this->tag.'_container'; 47 | } 48 | } 49 | 50 | /** 51 | * {@inheritdoc} 52 | * 53 | * @param Form $form form object 54 | * 55 | * @return string|TagElement the element html 56 | */ 57 | public function renderField(Form $form) 58 | { 59 | $id = $this->getHtmlId(); 60 | 61 | $tag = new TagElement([ 62 | 'tag' => $this->tag, 63 | 'id' => $id, 64 | 'attributes' => $this->attributes, 65 | 'has_close' => true, 66 | 'value_needed' => false, 67 | ]); 68 | 69 | $insertorder = array_flip($this->insert_field_order); 70 | $weights = []; 71 | $order = []; 72 | foreach ($this->getFields() as $key => $elem) { 73 | /** @var Field $elem */ 74 | $weights[$key] = $elem->getWeight(); 75 | $order[$key] = $insertorder[$key]; 76 | } 77 | if (count($this->getFields()) > 0) { 78 | array_multisort($weights, SORT_ASC, $order, SORT_ASC, $this->getFields()); 79 | } 80 | foreach ($this->getFields() as $name => $field) { 81 | /** @var Field $field */ 82 | $tag->addChild($field->renderHTML($form)); 83 | } 84 | return $tag; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/classes/exceptions/FormException.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### EXCEPTIONS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Exceptions; 17 | 18 | use Degami\Basics\Exceptions\BasicException; 19 | 20 | class FormException extends BasicException 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /src/classes/fields/Autocomplete.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\PHPFormsApi\Form; 19 | 20 | /** 21 | * The "autocomplete" text input field class 22 | */ 23 | class Autocomplete extends Textfield 24 | { 25 | /** 26 | * autocomplete path 27 | * 28 | * @var mixed 29 | */ 30 | protected $autocomplete_path = false; 31 | 32 | /** 33 | * options for autocomplete (if autocomplete path was not provided) 34 | * 35 | * @var array 36 | */ 37 | protected $options = []; 38 | 39 | /** 40 | * minimum string length for autocomplete 41 | * 42 | * @var integer 43 | */ 44 | protected $min_length = 3; 45 | 46 | /** 47 | * Class constructor 48 | * 49 | * @param array $options build options 50 | * @param ?string $name field name 51 | */ 52 | public function __construct(array $options = [], ?string $name = null) 53 | { 54 | if (!isset($options['attributes']['class'])) { 55 | $options['attributes']['class'] = ''; 56 | } 57 | $options['attributes']['class'] .= ' autocomplete'; 58 | 59 | parent::__construct($options, $name); 60 | } 61 | 62 | /** 63 | * {@inheritdoc} 64 | * 65 | * @param Form $form form object 66 | */ 67 | public function preRender(Form $form) 68 | { 69 | if ($this->pre_rendered == true) { 70 | return; 71 | } 72 | $id = $this->getHtmlId(); 73 | 74 | $this->addJs( 75 | " 76 | \$('#{$id}','#{$form->getId()}') 77 | .bind( 'keydown', function( event ) { 78 | if ( event.keyCode === $.ui.keyCode.TAB && \$( this ).autocomplete( 'instance' ).menu.active ) { 79 | event.preventDefault(); 80 | } 81 | }) 82 | .autocomplete({ 83 | source: " . ((!empty($this->options)) ? 84 | json_encode($this->options) : 85 | "'{$this->autocomplete_path}'") . ", 86 | minLength: {$this->min_length}, 87 | focus: function() { 88 | return false; 89 | } 90 | }); 91 | " 92 | ); 93 | 94 | parent::preRender($form); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/classes/fields/Button.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\PHPFormsApi\Form; 19 | use Degami\Basics\Html\TagElement; 20 | use Degami\PHPFormsApi\Abstracts\Fields\Clickable; 21 | 22 | /** 23 | * The button field class 24 | */ 25 | class Button extends Clickable 26 | { 27 | 28 | /** 29 | * Element label 30 | * 31 | * @var string 32 | */ 33 | protected $label; 34 | 35 | /** 36 | * Class constructor 37 | * 38 | * @param array $options build options 39 | * @param ?string $name field name 40 | */ 41 | public function __construct(array $options = [], ?string $name = null) 42 | { 43 | parent::__construct($options, $name); 44 | if (empty($this->label)) { 45 | $this->label = $this->getValues(); 46 | } 47 | } 48 | 49 | /** 50 | * {@inheritdoc} 51 | * 52 | * @param Form $form form object 53 | * 54 | * @return string the element html 55 | */ 56 | public function renderField(Form $form) 57 | { 58 | $id = $this->getHtmlId(); 59 | if ($this->disabled == true) { 60 | $this->attributes['disabled']='disabled'; 61 | } 62 | 63 | return new TagElement([ 64 | 'tag' => 'button', 65 | 'id' => $id, 66 | 'name' => $this->name, 67 | 'value' => $this->getValues(), 68 | 'text' => $this->getText($this->label), 69 | 'attributes' => $this->attributes, 70 | 'has_close' => true, 71 | ]); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/classes/fields/Checkbox.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\Basics\Html\BaseElement; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\PHPFormsApi\Abstracts\Base\Field; 21 | use Degami\Basics\Html\TagElement; 22 | 23 | /** 24 | * The single checkbox input field class 25 | */ 26 | class Checkbox extends Field 27 | { 28 | /** 29 | * @var string where (after or before) to print text 30 | */ 31 | protected $text_position = 'after'; 32 | 33 | /** 34 | * Class constructor 35 | * 36 | * @param array $options build options 37 | * @param ?string $name field name 38 | */ 39 | public function __construct(array $options = [], ?string $name = null) 40 | { 41 | parent::__construct($options, $name); 42 | $this->value = null; 43 | if (isset($options['value'])) { 44 | $this->value = $options['value']; 45 | } 46 | } 47 | 48 | /** 49 | * {@inheritdoc} 50 | * 51 | * @param Form $form form object 52 | * 53 | * @return string|BaseElement the element html 54 | */ 55 | public function renderField(Form $form) 56 | { 57 | $id = $this->getHtmlId(); 58 | 59 | if ($this->disabled == true) { 60 | $this->attributes['disabled']='disabled'; 61 | } 62 | 63 | $this->label_class .= " label-" . $this->getElementClassName(); 64 | $this->label_class = trim($this->label_class); 65 | 66 | if ($this->value == $this->default_value) { 67 | $this->attributes['checked'] = 'checked'; 68 | } 69 | 70 | $tag = new TagElement([ 71 | 'tag' => 'label', 72 | 'attributes' => ['for' => $id, 'class' => $this->label_class], 73 | 'text' => (($this->text_position == 'before') ? $this->getText($this->title) : ''), 74 | ]); 75 | $tag->addChild(new TagElement([ 76 | 'tag' => 'input', 77 | 'type' => 'checkbox', 78 | 'id' => $id, 79 | 'name' => $this->name, 80 | 'value' => $this->default_value, 81 | 'attributes' => $this->attributes, 82 | 'text' => (($this->text_position != 'before') ? $this->getText($this->title) : ''), 83 | ])); 84 | return $tag; 85 | } 86 | 87 | /** 88 | * {@inheritdoc} 89 | * 90 | * @return boolean this is a value 91 | */ 92 | public function isAValue(): bool 93 | { 94 | return true; 95 | } 96 | 97 | /** 98 | * {@inheritdoc} 99 | * 100 | * @return mixed field value 101 | */ 102 | public function getValues() 103 | { 104 | return $this->getValue(); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/classes/fields/Checkboxes.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\Basics\Html\BaseElement; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\Basics\Html\TagElement; 21 | use Degami\PHPFormsApi\Abstracts\Fields\FieldMultivalues; 22 | 23 | /** 24 | * The checkboxes group field class 25 | */ 26 | class Checkboxes extends FieldMultivalues 27 | { 28 | /** 29 | * {@inheritdoc} 30 | * 31 | * @param Form $form form object 32 | * 33 | * @return string|BaseElement the element html 34 | */ 35 | public function renderField(Form $form) 36 | { 37 | $id = $this->getHtmlId(); 38 | if (!is_array($this->default_value)) { 39 | $this->default_value = [ $this->default_value ]; 40 | } 41 | 42 | $tag = new TagElement([ 43 | 'tag' => 'div', 'attributes' => ['class' => 'options'], 44 | ]); 45 | 46 | if ($this->disabled == true) { 47 | $this->attributes['disabled']='disabled'; 48 | } 49 | 50 | foreach ($this->options as $key => $value) { 51 | if ($value instanceof Checkbox) { 52 | $value->setName("{$this->name}".(count($this->options)>1 ? "[]":"")); 53 | $value->setId("{$this->name}-{$key}"); 54 | $tag->addChild($value->renderHTML($form)); 55 | } else { 56 | if (is_array($value) && isset($value['attributes'])) { 57 | $attributes = $value['attributes']; 58 | } else { 59 | $attributes = []; 60 | } 61 | if (is_array($value)) { 62 | $value = $value['value']; 63 | } 64 | 65 | $tag_label = new TagElement([ 66 | 'tag' => 'label', 67 | 'attributes' => ['for' => "{$id}-{$key}", 'class' => "label-checkbox"], 68 | ]); 69 | $tag_label->addChild(new TagElement([ 70 | 'tag' => 'input', 71 | 'type' => 'checkbox', 72 | 'id' => "{$id}-{$key}", 73 | 'name' => "{$this->name}".(count($this->options)>1 ? "[]" : ""), 74 | 'value' => $key, 75 | 'attributes' => array_merge( 76 | $attributes, 77 | ( 78 | is_array($this->default_value) && 79 | in_array($key, $this->default_value) 80 | ) ? 81 | ['checked' => 'checked'] : [] 82 | ), 83 | 'text' => $value, 84 | ])); 85 | $tag->addChild($tag_label); 86 | } 87 | } 88 | 89 | return $tag; 90 | } 91 | 92 | /** 93 | * {@inheritdoc} 94 | * 95 | * @return mixed field value 96 | */ 97 | public function getValues() 98 | { 99 | return $this->getValue(); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/classes/fields/Color.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\Basics\Html\BaseElement; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\PHPFormsApi\Abstracts\Base\Field; 21 | use Degami\Basics\Html\TagElement; 22 | 23 | /** 24 | * The color input field class 25 | */ 26 | class Color extends Field 27 | { 28 | /** 29 | * Class constructor 30 | * 31 | * @param array $options build options 32 | * @param ?string $name field name 33 | */ 34 | public function __construct(array $options = [], ?string $name = null) 35 | { 36 | parent::__construct($options, $name); 37 | if (!empty($this->default_value) && !$this->isRGB($this->default_value)) { 38 | $this->value = $this->default_value = '#000000'; 39 | } 40 | } 41 | 42 | /** 43 | * Check if string is an RGB representation 44 | * 45 | * @param string $str string to check 46 | * @return boolean true if string is RGB 47 | */ 48 | private function isRGB(string $str): bool 49 | { 50 | return preg_match("/^#?([a-f\d]{3}([a-f\d]{3})?)$/i", $str); 51 | } 52 | 53 | /** 54 | * {@inheritdoc} 55 | * 56 | * @param Form $form form object 57 | * 58 | * @return string|BaseElement the element html 59 | */ 60 | public function renderField(Form $form) 61 | { 62 | $id = $this->getHtmlId(); 63 | 64 | if (!isset($this->attributes['class'])) { 65 | $this->attributes['class'] = ''; 66 | } 67 | if ($this->hasErrors()) { 68 | $this->attributes['class'] .= ' has-errors'; 69 | } 70 | if ($this->disabled == true) { 71 | $this->attributes['disabled']='disabled'; 72 | } 73 | if (is_array($this->value)) { 74 | $this->value = ''; 75 | } 76 | 77 | return new TagElement([ 78 | 'tag' => 'input', 79 | 'type' => 'color', 80 | 'id' => $id, 81 | 'name' => $this->name, 82 | 'value' => htmlspecialchars($this->getValues()), 83 | 'attributes' => $this->attributes + ['size' => $this->size], 84 | ]); 85 | } 86 | 87 | /** 88 | * {@inheritdoc} 89 | * 90 | * @return boolean this is a value 91 | */ 92 | public function isAValue(): bool 93 | { 94 | return true; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/classes/fields/Datalist.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\Basics\Html\BaseElement; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\Basics\Html\TagElement; 21 | use Degami\PHPFormsApi\Abstracts\Fields\FieldMultivalues; 22 | use Degami\Basics\Html\TagList; 23 | 24 | /** 25 | * The "autocomplete" text input field class 26 | */ 27 | class Datalist extends FieldMultivalues 28 | { 29 | /** 30 | * Class constructor 31 | * 32 | * @param array $options build options 33 | * @param ?string $name field name 34 | */ 35 | public function __construct(array $options = [], ?string $name = null) 36 | { 37 | if (isset($options['options'])) { 38 | foreach ($options['options'] as $k => $o) { 39 | if ($o instanceof Option) { 40 | $o->setParent($this); 41 | $this->options[] = $o; 42 | } else { 43 | $option = new Option($o, $o); 44 | $option->setParent($this); 45 | $this->options[] = $option; 46 | } 47 | } 48 | unset($options['options']); 49 | } 50 | 51 | if (isset($options['default_value'])) { 52 | if (is_array($options['default_value'])) { 53 | $options['default_value'] = reset($options['default_value']); 54 | } 55 | $options['default_value'] = "".$options['default_value']; 56 | } 57 | 58 | parent::__construct($options, $name); 59 | } 60 | 61 | /** 62 | * {@inheritdoc} 63 | * 64 | * @param Form $form form object 65 | * @return string|BaseElement the element html 66 | */ 67 | public function renderField(Form $form) 68 | { 69 | $id = $this->getHtmlId(); 70 | 71 | if (!isset($this->attributes['class'])) { 72 | $this->attributes['class'] = ''; 73 | } 74 | if ($this->hasErrors()) { 75 | $this->attributes['class'] .= ' has-errors'; 76 | } 77 | if ($this->disabled == true) { 78 | $this->attributes['disabled']='disabled'; 79 | } 80 | if (is_array($this->value)) { 81 | $this->value = ''; 82 | } 83 | 84 | $tag = new TagList(); 85 | $tag->addChild(new TagElement([ 86 | 'tag' => 'input', 87 | 'type' => 'text', 88 | 'id' => $id, 89 | 'name' => $this->name, 90 | 'value' => htmlspecialchars($this->getValues()), 91 | 'attributes' => $this->attributes + ['size' => $this->size, 'list' => $this->name."-data"], 92 | ])); 93 | 94 | $dlist = new TagElement([ 95 | 'tag' => 'datalist', 96 | 'type' => null, 97 | 'id' => $this->name.'-data', 98 | 'value_needed' => false, 99 | 'has_close' => true, 100 | ]); 101 | foreach ($this->options as $key => $opt) { 102 | /** @var Option $opt */ 103 | $dlist->addChild(new TagElement([ 104 | 'tag' => 'option', 105 | 'type' => null, 106 | 'value' => $opt->getKey(), 107 | 'text' => $this->getText($opt->getLabel()), 108 | 'has_close' => true, 109 | ])); 110 | } 111 | $tag->addChild($dlist); 112 | 113 | return $tag; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/classes/fields/Date.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\Basics\Html\BaseElement; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\PHPFormsApi\Abstracts\Base\Field; 21 | use Degami\Basics\Html\TagElement; 22 | 23 | /** 24 | * The date field class 25 | */ 26 | class Date extends Field 27 | { 28 | /** 29 | * Class constructor 30 | * 31 | * @param array $options build options 32 | * @param ?string $name field name 33 | */ 34 | public function __construct(array $options = [], ?string $name = null) 35 | { 36 | $this->default_value = date('Y-m-d'); 37 | parent::__construct($options, $name); 38 | } 39 | 40 | /** 41 | * {@inheritdoc} 42 | * 43 | * @param Form $form form object 44 | * 45 | * @return string|BaseElement the element html 46 | */ 47 | public function renderField(Form $form) 48 | { 49 | $id = $this->getHtmlId(); 50 | 51 | if (!isset($this->attributes['class'])) { 52 | $this->attributes['class'] = ''; 53 | } 54 | if ($this->hasErrors()) { 55 | $this->attributes['class'] .= ' has-errors'; 56 | } 57 | if ($this->disabled == true) { 58 | $this->attributes['disabled']='disabled'; 59 | } 60 | if (is_array($this->value)) { 61 | $this->value = ''; 62 | } 63 | 64 | return new TagElement([ 65 | 'tag' => 'input', 66 | 'type' => 'date', 67 | 'id' => $id, 68 | 'name' => $this->name, 69 | 'value' => htmlspecialchars($this->getValues()), 70 | 'attributes' => $this->attributes + ['size' => $this->size], 71 | ]); 72 | } 73 | 74 | /** 75 | * {@inheritdoc} 76 | * 77 | * @return boolean this is a value 78 | */ 79 | public function isAValue(): bool 80 | { 81 | return true; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/classes/fields/Datepicker.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\PHPFormsApi\Form; 19 | 20 | /** 21 | * The datepicker text input field class 22 | */ 23 | class Datepicker extends Textfield 24 | { 25 | /** 26 | * date format 27 | * 28 | * @var string 29 | */ 30 | protected $date_format = 'yy-mm-dd'; 31 | 32 | /** 33 | * change month flag 34 | * 35 | * @var boolean 36 | */ 37 | protected $change_month = false; 38 | 39 | /** 40 | * change year flag 41 | * 42 | * @var boolean 43 | */ 44 | protected $change_year = false; 45 | 46 | /** 47 | * min date 48 | * 49 | * @var string 50 | */ 51 | protected $mindate = '-10Y'; 52 | 53 | /** 54 | * max date 55 | * 56 | * @var string 57 | */ 58 | protected $maxdate = '+10Y'; 59 | 60 | /** 61 | * year range 62 | * 63 | * @var string 64 | */ 65 | protected $yearrange = '-10:+10'; 66 | 67 | /** 68 | * disabled dates array 69 | * 70 | * @var array 71 | */ 72 | protected $disabled_dates = []; // an array of date strings compliant to $date_format 73 | 74 | /** 75 | * {@inheritdoc} 76 | * 77 | * @param Form $form form object 78 | */ 79 | public function preRender(Form $form) 80 | { 81 | if ($this->pre_rendered == true) { 82 | return; 83 | } 84 | $id = $this->getHtmlId(); 85 | 86 | $changeMonth = ($this->change_month) ? 'true' :'false'; 87 | $changeYear = ($this->change_year == true) ? 'true' :'false'; 88 | 89 | $this->addJs( 90 | ((count($this->disabled_dates)>0) ? 91 | "var disabled_dates_array_{$form->getId()}_{$id} = ". 92 | json_encode((array) $this->disabled_dates).";": 93 | "" 94 | ). 95 | "\$('#{$id}','#{$form->getId()}').datepicker({ 96 | dateFormat: '{$this->date_format}', 97 | ".((count($this->disabled_dates)>0) ? "beforeShowDay: function(date){ 98 | var string = $.datepicker.formatDate('{$this->date_format}', date); 99 | return [ disabled_dates_array_{$form->getId()}_{$id}.indexOf(string) == -1 ]; 100 | },": "")." 101 | changeMonth: {$changeMonth}, 102 | changeYear: {$changeYear}, 103 | minDate: \"{$this->mindate}\", 104 | maxDate: \"{$this->maxdate}\", 105 | yearRange: \"{$this->yearrange}\" 106 | });" 107 | ); 108 | 109 | parent::preRender($form); 110 | } 111 | 112 | /** 113 | * {@inheritdoc} 114 | * 115 | * @return boolean this is a value 116 | */ 117 | public function isAValue() : bool 118 | { 119 | return true; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/classes/fields/Datetime.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\Basics\Traits\ToolsTrait as BasicToolsTrait; 19 | use Degami\PHPFormsApi\Abstracts\Base\Field; 20 | use Degami\PHPFormsApi\Abstracts\Base\FieldsContainer; 21 | use Degami\PHPFormsApi\Form; 22 | use Degami\PHPFormsApi\Abstracts\Fields\ComposedField; 23 | 24 | /** 25 | * The datetime group field class 26 | */ 27 | class Datetime extends ComposedField 28 | { 29 | use BasicToolsTrait; 30 | 31 | /** 32 | * date sub element 33 | * 34 | * @var Date 35 | */ 36 | protected $date = null; 37 | 38 | /** 39 | * time sub_element 40 | * 41 | * @var Time 42 | */ 43 | protected $time = null; 44 | 45 | /** 46 | * "use js selects" flag 47 | * 48 | * @var boolean 49 | */ 50 | protected $js_selects = false; 51 | 52 | /** 53 | * Class constructor 54 | * 55 | * @param array $options build options 56 | * @param ?string $name field name 57 | */ 58 | public function __construct(array $options = [], ?string $name = null) 59 | { 60 | parent::__construct($options, $name); 61 | 62 | unset($options['title']); 63 | $options['container_tag'] = ''; 64 | 65 | $options['type'] = 'date'; 66 | $this->date = new Date($options, $this->getSubfieldName('date')); 67 | 68 | $options['type'] = 'time'; 69 | $this->time = new Time($options, $this->getSubfieldName('time')); 70 | } 71 | 72 | /** 73 | * {@inheritdoc} 74 | * 75 | * @param Form $form form object 76 | */ 77 | public function preRender(Form $form) 78 | { 79 | if ($this->pre_rendered == true) { 80 | return; 81 | } 82 | $id = $this->getHtmlId(); 83 | $this->addCss("#{$id} div.date,#{$id} div.time{display: inline-block;margin-right: 5px;}"); 84 | 85 | $this->date->preRender($form); 86 | $this->time->preRender($form); 87 | 88 | foreach ($this->date->getJs() as $date_js_line) { 89 | if (!empty($date_js_line)) { 90 | $this->addJs($date_js_line); 91 | } 92 | } 93 | 94 | foreach ($this->time->getJs() as $time_js_line) { 95 | if (!empty($time_js_line)) { 96 | $this->addJs($time_js_line); 97 | } 98 | } 99 | 100 | parent::preRender($form); 101 | } 102 | 103 | /** 104 | * {@inheritdoc} . it simply calls the sub elements preprocess 105 | * 106 | * @param string $process_type preprocess type 107 | */ 108 | public function preProcess($process_type = "preprocess") 109 | { 110 | $this->date->preProcess($process_type); 111 | $this->time->preProcess($process_type); 112 | } 113 | 114 | /** 115 | * {@inheritdoc} . it simply calls the sub elements process 116 | * 117 | * @param mixed $values value to set 118 | */ 119 | public function processValue($values) 120 | { 121 | $this->processSubfieldsValues($values, $this->date, 'date'); 122 | $this->processSubfieldsValues($values, $this->time, 'time'); 123 | } 124 | 125 | /** 126 | * {@inheritdoc} 127 | * 128 | * @return boolean TRUE if element is valid 129 | */ 130 | public function isValid() : bool 131 | { 132 | return $this->date->isValid() && $this->time->isValid(); 133 | } 134 | 135 | /** 136 | * renders form errors 137 | * 138 | * @return string errors as an html
  • list 139 | */ 140 | public function showErrors() : string 141 | { 142 | $out = trim($this->date->showErrors() . $this->time->showErrors()); 143 | return ($out == '') ? '' : $out; 144 | } 145 | 146 | /** 147 | * resets the sub elements 148 | */ 149 | public function resetField(): Field 150 | { 151 | $this->date->resetField(); 152 | $this->time->resetField(); 153 | 154 | return $this; 155 | } 156 | 157 | /** 158 | * Return field value 159 | * 160 | * @return mixed field value 161 | */ 162 | public function getValues() 163 | { 164 | return [ 165 | 'date'=> $this->date->getValues(), 166 | 'time'=> $this->time->getValues(), 167 | 'datetime' => $this->date->getValues().' '.$this->time->getValues(), 168 | ]; 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /src/classes/fields/Datetimeselect.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\PHPFormsApi\Abstracts\Base\Field; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\PHPFormsApi\Abstracts\Fields\ComposedField; 21 | 22 | /** 23 | * The datetime select group field class 24 | */ 25 | class Datetimeselect extends ComposedField 26 | { 27 | /** 28 | * date sub element 29 | * 30 | * @var Date 31 | */ 32 | protected $date = null; 33 | 34 | /** 35 | * time sub_element 36 | * 37 | * @var Time 38 | */ 39 | protected $time = null; 40 | 41 | /** 42 | * "use js selects" flag 43 | * 44 | * @var boolean 45 | */ 46 | protected $js_selects = false; 47 | 48 | /** 49 | * Class constructor 50 | * 51 | * @param array $options build options 52 | * @param ?string $name field name 53 | */ 54 | public function __construct(array $options = [], ?string $name = null) 55 | { 56 | parent::__construct($options, $name); 57 | 58 | unset($options['title']); 59 | $options['container_tag'] = ''; 60 | 61 | $options['type'] = 'dateselect'; 62 | $this->date = new Dateselect($options, $this->getSubfieldName('date')); 63 | 64 | $options['type'] = 'timeselect'; 65 | $this->time = new Timeselect($options, $this->getSubfieldName('time')); 66 | } 67 | 68 | /** 69 | * {@inheritdoc} 70 | * 71 | * @param Form $form form object 72 | */ 73 | public function preRender(Form $form) 74 | { 75 | if ($this->pre_rendered == true) { 76 | return; 77 | } 78 | $id = $this->getHtmlId(); 79 | $this->addCss("#{$id} div.date,#{$id} div.time{display: inline-block;margin-right: 5px;}"); 80 | 81 | $this->date->preRender($form); 82 | $this->time->preRender($form); 83 | 84 | foreach ($this->date->getJs() as $date_js_line) { 85 | if (!empty($date_js_line)) { 86 | $this->addJs($date_js_line); 87 | } 88 | } 89 | 90 | foreach ($this->time->getJs() as $time_js_line) { 91 | if (!empty($time_js_line)) { 92 | $this->addJs($time_js_line); 93 | } 94 | } 95 | 96 | parent::preRender($form); 97 | } 98 | 99 | /** 100 | * {@inheritdoc} . it simply calls the sub elements preprocess 101 | * 102 | * @param string $process_type preprocess type 103 | */ 104 | public function preProcess($process_type = "preprocess") 105 | { 106 | $this->date->preProcess($process_type); 107 | $this->time->preProcess($process_type); 108 | } 109 | 110 | /** 111 | * {@inheritdoc} . it simply calls the sub elements process 112 | * 113 | * @param array $values value to set 114 | */ 115 | public function processValue($values) 116 | { 117 | $this->processSubfieldsValues($values, $this->date, 'date'); 118 | $this->processSubfieldsValues($values, $this->time, 'time'); 119 | } 120 | 121 | /** 122 | * {@inheritdoc} 123 | * 124 | * @return boolean TRUE if element is valid 125 | */ 126 | public function isValid() : bool 127 | { 128 | return $this->date->isValid() && $this->time->isValid(); 129 | } 130 | 131 | /** 132 | * renders form errors 133 | * 134 | * @return string errors as an html
  • list 135 | */ 136 | public function showErrors() : string 137 | { 138 | $out = trim($this->date->showErrors() . $this->time->showErrors()); 139 | return ($out == '') ? '' : $out; 140 | } 141 | 142 | /** 143 | * resets the sub elements 144 | */ 145 | public function resetField() : Field 146 | { 147 | $this->date->resetField(); 148 | $this->time->resetField(); 149 | 150 | return $this; 151 | } 152 | 153 | /** 154 | * Return field value 155 | * 156 | * @return mixed field value 157 | */ 158 | public function getValues() 159 | { 160 | return [ 161 | 'date'=> $this->date->getValues(), 162 | 'time'=> $this->time->getValues(), 163 | 'datetime' => $this->date->valueString().' '.$this->time->valueString(), 164 | ]; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/classes/fields/Email.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\PHPFormsApi\Form; 19 | use Degami\PHPFormsApi\Abstracts\Base\Field; 20 | use Degami\Basics\Html\TagElement; 21 | 22 | /** 23 | * The email input field class 24 | */ 25 | class Email extends Field 26 | { 27 | /** 28 | * Class constructor 29 | * 30 | * @param array $options build options 31 | * @param ?string $name field name 32 | */ 33 | public function __construct(array $options = [], ?string $name = null) 34 | { 35 | parent::__construct($options, $name); 36 | 37 | // ensure is email validator is present 38 | $this->getValidate()->addElement('email'); 39 | } 40 | 41 | /** 42 | * {@inheritdoc} 43 | * 44 | * @param Form $form form object 45 | * 46 | * @return string the element html 47 | */ 48 | public function renderField(Form $form) 49 | { 50 | $id = $this->getHtmlId(); 51 | 52 | if (!isset($this->attributes['class'])) { 53 | $this->attributes['class'] = ''; 54 | } 55 | if ($this->hasErrors()) { 56 | $this->attributes['class'] .= ' has-errors'; 57 | } 58 | if ($this->disabled == true) { 59 | $this->attributes['disabled']='disabled'; 60 | } 61 | 62 | $tag = new TagElement([ 63 | 'tag' => 'input', 64 | 'type' => 'email', 65 | 'id' => $id, 66 | 'name' => $this->name, 67 | 'value' => $this->getValues(), 68 | 'attributes' => $this->attributes + ['size' => $this->size], 69 | ]); 70 | return $tag; 71 | } 72 | 73 | /** 74 | * {@inheritdoc} 75 | * 76 | * @return boolean this is a value 77 | */ 78 | public function isAValue() : bool 79 | { 80 | return true; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/classes/fields/Geolocation.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\PHPFormsApi\Abstracts\Base\Field; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\PHPFormsApi\Abstracts\Fields\ComposedField; 21 | 22 | /** 23 | * The geolocation field class 24 | */ 25 | class Geolocation extends ComposedField 26 | { 27 | 28 | /** 29 | * latitude 30 | * 31 | * @var float 32 | */ 33 | protected $latitude; 34 | 35 | /** 36 | * longitude 37 | * 38 | * @var float 39 | */ 40 | protected $longitude; 41 | 42 | /** 43 | * Class constructor 44 | * 45 | * @param array $options build options 46 | * @param ?string $name field name 47 | */ 48 | public function __construct(array $options = [], ?string $name = null) 49 | { 50 | parent::__construct($options, $name); 51 | 52 | $defaults = isset($options['default_value']) ? $options['default_value'] : ['latitude' => 0, 'longitude' => 0]; 53 | 54 | unset($options['title']); 55 | unset($options['prefix']); 56 | unset($options['suffix']); 57 | $options['container_tag'] = ''; 58 | 59 | if (!isset($options['size'])) { 60 | $options['size'] = 5; 61 | } 62 | 63 | $options['type'] = 'textfield'; 64 | $options['suffix'] = $this->getText('latitude').' '; 65 | $options['default_value'] = (is_array($defaults) && isset($defaults['latitude'])) ? $defaults['latitude'] : 0; 66 | $this->latitude = new Textfield($options, $this->getSubfieldName('latitude')); 67 | 68 | $options['type'] = 'textfield'; 69 | $options['suffix'] = $this->getText('longitude').' '; 70 | $options['default_value'] = (is_array($defaults) && isset($defaults['longitude'])) ? $defaults['longitude'] : 0; 71 | $this->longitude = new Textfield($options, $this->getSubfieldName('longitude')); 72 | } 73 | 74 | /** 75 | * {@inheritdoc} 76 | * 77 | * @param Form $form form object 78 | */ 79 | public function preRender(Form $form) 80 | { 81 | if ($this->pre_rendered == true) { 82 | return; 83 | } 84 | parent::preRender($form); 85 | 86 | $this->latitude->preRender($form); 87 | $this->longitude->preRender($form); 88 | } 89 | 90 | /** 91 | * {@inheritdoc} . it simply calls the sub elements preprocess 92 | * 93 | * @param string $process_type preprocess type 94 | */ 95 | public function preProcess($process_type = "preprocess") 96 | { 97 | $this->latitude->preProcess($process_type); 98 | $this->longitude->preProcess($process_type); 99 | } 100 | 101 | /** 102 | * {@inheritdoc} . it simply calls the sub elements process 103 | * 104 | * @param mixed $values value to set 105 | */ 106 | public function processValue($values) 107 | { 108 | $this->processSubfieldsValues($values, $this->latitude, 'latitude'); 109 | $this->processSubfieldsValues($values, $this->longitude, 'longitude'); 110 | } 111 | 112 | /** 113 | * {@inheritdoc} 114 | * 115 | * @return boolean TRUE if element is valid 116 | */ 117 | public function isValid() : bool 118 | { 119 | return $this->latitude->isValid() && $this->longitude->isValid(); 120 | } 121 | 122 | 123 | /** 124 | * renders form errors 125 | * 126 | * @return string errors as an html
  • list 127 | */ 128 | public function showErrors() : string 129 | { 130 | $out = trim($this->latitude->showErrors() . $this->longitude->showErrors()); 131 | return ($out == '') ? '' : $out; 132 | } 133 | 134 | 135 | /** 136 | * resets the sub elements 137 | */ 138 | public function resetField() : Field 139 | { 140 | $this->latitude->resetField(); 141 | $this->longitude->resetField(); 142 | 143 | return $this; 144 | } 145 | 146 | /** 147 | * Return field value 148 | * 149 | * @return mixed field value 150 | */ 151 | public function getValues() 152 | { 153 | return [ 154 | 'latitude'=> $this->latitude->getValues(), 155 | 'longitude'=> $this->longitude->getValues(), 156 | ]; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/classes/fields/Hidden.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\PHPFormsApi\Form; 19 | use Degami\PHPFormsApi\Abstracts\Base\Field; 20 | use Degami\Basics\Html\TagElement; 21 | 22 | /** 23 | * The hidden input field class 24 | */ 25 | class Hidden extends Field 26 | { 27 | /** 28 | * Class constructor 29 | * 30 | * @param array $options build options 31 | * @param ?string $name field name 32 | */ 33 | public function __construct(array $options = [], ?string $name = null) 34 | { 35 | $this->container_tag = ''; 36 | $this->container_class = ''; 37 | parent::__construct($options, $name); 38 | } 39 | 40 | /** 41 | * {@inheritdoc} 42 | * 43 | * @param Form $form form object 44 | * 45 | * @return string the element html 46 | */ 47 | public function renderField(Form $form) 48 | { 49 | $id = $this->getHtmlId(); 50 | 51 | $tag = new TagElement([ 52 | 'tag' => 'input', 53 | 'type' => 'hidden', 54 | 'id' => $id, 55 | 'name' => $this->name, 56 | 'value' => $this->getValues(), 57 | 'attributes' => $this->attributes, 58 | ]); 59 | return $tag; 60 | } 61 | 62 | /** 63 | * {@inheritdoc} 64 | * 65 | * @return boolean this is a value 66 | */ 67 | public function isAValue() : bool 68 | { 69 | return true; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/classes/fields/ImageButton.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\Basics\Html\BaseElement; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\Basics\Html\TagElement; 21 | use Degami\PHPFormsApi\Abstracts\Fields\Clickable; 22 | 23 | /** 24 | * The image submit input type field class 25 | */ 26 | class ImageButton extends Clickable 27 | { 28 | /** 29 | * image source 30 | * 31 | * @var string 32 | */ 33 | protected $src; 34 | 35 | /** 36 | * image alternate 37 | * 38 | * @var string 39 | */ 40 | protected $alt; 41 | 42 | /** 43 | * Class constructor 44 | * 45 | * @param array $options build options 46 | * @param ?string $name field name 47 | */ 48 | public function __construct(array $options = [], ?string $name = null) 49 | { 50 | $this->default_value = [ 51 | 'x'=>-1, 52 | 'y'=>-1, 53 | ]; 54 | 55 | parent::__construct($options, $name); 56 | } 57 | 58 | /** 59 | * {@inheritdoc} 60 | * 61 | * @param Form $form form object 62 | * 63 | * @return string|BaseElement the element html 64 | */ 65 | public function renderField(Form $form) 66 | { 67 | $id = $this->getHtmlId(); 68 | if ($this->disabled == true) { 69 | $this->attributes['disabled']='disabled'; 70 | } 71 | 72 | $tag = new TagElement([ 73 | 'tag' => 'input', 74 | 'type' => 'image', 75 | 'id' => $id, 76 | 'name' => $this->name, 77 | 'value_needed' => false, 78 | 'attributes' => $this->attributes + ['src' => $this->src, 'alt' => $this->alt], 79 | ]); 80 | return $tag; 81 | } 82 | 83 | /** 84 | * {@inheritdoc} 85 | * 86 | * @param array $request request array 87 | */ 88 | public function alterRequest(array &$request) 89 | { 90 | foreach ($request as $key => $val) { 91 | //IMAGE BUTTONS HANDLE 92 | if (preg_match('/^(.*?)_(x|y)$/', $key, $matches) && $this->getName() == $matches[1]) { 93 | //assume this is an input type="image" 94 | if (isset($request[$matches[1].'_'.(($matches[2] == 'x')?'y':'x')])) { 95 | $request[$matches[1]] = [ 96 | 'x'=>$request[$matches[1].'_x'], 97 | 'y'=>$request[$matches[1].'_y'], 98 | ]; 99 | 100 | unset($request[$matches[1].'_x']); 101 | unset($request[$matches[1].'_y']); 102 | } 103 | } 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/classes/fields/Markup.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\Basics\Html\BaseElement; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\PHPFormsApi\Abstracts\Base\Field; 21 | 22 | /** 23 | * The markup field class. 24 | * this is not a value 25 | */ 26 | class Markup extends Field 27 | { 28 | /** 29 | * Class constructor 30 | * 31 | * @param array $options build options 32 | * @param ?string $name field name 33 | */ 34 | public function __construct(array $options = [], ?string $name = null) 35 | { 36 | parent::__construct($options, $name); 37 | if (isset($options['value'])) { 38 | $this->value = $options['value']; 39 | } 40 | } 41 | 42 | /** 43 | * {@inheritdoc} 44 | * 45 | * @param Form $form form object 46 | * 47 | * @return string|BaseElement the element value 48 | */ 49 | public function renderField(Form $form) 50 | { 51 | return $this->getValues(); 52 | } 53 | 54 | /** 55 | * validate function 56 | * 57 | * @return bool this field is always valid 58 | */ 59 | public function isValid() : bool 60 | { 61 | return true; 62 | } 63 | 64 | /** 65 | * {@inheritdoc} 66 | * 67 | * @return bool this is not a value 68 | */ 69 | public function isAValue() : bool 70 | { 71 | return false; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/classes/fields/Maskedfield.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\PHPFormsApi\Form; 19 | 20 | /** 21 | * The "masked" text input field class 22 | */ 23 | class Maskedfield extends Textfield 24 | { 25 | /** 26 | * input mask string 27 | * 28 | * @var string 29 | */ 30 | protected $mask; 31 | 32 | /** 33 | * jQuery Mask Plugin patterns 34 | * 35 | * @var array 36 | */ 37 | private $translation = [ 38 | '0' => "\d", 39 | '9' => "\d?", 40 | '#' => "\d+", 41 | 'A' => "[a-zA-Z0-9]", 42 | 'S' => "[a-zA-Z]", 43 | ]; 44 | 45 | /** 46 | * Class constructor 47 | * 48 | * @param array $options build options 49 | * @param ?string $name field name 50 | */ 51 | public function __construct(array $options, ?string $name = null) 52 | { 53 | if (!isset($options['attributes']['class'])) { 54 | $options['attributes']['class'] = ''; 55 | } 56 | $options['attributes']['class'].=' maskedfield'; 57 | 58 | parent::__construct($options, $name); 59 | } 60 | 61 | /** 62 | * {@inheritdoc} 63 | * 64 | * @param Form $form form object 65 | */ 66 | public function preRender(Form $form) 67 | { 68 | if ($this->pre_rendered == true) { 69 | return; 70 | } 71 | $id = $this->getHtmlId(); 72 | $this->addJs("\$('#{$id}','#{$form->getId()}').mask('{$this->mask}');"); 73 | parent::preRender($form); 74 | } 75 | 76 | /** 77 | * {@inheritdoc} 78 | * 79 | * @return boolean this TRUE if this element conforms to mask 80 | */ 81 | public function isValid() : bool 82 | { 83 | $mask = $this->mask; 84 | $mask = preg_replace("(\[|\]|\(|\))", "\\\1", $mask); 85 | foreach ($this->translation as $search => $replace) { 86 | $mask = str_replace($search, $replace, $mask); 87 | } 88 | $mask = '/^'.$mask.'$/'; 89 | if (!preg_match($mask, $this->value)) { 90 | $this->addError($this->getText("Value does not conform to mask"), __FUNCTION__); 91 | 92 | if ($this->stop_on_first_error) { 93 | return false; 94 | } 95 | } 96 | 97 | return parent::isValid(); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/classes/fields/Number.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\Basics\Html\BaseElement; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\PHPFormsApi\Abstracts\Base\Field; 21 | use Degami\Basics\Html\TagElement; 22 | 23 | /** 24 | * The number input field class 25 | */ 26 | class Number extends Field 27 | { 28 | /** 29 | * minimum value 30 | * 31 | * @var null 32 | */ 33 | protected $min = null; 34 | 35 | /** 36 | * maximum value 37 | * 38 | * @var null 39 | */ 40 | protected $max = null; 41 | 42 | /** 43 | * step value 44 | * 45 | * @var integer 46 | */ 47 | protected $step = 1; 48 | 49 | /** 50 | * Class constructor 51 | * 52 | * @param array $options build options 53 | * @param string $name field name 54 | */ 55 | public function __construct($options = [], $name = null) 56 | { 57 | parent::__construct($options, $name); 58 | 59 | // ensure is numeric validator is present 60 | $this->getValidate()->addElement('numeric'); 61 | } 62 | 63 | /** 64 | * {@inheritdoc} 65 | * 66 | * @param Form $form form object 67 | * @return string|BaseElement the element html 68 | */ 69 | public function renderField(Form $form) 70 | { 71 | $id = $this->getHtmlId(); 72 | 73 | if (!isset($this->attributes['class'])) { 74 | $this->attributes['class'] = ''; 75 | } 76 | if ($this->hasErrors()) { 77 | $this->attributes['class'] .= ' has-errors'; 78 | } 79 | if ($this->disabled == true) { 80 | $this->attributes['disabled']='disabled'; 81 | } 82 | 83 | $this->attributes['size'] = $this->size; 84 | if (is_numeric($this->min) && is_numeric($this->max) && $this->max >= $this->min) { 85 | $this->attributes += [ 86 | 'size' => $this->size, 87 | 'min' => $this->min, 88 | 'max' => $this->max, 89 | 'step' => $this->step 90 | ]; 91 | } 92 | 93 | $tag = new TagElement([ 94 | 'tag' => 'input', 95 | 'type' => 'number', 96 | 'id' => $id, 97 | 'name' => $this->name, 98 | 'value' => $this->getValues(), 99 | 'attributes' => $this->attributes, 100 | ]); 101 | return $tag; 102 | } 103 | 104 | /** 105 | * {@inheritdoc} 106 | * 107 | * @return boolean this is a value 108 | */ 109 | public function isAValue() : bool 110 | { 111 | return true; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/classes/fields/Optgroup.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\Basics\Html\BaseElement; 19 | use Degami\PHPFormsApi\Abstracts\Base\Element; 20 | use Degami\PHPFormsApi\Abstracts\Fields\Optionable; 21 | use Degami\Basics\Html\TagElement; 22 | use Degami\PHPFormsApi\Abstracts\Fields\FieldMultivalues; 23 | 24 | /** 25 | * The optgroup element class 26 | */ 27 | class Optgroup extends Optionable 28 | { 29 | /** 30 | * options array 31 | * 32 | * @var array 33 | */ 34 | protected $options; 35 | 36 | /** 37 | * Class constructor 38 | * 39 | * @param string $label label 40 | * @param array $options options array 41 | */ 42 | public function __construct(string $label, array $options) 43 | { 44 | if (isset($options['options'])) { 45 | foreach ($options['options'] as $key => $value) { 46 | if ($value instanceof Option) { 47 | $this->addOption($value); 48 | $value->setParent($this); 49 | } elseif (is_scalar($key) && is_scalar($value)) { 50 | $this->addOption(new Option($key, $value)); 51 | } 52 | } 53 | unset($options['options']); 54 | } 55 | parent::__construct($label, $options); 56 | } 57 | 58 | /** 59 | * Check if key is present into element options array 60 | * 61 | * @param mixed $needle element to find 62 | * @return boolean TRUE if element is present 63 | */ 64 | public function optionsHasKey($needle): bool 65 | { 66 | return FieldMultivalues::hasKey($needle, $this->options); 67 | } 68 | 69 | /** 70 | * Add option 71 | * 72 | * @param Option $option option to add 73 | * @return Optgroup 74 | */ 75 | public function addOption(Option $option): Optgroup 76 | { 77 | $option->setParent($this); 78 | $this->options[] = $option; 79 | 80 | return $this; 81 | } 82 | 83 | /** 84 | * render the optgroup 85 | * 86 | * @param Select $form_field select field 87 | * @return TagElement the optgroup html 88 | */ 89 | public function renderHTML(Select $form_field): TagElement 90 | { 91 | $this->no_translation = $form_field->no_translation; 92 | $tag = new TagElement([ 93 | 'tag' => 'optgroup', 94 | 'type' => null, 95 | 'id' => null, 96 | 'attributes' => $this->attributes + [ 'label' => $this->label ], 97 | 'value_needed' => false, 98 | 'has_close' => true, 99 | ]); 100 | foreach ($this->options as $option) { 101 | $tag->addChild($option->renderHTML($form_field)); 102 | } 103 | return $tag; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/classes/fields/Option.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\PHPFormsApi\Abstracts\Base\Element; 19 | use Degami\PHPFormsApi\Abstracts\Fields\Optionable; 20 | use Degami\Basics\Html\TagElement; 21 | 22 | /** 23 | * The option element class 24 | */ 25 | class Option extends Optionable 26 | { 27 | /** 28 | * option key 29 | * 30 | * @var string 31 | */ 32 | protected $key; 33 | 34 | /** 35 | * Class constructor 36 | * 37 | * @param string $key key 38 | * @param string $label label 39 | * @param array $options build options 40 | */ 41 | public function __construct(string $key, string $label, $options = []) 42 | { 43 | $this->setKey(trim($key)); 44 | parent::__construct($label, $options); 45 | } 46 | 47 | /** 48 | * render the option 49 | * 50 | * @param Select $form_field select field 51 | * 52 | * @return TagElement the option html 53 | */ 54 | public function renderHTML(Select $form_field): TagElement 55 | { 56 | $this->no_translation = $form_field->no_translation; 57 | $field_value = $form_field->getValue(); 58 | 59 | if (is_array($field_value) || $form_field->isMultiple() == true) { 60 | if (!is_array($field_value)) { 61 | $field_value = [$field_value]; 62 | } 63 | if (in_array($this->key, array_values($field_value), true)) { 64 | $this->attributes['selected'] = 'selected'; 65 | } 66 | } else { 67 | if ($this->key === $field_value) { 68 | $this->attributes['selected'] = 'selected'; 69 | } 70 | } 71 | $tag = new TagElement([ 72 | 'tag' => 'option', 73 | 'type' => null, 74 | 'value' => $this->key, 75 | 'text' => $this->getText($this->label), 76 | 'attributes' => $this->attributes + ['class' => false], 77 | 'has_close' => true, 78 | ]); 79 | return $tag; 80 | } 81 | 82 | /** 83 | * Get the element key 84 | * 85 | * @return mixed the element key 86 | */ 87 | public function getKey() 88 | { 89 | return $this->key; 90 | } 91 | 92 | /** 93 | * Set the element key 94 | * 95 | * @param mixed $key element key 96 | * @return Option 97 | */ 98 | public function setKey($key) 99 | { 100 | $this->key = $key; 101 | 102 | return $this; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/classes/fields/Progressbar.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\Basics\Html\BaseElement; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\PHPFormsApi\Abstracts\Base\Field; 21 | use Degami\Basics\Html\TagElement; 22 | 23 | /** 24 | * The progressbar field class 25 | */ 26 | class Progressbar extends Markup 27 | { 28 | 29 | /** 30 | * "indeterminate progressbar" flag 31 | * 32 | * @var boolean 33 | */ 34 | protected $indeterminate = false; 35 | 36 | /** 37 | * "show label" flag 38 | * 39 | * @var boolean 40 | */ 41 | protected $show_label = false; 42 | 43 | /** 44 | * {@inheritdoc} 45 | * 46 | * @param Form $form form object 47 | */ 48 | public function preRender(Form $form) 49 | { 50 | if ($this->pre_rendered == true) { 51 | return; 52 | } 53 | $id = $this->getHtmlId(); 54 | if ($this->indeterminate == true || !is_numeric($this->getValues())) { 55 | $this->addJs("\$('#{$id}','#{$form->getId()}').progressbar({ value: false });"); 56 | } elseif ($this->show_label == true) { 57 | $this->addJs( 58 | " 59 | \$('#{$id}','#{$form->getId()}').progressbar({ value: parseInt(" . $this->getValues() . ") }); 60 | \$('#{$id} .progress-label','#{$form->getId()}').text('" . $this->getValues() . "%'); 61 | " 62 | ); 63 | } else { 64 | $this->addJs("\$('#{$id}','#{$form->getId()}').progressbar({ value: parseInt(" . $this->getValues() . ") });"); 65 | } 66 | 67 | parent::preRender($form); 68 | } 69 | 70 | /** 71 | * {@inheritdoc} 72 | * 73 | * @param Form $form form object 74 | * 75 | * @return string|BaseElement the element html 76 | */ 77 | public function renderField(Form $form) 78 | { 79 | $id = $this->getHtmlId(); 80 | 81 | if ($this->show_label == true) { 82 | $this->addCss("#{$form->getId()} #{$id}.ui-progressbar {position: relative;}"); 83 | $this->addCss("#{$form->getId()} #{$id} .progress-label {position: absolute;left: 50%;top: 4px;}"); 84 | } 85 | 86 | $tag = new TagElement([ 87 | 'tag' => 'div', 88 | 'type' => null, 89 | 'id' => $id, 90 | 'text' => null, 91 | 'attributes' => $this->attributes, 92 | 'has_close' => true, 93 | ]); 94 | 95 | if ($this->show_label == true) { 96 | $tag->addChild(new TagElement([ 97 | 'tag' => 'div', 98 | 'type' => null, 99 | 'id' => null, 100 | 'text' => null, 101 | 'attributes' => ['class' => 'progress-label'], 102 | 'has_close' => true, 103 | ])); 104 | } 105 | return $tag; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/classes/fields/Radios.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\Basics\Html\BaseElement; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\Basics\Html\TagElement; 21 | use Degami\PHPFormsApi\Abstracts\Fields\FieldMultivalues; 22 | 23 | /** 24 | * The radios group field class 25 | */ 26 | class Radios extends FieldMultivalues 27 | { 28 | /** 29 | * {@inheritdoc} 30 | * 31 | * @param Form $form form object 32 | * 33 | * @return string|BaseElement the element html 34 | */ 35 | public function renderField(Form $form) 36 | { 37 | $id = $this->getHtmlId(); 38 | $tag = new TagElement([ 39 | 'tag' => 'div', 40 | 'attributes' => ['class' => 'options'], 41 | ]); 42 | 43 | if ($this->disabled == true) { 44 | $this->attributes['disabled'] = 'disabled'; 45 | } 46 | 47 | foreach ($this->options as $key => $value) { 48 | if (is_array($value) && isset($value['attributes'])) { 49 | $attributes = $value['attributes']; 50 | } else { 51 | $attributes = []; 52 | } 53 | 54 | if (is_array($value)) { 55 | $value = $value['value']; 56 | } 57 | 58 | $tag_label = new TagElement([ 59 | 'tag' => 'label', 60 | 'attributes' => ['for' => "{$id}-{$key}", 'class' => "label-radio"], 61 | ]); 62 | $tag_label->addChild(new TagElement([ 63 | 'tag' => 'input', 64 | 'type' => 'radio', 65 | 'id' => "{$id}-{$key}", 66 | 'name' => $this->name, 67 | 'value' => $key, 68 | 'attributes' => array_merge($attributes, ($this->getValues() == $key) ? ['checked' => 'checked'] : []), 69 | 'text' => $value, 70 | ])); 71 | $tag->addChild($tag_label); 72 | } 73 | return $tag; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/classes/fields/Range.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\Basics\Html\BaseElement; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\Basics\Html\TagElement; 21 | 22 | /** 23 | * The range input field class 24 | */ 25 | class Range extends Number 26 | { 27 | 28 | /** 29 | * {@inheritdoc} 30 | * 31 | * @param Form $form form object 32 | * 33 | * @return string|BaseElement the element html 34 | */ 35 | public function renderField(Form $form) 36 | { 37 | $id = $this->getHtmlId(); 38 | 39 | if (!isset($this->attributes['class'])) { 40 | $this->attributes['class'] = ''; 41 | } 42 | if ($this->hasErrors()) { 43 | $this->attributes['class'] .= ' has-errors'; 44 | } 45 | if ($this->disabled == true) { 46 | $this->attributes['disabled']='disabled'; 47 | } 48 | 49 | $this->attributes['size'] = $this->size; 50 | if (is_numeric($this->min) && is_numeric($this->max) && $this->max >= $this->min) { 51 | $this->attributes += [ 52 | 'size' => $this->size, 53 | 'min' => $this->min, 54 | 'max' => $this->max, 55 | 'step' => $this->step 56 | ]; 57 | } 58 | 59 | return new TagElement([ 60 | 'tag' => 'input', 61 | 'type' => 'range', 62 | 'id' => $id, 63 | 'name' => $this->name, 64 | 'value' => $this->getValues(), 65 | 'attributes' => $this->attributes, 66 | ]); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/classes/fields/Recaptcha.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\Basics\Html\BaseElement; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\PHPFormsApi\Abstracts\Fields\Captcha; 21 | 22 | /** 23 | * The recaptcha field class 24 | */ 25 | class Recaptcha extends Captcha 26 | { 27 | 28 | /** 29 | * public key 30 | * 31 | * @var string 32 | */ 33 | protected $publickey = ''; 34 | 35 | /** 36 | * private key 37 | * 38 | * @var string 39 | */ 40 | protected $privatekey = ''; 41 | 42 | 43 | /** 44 | * {@inheritdoc} 45 | * 46 | * @param Form $form form object 47 | * 48 | * @return string|BaseElement the element html 49 | */ 50 | public function renderField(Form $form) 51 | { 52 | if (!function_exists('recaptcha_get_html')) { 53 | return ''; 54 | } 55 | return recaptcha_get_html($this->publickey); 56 | } 57 | 58 | /** 59 | * {@inheritdoc} 60 | * 61 | * @return boolean TRUE if element is valid 62 | */ 63 | public function isValid() : bool 64 | { 65 | if ($this->already_validated == true) { 66 | return true; 67 | } 68 | if (isset($this->value['already_validated']) && $this->value['already_validated'] == true) { 69 | return true; 70 | } 71 | if (!function_exists('recaptcha_check_answer')) { 72 | $this->already_validated = true; 73 | return true; 74 | } 75 | 76 | if (!is_array($this->value)) { 77 | $this->value = []; 78 | } 79 | 80 | // if something is missing... 81 | $this->value += [ 82 | 'challenge_field' => '', 83 | 'response_field' => '', 84 | ]; 85 | 86 | $resp = recaptcha_check_answer( 87 | $this->privatekey, 88 | $_SERVER["REMOTE_ADDR"], 89 | $this->value["challenge_field"], 90 | $this->value["response_field"] 91 | ); 92 | if (!$resp->is_valid) { 93 | $this->addError($this->getText("Recaptcha response is not valid"), __FUNCTION__); 94 | } else { 95 | $this->already_validated = true; 96 | $this->value['already_validated'] = true; 97 | } 98 | 99 | return $resp->is_valid; 100 | } 101 | 102 | /** 103 | * {@inheritdoc} 104 | * 105 | * @param array $request request array 106 | */ 107 | public function alterRequest(array &$request) 108 | { 109 | foreach ($request as $key => $val) { 110 | //RECAPTCHA HANDLE 111 | if (preg_match('/^recaptcha\_(challenge|response)\_field$/', $key, $matches)) { 112 | $fieldname = $this->getName(); 113 | if (!empty($request["recaptcha_challenge_field"])) { 114 | $request[$fieldname]["challenge_field"] = $request["recaptcha_challenge_field"]; 115 | unset($request["recaptcha_challenge_field"]); 116 | } 117 | if (!empty($request["recaptcha_response_field"])) { 118 | $request[$fieldname]["response_field"] = $request["recaptcha_response_field"]; 119 | unset($request["recaptcha_response_field"]); 120 | } 121 | } 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/classes/fields/Reset.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\Basics\Html\BaseElement; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\Basics\Html\TagElement; 21 | use Degami\PHPFormsApi\Abstracts\Fields\Action; 22 | 23 | /** 24 | * The reset button field class 25 | */ 26 | class Reset extends Action 27 | { 28 | 29 | /** 30 | * Class constructor 31 | * 32 | * @param array $options build options 33 | * @param ?string $name field name 34 | */ 35 | public function __construct(array $options = [], ?string $name = null) 36 | { 37 | parent::__construct($options, $name); 38 | if (isset($options['value'])) { 39 | $this->value = $options['value']; 40 | } 41 | } 42 | 43 | /** 44 | * {@inheritdoc} 45 | * 46 | * @param Form $form form object 47 | * 48 | * @return string|BaseElement the element html 49 | */ 50 | public function renderField(Form $form) 51 | { 52 | $id = $this->getHtmlId(); 53 | if (empty($this->value)) { 54 | $this->value = 'Reset'; 55 | } 56 | if ($this->disabled == true) { 57 | $this->attributes['disabled']='disabled'; 58 | } 59 | 60 | return new TagElement([ 61 | 'tag' => 'input', 62 | 'type' => 'reset', 63 | 'id' => $id, 64 | 'name' => $this->name, 65 | 'value' => $this->getText($this->getValues()), 66 | 'attributes' => $this->attributes, 67 | ]); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/classes/fields/Select.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\PHPFormsApi\Form; 19 | use Degami\PHPFormsApi\Abstracts\Fields\FieldMultivalues; 20 | use Degami\PHPFormsApi\Abstracts\Fields\Optionable; 21 | use Degami\Basics\Html\TagElement; 22 | 23 | /** 24 | * The select field class 25 | */ 26 | class Select extends FieldMultivalues 27 | { 28 | 29 | /** 30 | * multiple attribute 31 | * 32 | * @var boolean 33 | */ 34 | protected $multiple = false; 35 | 36 | /** 37 | * Class constructor 38 | * 39 | * @param array $options build options 40 | * @param ?string $name field name 41 | */ 42 | public function __construct(array $options = [], ?string $name = null) 43 | { 44 | if (isset($options['options'])) { 45 | foreach ($options['options'] as $k => $o) { 46 | if ($o instanceof Optionable) { 47 | $o->setParent($this); 48 | $this->addOption($o); 49 | } elseif (is_array($o)) { 50 | $option = new Optgroup($k, ['options' => $o]); 51 | $option->setParent($this); 52 | $this->addOption($option); 53 | } else { 54 | $option = new Option($k, $o); 55 | $option->setParent($this); 56 | $this->addOption($option); 57 | } 58 | } 59 | unset($options['options']); 60 | } 61 | 62 | if (isset($options['default_value'])) { 63 | if (!$this->isMultiple() && !(isset($options['multiple']) && $options['multiple']==true)) { 64 | if (is_array($options['default_value'])) { 65 | $options['default_value'] = reset($options['default_value']); 66 | } 67 | $options['default_value'] = "".$options['default_value']; 68 | } else { 69 | if (!is_array($options['default_value'])) { 70 | $options['default_value'] = [$options['default_value']]; 71 | } 72 | foreach ($options['default_value'] as $k => $v) { 73 | $options['default_value'][$k] = "".$v; 74 | } 75 | } 76 | } 77 | 78 | parent::__construct($options, $name); 79 | } 80 | 81 | /** 82 | * Return field multiple attribute 83 | * 84 | * @return boolean field is multiple 85 | */ 86 | public function isMultiple() 87 | { 88 | return $this->multiple; 89 | } 90 | 91 | /** 92 | * Set field multiple attribute 93 | * 94 | * @param boolean $multiple multiple attribute 95 | * @return Select 96 | */ 97 | public function setMultiple($multiple = true) 98 | { 99 | $this->multiple = ($multiple == true); 100 | return $this; 101 | } 102 | 103 | /** 104 | * Return field value 105 | * 106 | * @return mixed field value 107 | */ 108 | public function getValue() 109 | { 110 | return $this->value; 111 | } 112 | 113 | /** 114 | * {@inheritdoc} 115 | * 116 | * @param Form $form form object 117 | * 118 | * @return string the element html 119 | */ 120 | public function renderField(Form $form) 121 | { 122 | $id = $this->getHtmlId(); 123 | $output = ''; 124 | 125 | if (!isset($this->attributes['class'])) { 126 | $this->attributes['class'] = ''; 127 | } 128 | if ($this->hasErrors()) { 129 | $this->attributes['class'] .= ' has-errors'; 130 | } 131 | if ($this->disabled == true) { 132 | $this->attributes['disabled']='disabled'; 133 | } 134 | $attributes = $this->getAttributes(); 135 | $field_name = ($this->multiple) ? "{$this->name}[]" : $this->name; 136 | 137 | $tag = new TagElement([ 138 | 'tag' => 'select', 139 | 'id' => $id, 140 | 'name' => $field_name, 141 | // 'value' => htmlspecialchars($this->value), 142 | 'attributes' => $this->attributes + ( 143 | ($this->multiple) ? ['multiple' => 'multiple','size' => $this->size] : [] 144 | ), 145 | ]); 146 | 147 | if (isset($this->attributes['placeholder']) && !empty($this->attributes['placeholder'])) { 148 | $tag->addChild(new TagElement([ 149 | 'tag' => 'option', 150 | 'attributes' => [ 151 | 'disabled' => 'disabled', 152 | ] + (isset($this->default_value) ? [] : ['selected' => 'selected']), 153 | 'text' => $this->attributes['placeholder'], 154 | ])); 155 | } 156 | 157 | foreach ($this->options as $key => $value) { 158 | /** @var \Degami\PHPFormsApi\Fields\Option $value */ 159 | $tag->addChild( 160 | $value->renderHTML($this) 161 | ); 162 | } 163 | 164 | return $tag; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/classes/fields/Selectmenu.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\PHPFormsApi\Form; 19 | 20 | /** 21 | * The "selectmenu" select field class 22 | */ 23 | class Selectmenu extends Select 24 | { 25 | 26 | /** 27 | * {@inheritdoc} 28 | * 29 | * @param Form $form form object 30 | */ 31 | public function preRender(Form $form) 32 | { 33 | if ($this->pre_rendered == true) { 34 | return; 35 | } 36 | $id = $this->getHtmlId(); 37 | $this->addJs("\$('#{$id}','#{$form->getId()}').selectmenu({width: 'auto' });"); 38 | 39 | parent::preRender($form); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/classes/fields/Slider.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\Basics\Html\BaseElement; 19 | use Degami\PHPFormsApi\Form; 20 | 21 | /** 22 | * The "slider" select field class 23 | */ 24 | class Slider extends Select 25 | { 26 | 27 | /** 28 | * show value on change 29 | * 30 | * @var boolean 31 | */ 32 | protected $with_val = false; 33 | 34 | 35 | /** 36 | * Class constructor 37 | * 38 | * @param array $options build options 39 | * @param ?string $name field name 40 | */ 41 | public function __construct(array $options = [], ?string $name = null) 42 | { 43 | // get the "default_value" index value 44 | $values = call_user_func_array([__CLASS__, 'arrayGetValues'], [ $this->default_value, $this->options ]); 45 | $oldkey_value = end($values); 46 | 47 | // flatten the options array ang get a numeric keyset 48 | $options['options'] = call_user_func_array([__CLASS__, 'arrayFlatten'], [ $options['options'] ]); 49 | 50 | // search the new index 51 | $this->value = $this->default_value = array_search($oldkey_value, $this->options); 52 | 53 | if (!isset($options['attributes']['class'])) { 54 | $options['attributes']['class'] = ''; 55 | } 56 | $options['attributes']['class'].=' slider'; 57 | 58 | if (isset($options['multiple'])) { 59 | $options['multiple'] = false; 60 | } 61 | 62 | parent::__construct($options, $name); 63 | } 64 | 65 | /** 66 | * {@inheritdoc} 67 | * 68 | * @param Form $form form object 69 | */ 70 | public function preRender(Form $form) 71 | { 72 | if ($this->pre_rendered == true) { 73 | return; 74 | } 75 | $id = $this->getHtmlId(); 76 | $add_js = ''; 77 | if ($this->with_val == true) { 78 | $add_js .= " 79 | var text = \$( '#{$id}' )[ 0 ].options[ \$( '#{$id}' )[ 0 ].selectedIndex ].label; 80 | \$('#{$id}-show_val','#{$form->getId()}').text( text );"; 81 | } 82 | $this->addJs( 83 | " 84 | \$('#{$id}-slider','#{$form->getId()}').slider({ 85 | min: 1, 86 | max: ".count($this->options).", 87 | value: \$( '#{$id}' )[ 0 ].selectedIndex + 1, 88 | slide: function( event, ui ) { 89 | \$( '#{$id}' )[ 0 ].selectedIndex = ui.value - 1; 90 | ".$add_js." 91 | } 92 | }); 93 | \$( '#{$id}' ).change(function() { 94 | \$('#{$id}-slider').slider('value', this.selectedIndex + 1 ); 95 | }).hide();" 96 | ); 97 | 98 | parent::preRender($form); 99 | } 100 | 101 | /** 102 | * {@inheritdoc} 103 | * 104 | * @param Form $form form object 105 | * 106 | * @return string|BaseElement the element html 107 | */ 108 | public function renderField(Form $form) 109 | { 110 | $id = $this->getHtmlId(); 111 | 112 | $text = isset($this->default_value) && $this->optionsHasKey($this->default_value) ? 113 | $this->options[ $this->default_value ]->getLabel() : 114 | ''; 115 | if (trim($text) == '' && count($this->options) > 0) { 116 | /** @var Option $option */ 117 | $option = reset($this->options); 118 | $text = $option->getLabel(); 119 | } 120 | if (!preg_match("/
    <\/div>/i", $this->suffix)) { 121 | $this->suffix = "
    " . 122 | (($this->with_val == true) ? "
    {$text}
    " : '') . 123 | $this->suffix; 124 | } 125 | return parent::renderField($form); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/classes/fields/Spinner.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\PHPFormsApi\Form; 19 | 20 | /** 21 | * The spinner number input field class 22 | */ 23 | class Spinner extends Number 24 | { 25 | /** 26 | * {@inheritdoc} 27 | * 28 | * @param Form $form form object 29 | */ 30 | public function preRender(Form $form) 31 | { 32 | if ($this->pre_rendered == true) { 33 | return; 34 | } 35 | $id = $this->getHtmlId(); 36 | 37 | $js_options = ''; 38 | if (is_numeric($this->min) && is_numeric($this->max) && $this->max >= $this->min) { 39 | $js_options = "{min: $this->min, max: $this->max, step: $this->step}"; 40 | } 41 | 42 | $this->addJs("\$('#{$id}','#{$form->getId()}').attr('type','text').spinner({$js_options});"); 43 | 44 | parent::preRender($form); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/classes/fields/Submit.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\Basics\Html\BaseElement; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\Basics\Html\TagElement; 21 | use Degami\PHPFormsApi\Abstracts\Fields\Clickable; 22 | 23 | /** 24 | * The submit input type field class 25 | */ 26 | class Submit extends Clickable 27 | { 28 | /** 29 | * {@inheritdoc} 30 | * 31 | * @param Form $form form object 32 | * @return string|BaseElement the element html 33 | */ 34 | public function renderField(Form $form) 35 | { 36 | $id = $this->getHtmlId(); 37 | if (empty($this->value)) { 38 | $this->value = 'Submit'; 39 | } 40 | if ($this->disabled == true) { 41 | $this->attributes['disabled']='disabled'; 42 | } 43 | 44 | $tag = new TagElement([ 45 | 'tag' => 'input', 46 | 'type' => 'submit', 47 | 'id' => $id, 48 | 'name' => $this->name, 49 | 'value' => $this->getText($this->getValues()), 50 | 'attributes' => $this->attributes, 51 | ]); 52 | return $tag; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/classes/fields/Switchbox.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\Basics\Html\BaseElement; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\Basics\Html\TagElement; 21 | 22 | /** 23 | * The switch selection field class 24 | */ 25 | class Switchbox extends Radios 26 | { 27 | 28 | /** @var mixed "no" value */ 29 | protected $no_value; 30 | 31 | /** @var string "no" label */ 32 | protected $no_label; 33 | 34 | /** @var mixed "yes" value */ 35 | protected $yes_value; 36 | 37 | /** @var string "yes" label */ 38 | protected $yes_label; 39 | 40 | /** 41 | * Class constructor 42 | * 43 | * @param array $options build options 44 | * @param ?string $name field name 45 | */ 46 | public function __construct(array $options = [], ?string $name = null) 47 | { 48 | $this->no_value = 0; 49 | $this->no_label = $this->getText('No'); 50 | $this->yes_value = 1; 51 | $this->yes_label = $this->getText('Yes'); 52 | 53 | // labels and values can be overwritten 54 | parent::__construct($options, $name); 55 | 56 | // "options" is overwritten 57 | $this->options = [ 58 | $this->no_value => $this->no_label, 59 | $this->yes_value => $this->yes_label, 60 | ]; 61 | } 62 | 63 | /** 64 | * {@inheritdoc} 65 | * 66 | * @param Form $form form object 67 | */ 68 | public function preRender(Form $form) 69 | { 70 | if ($this->pre_rendered == true) { 71 | return; 72 | } 73 | $id = $this->getHtmlId(); 74 | 75 | 76 | foreach ($this->options as $key => $value) { 77 | $this->addJs( 78 | "\$('#{$id}-{$key}','#{$form->getId()}') 79 | .click(function(evt){ 80 | \$(this).closest('label').addClass('ui-state-active'); 81 | \$('#{$id} input[type=\"radio\"]').not(this).closest('label').removeClass('ui-state-active'); 82 | });" 83 | ); 84 | } 85 | 86 | $this->addCss( 87 | "#{$id} .label-switch{ 88 | text-align: center; 89 | display: inline-block; 90 | width: 50%; 91 | padding-top: 10px; 92 | padding-bottom: 10px; 93 | box-sizing: border-box; 94 | }" 95 | ); 96 | $this->addJs( 97 | "\$('#{$id}','#{$form->getId()}').find('input[type=\"radio\"]:checked') 98 | .closest('label').addClass('ui-state-active');" 99 | ); 100 | //$this->add_css("#{$id} .label-switch input{ display: none; }"); 101 | $this->addJs("\$('#{$id} input[type=\"radio\"]','#{$form->getId()}').hide();"); 102 | parent::preRender($form); 103 | } 104 | 105 | /** 106 | * {@inheritdoc} 107 | * 108 | * @param Form $form form object 109 | * 110 | * @return string|BaseElement the element html 111 | */ 112 | public function renderField(Form $form) 113 | { 114 | $id = $this->getHtmlId(); 115 | $tag = new TagElement([ 116 | 'tag' => 'div', 117 | 'id' => $id, 118 | 'attributes' => ['class' => 'options ui-widget-content ui-corner-all'], 119 | ]); 120 | 121 | if ($this->disabled == true) { 122 | $this->attributes['disabled']='disabled'; 123 | } 124 | 125 | foreach ($this->options as $key => $value) { 126 | $attributes = $this->attributes; 127 | if (is_array($value) && isset($value['attributes'])) { 128 | $attributes = $value['attributes']; 129 | } 130 | if (is_array($value)) { 131 | $value = $value['value']; 132 | } 133 | 134 | $tag_label = new TagElement([ 135 | 'tag' => 'label', 136 | 'attributes' => [ 137 | 'id' => "{$id}-{$key}-button", 138 | 'for' => "{$id}-{$key}", 139 | 'class' => "label-switch ui-widget ui-state-default" 140 | ], 141 | ]); 142 | $tag_label->addChild(new TagElement([ 143 | 'tag' => 'input', 144 | 'type' => 'radio', 145 | 'id' => "{$id}-{$key}", 146 | 'name' => "{$this->name}", 147 | 'value' => $key, 148 | 'attributes' => array_merge( 149 | $attributes, 150 | (($this->getValues() == $key) ? ['checked' => 'checked'] : []) 151 | ), 152 | 'text' => $this->getText($value), 153 | ])); 154 | $tag->addChild($tag_label); 155 | } 156 | return $tag; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/classes/fields/Tel.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\PHPFormsApi\Form; 19 | use Degami\PHPFormsApi\Abstracts\Base\Field; 20 | use Degami\Basics\Html\TagElement; 21 | 22 | /** 23 | * The tel input field class 24 | */ 25 | class Tel extends Field 26 | { 27 | /** 28 | * {@inheritdoc} 29 | * 30 | * @param Form $form form object 31 | * 32 | * @return string the element html 33 | */ 34 | public function renderField(Form $form) 35 | { 36 | $id = $this->getHtmlId(); 37 | 38 | if (!isset($this->attributes['class'])) { 39 | $this->attributes['class'] = ''; 40 | } 41 | if ($this->hasErrors()) { 42 | $this->attributes['class'] .= ' has-errors'; 43 | } 44 | if ($this->disabled == true) { 45 | $this->attributes['disabled']='disabled'; 46 | } 47 | if (is_array($this->value)) { 48 | $this->value = ''; 49 | } 50 | 51 | return new TagElement([ 52 | 'tag' => 'input', 53 | 'type' => 'tel', 54 | 'id' => $id, 55 | 'name' => $this->name, 56 | 'value' => htmlspecialchars($this->getValues()), 57 | 'attributes' => $this->attributes + ['size' => $this->size], 58 | ]); 59 | } 60 | 61 | /** 62 | * {@inheritdoc} 63 | * 64 | * @return boolean this is a value 65 | */ 66 | public function isAValue() : bool 67 | { 68 | return true; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/classes/fields/Textarea.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\PHPFormsApi\Form; 19 | use Degami\PHPFormsApi\Abstracts\Base\Field; 20 | use Degami\Basics\Html\TagElement; 21 | 22 | /** 23 | * The textarea field class 24 | */ 25 | class Textarea extends Field 26 | { 27 | /** 28 | * Element maxlenght 29 | * 30 | * @var integer 31 | */ 32 | protected $maxlength = null; 33 | 34 | /** 35 | * Element minlength 36 | * 37 | * @var integer 38 | */ 39 | protected $minlength = null; 40 | 41 | /** 42 | * rows 43 | * 44 | * @var integer 45 | */ 46 | protected $rows = 5; 47 | 48 | /** 49 | * resizable flag 50 | * 51 | * @var boolean 52 | */ 53 | protected $resizable = false; 54 | 55 | /** 56 | * {@inheritdoc} 57 | * 58 | * @param Form $form form object 59 | */ 60 | public function preRender(Form $form) 61 | { 62 | if ($this->pre_rendered == true) { 63 | return; 64 | } 65 | $id = $this->getHtmlId(); 66 | if ($this->resizable == true) { 67 | $this->addJs("\$('#{$id}','#{$form->getId()}').resizable({handles:\"se\"});"); 68 | } 69 | parent::preRender($form); 70 | } 71 | 72 | /** 73 | * {@inheritdoc} 74 | * 75 | * @param Form $form form object 76 | * @return string the element html 77 | */ 78 | public function renderField(Form $form) 79 | { 80 | $id = $this->getHtmlId(); 81 | 82 | if (!isset($this->attributes['class'])) { 83 | $this->attributes['class'] = ''; 84 | } 85 | $errors = $this->getErrors(); 86 | if (!empty($errors)) { 87 | $this->attributes['class'] .= ' has-errors'; 88 | } 89 | if ($this->disabled == true) { 90 | $this->attributes['disabled']='disabled'; 91 | } 92 | 93 | return new TagElement([ 94 | 'tag' => 'textarea', 95 | 'id' => $id, 96 | 'name' => $this->name, 97 | 'text' => $this->getValues(), 98 | 'attributes' => $this->attributes + ['cols' => $this->size, 'rows' => $this->rows], 99 | 'has_close' => true, 100 | ]); 101 | } 102 | 103 | /** 104 | * {@inheritdoc} 105 | * 106 | * @return boolean this is a value 107 | */ 108 | public function isAValue() : bool 109 | { 110 | return true; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/classes/fields/Textfield.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\Basics\Html\BaseElement; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\PHPFormsApi\Abstracts\Base\Field; 21 | use Degami\Basics\Html\TagElement; 22 | 23 | /** 24 | * The text input field class 25 | */ 26 | class Textfield extends Field 27 | { 28 | /** 29 | * Element maxlenght 30 | * 31 | * @var integer 32 | */ 33 | protected $maxlength = null; 34 | 35 | /** 36 | * Element minlength 37 | * 38 | * @var integer 39 | */ 40 | protected $minlength = null; 41 | 42 | /** 43 | * {@inheritdoc} 44 | * 45 | * @param Form $form form object 46 | * 47 | * @return string|BaseElement the element html 48 | */ 49 | public function renderField(Form $form) 50 | { 51 | $id = $this->getHtmlId(); 52 | 53 | if (!isset($this->attributes['class'])) { 54 | $this->attributes['class'] = ''; 55 | } 56 | if ($this->hasErrors()) { 57 | $this->attributes['class'] .= ' has-errors'; 58 | } 59 | if ($this->disabled == true) { 60 | $this->attributes['disabled']='disabled'; 61 | } 62 | if (is_array($this->value)) { 63 | $this->value = ''; 64 | } 65 | 66 | return new TagElement([ 67 | 'tag' => 'input', 68 | 'type' => 'text', 69 | 'id' => $id, 70 | 'name' => $this->name, 71 | 'value' => htmlspecialchars((string) $this->getValues()), 72 | 'attributes' => $this->attributes + ['size' => $this->size], 73 | ]); 74 | } 75 | 76 | /** 77 | * {@inheritdoc} 78 | * 79 | * @return boolean this is a value 80 | */ 81 | public function isAValue() : bool 82 | { 83 | return true; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/classes/fields/Time.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\Basics\Html\BaseElement; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\PHPFormsApi\Abstracts\Base\Field; 21 | use Degami\Basics\Html\TagElement; 22 | 23 | /** 24 | * The time field class 25 | */ 26 | class Time extends Field 27 | { 28 | /** 29 | * Class constructor 30 | * 31 | * @param array $options build options 32 | * @param ?string $name field name 33 | */ 34 | public function __construct(array $options = [], ?string $name = null) 35 | { 36 | $this->default_value = '00:00'; 37 | parent::__construct($options, $name); 38 | } 39 | 40 | /** 41 | * {@inheritdoc} 42 | * 43 | * @param Form $form form object 44 | * 45 | * @return string|BaseElement the element html 46 | */ 47 | public function renderField(Form $form) 48 | { 49 | $id = $this->getHtmlId(); 50 | 51 | if (!isset($this->attributes['class'])) { 52 | $this->attributes['class'] = ''; 53 | } 54 | if ($this->hasErrors()) { 55 | $this->attributes['class'] .= ' has-errors'; 56 | } 57 | if ($this->disabled == true) { 58 | $this->attributes['disabled']='disabled'; 59 | } 60 | if (is_array($this->value)) { 61 | $this->value = ''; 62 | } 63 | 64 | return new TagElement([ 65 | 'tag' => 'input', 66 | 'type' => 'time', 67 | 'id' => $id, 68 | 'name' => $this->name, 69 | 'value' => htmlspecialchars($this->getValues()), 70 | 'attributes' => $this->attributes + ['size' => $this->size], 71 | ]); 72 | } 73 | 74 | /** 75 | * {@inheritdoc} 76 | * 77 | * @return boolean this is a value 78 | */ 79 | public function isAValue() : bool 80 | { 81 | return true; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/classes/fields/Tinymce.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\PHPFormsApi\Form; 19 | use \stdClass; 20 | 21 | /** 22 | * tinymce beautified textarea 23 | */ 24 | class Tinymce extends Textarea 25 | { 26 | /** 27 | * tinymce options 28 | * 29 | * @var array 30 | */ 31 | protected $tinymce_options = []; 32 | 33 | /** 34 | * Get tinymce options array 35 | * 36 | * @return array tinymce options 37 | */ 38 | public function &getTinymceOptions(): array 39 | { 40 | return $this->tinymce_options; 41 | } 42 | 43 | /** 44 | * Set tinymce options array 45 | * 46 | * @param array $options array of valid tinymce options 47 | * @return self 48 | */ 49 | public function setTinymceOptions(array $options): Tinymce 50 | { 51 | $options = array_filter($options, [$this, 'isValidTinymceOption']); 52 | $this->tinymce_options = $options; 53 | 54 | return $this; 55 | } 56 | 57 | /** 58 | * {@inheritdoc} 59 | * 60 | * @param Form $form form object 61 | */ 62 | public function preRender(Form $form) 63 | { 64 | if ($this->pre_rendered == true) { 65 | return; 66 | } 67 | $id = $this->getHtmlId(); 68 | $this->tinymce_options['selector'] = "#{$id}"; 69 | $tinymce_options = new stdClass; 70 | foreach ($this->tinymce_options as $key => $value) { 71 | if (! $this->isValidTinymceOption($key)) { 72 | continue; 73 | } 74 | $tinymce_options->{$key} = $value; 75 | } 76 | $this->addJs("tinymce.init(".json_encode($tinymce_options).");"); 77 | $this->addJs(" 78 | document.querySelector('form').addEventListener('submit', function() { 79 | const editor = tinymce.get('$id'); 80 | const content = editor.getBody().innerHTML; 81 | const textarea = document.querySelector('textarea#$id'); 82 | if (textarea) { 83 | textarea.value = content; 84 | } 85 | }); 86 | "); 87 | parent::preRender($form); 88 | } 89 | 90 | /** 91 | * filters valid tinymce options 92 | * 93 | * @param string $propertyname property name 94 | * @return boolean TRUE if is a valid tinymce option 95 | */ 96 | private function isValidTinymceOption(string $propertyname): bool 97 | { 98 | // could be used to filter elements 99 | return true; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/classes/fields/Url.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\PHPFormsApi\Form; 19 | use Degami\PHPFormsApi\Abstracts\Base\Field; 20 | use Degami\Basics\Html\TagElement; 21 | 22 | /** 23 | * The url input field class 24 | */ 25 | class Url extends Field 26 | { 27 | 28 | /** 29 | * Class constructor 30 | * 31 | * @param array $options build options 32 | * @param ?string $name field name 33 | */ 34 | public function __construct(array $options = [], ?string $name = null) 35 | { 36 | parent::__construct($options, $name); 37 | 38 | // ensure is url validator is present 39 | $this->getValidate()->addElement('url'); 40 | } 41 | 42 | /** 43 | * {@inheritdoc} 44 | * 45 | * @param Form $form form object 46 | * 47 | * @return string the element html 48 | */ 49 | public function renderField(Form $form) 50 | { 51 | $id = $this->getHtmlId(); 52 | 53 | if (!isset($this->attributes['class'])) { 54 | $this->attributes['class'] = ''; 55 | } 56 | if ($this->hasErrors()) { 57 | $this->attributes['class'] .= ' has-errors'; 58 | } 59 | if ($this->disabled == true) { 60 | $this->attributes['disabled']='disabled'; 61 | } 62 | if (is_array($this->value)) { 63 | $this->value = ''; 64 | } 65 | 66 | return new TagElement([ 67 | 'tag' => 'input', 68 | 'type' => 'url', 69 | 'id' => $id, 70 | 'name' => $this->name, 71 | 'value' => htmlspecialchars($this->getValues()), 72 | 'attributes' => $this->attributes + ['size' => $this->size], 73 | ]); 74 | } 75 | 76 | /** 77 | * {@inheritdoc} 78 | * 79 | * @return boolean this is a value 80 | */ 81 | public function isAValue() : bool 82 | { 83 | return true; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/classes/fields/Value.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELDS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Fields; 17 | 18 | use Degami\Basics\Html\BaseElement; 19 | use Degami\PHPFormsApi\Form; 20 | use Degami\PHPFormsApi\Abstracts\Base\Field; 21 | 22 | /** 23 | * The value field class 24 | * this field is not rendered as part of the form, but the value is passed on form submission 25 | */ 26 | class Value extends Field 27 | { 28 | 29 | /** 30 | * Class constructor 31 | * 32 | * @param array $options build options 33 | * @param ?string $name field name 34 | */ 35 | public function __construct(array $options = [], ?string $name = null) 36 | { 37 | $this->container_tag = ''; 38 | $this->container_class = ''; 39 | parent::__construct($options, $name); 40 | if (isset($options['value'])) { 41 | $this->value = $options['value']; 42 | } 43 | } 44 | 45 | /** 46 | * {@inheritdoc} 47 | * 48 | * @param Form $form form object 49 | * 50 | * @return string|BaseElement an empty string 51 | */ 52 | public function renderField(Form $form) 53 | { 54 | return ''; 55 | } 56 | 57 | /** 58 | * validate function 59 | * 60 | * @return boolean this field is always valid 61 | */ 62 | public function isValid() : bool 63 | { 64 | return true; 65 | } 66 | 67 | /** 68 | * {@inheritdoc} 69 | * 70 | * @return boolean this is a value 71 | */ 72 | public function isAValue() : bool 73 | { 74 | return true; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/classes/traits/Containers.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### TRAITS #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Traits; 17 | 18 | use Degami\PHPFormsApi\Abstracts\Base\Element; 19 | use Degami\PHPFormsApi\Abstracts\Base\Field; 20 | use Degami\PHPFormsApi\Abstracts\Base\FieldsContainer; 21 | use Degami\PHPFormsApi\Abstracts\Fields\ComposedField; 22 | use Degami\PHPFormsApi\Exceptions\FormException; 23 | 24 | /** 25 | * containers specific functions 26 | */ 27 | trait Containers 28 | { 29 | 30 | /** 31 | * keeps fields insert order 32 | * 33 | * @var array 34 | */ 35 | protected $insert_field_order = []; 36 | 37 | /** 38 | * Element fields 39 | * 40 | * @var array 41 | */ 42 | protected $fields = []; 43 | 44 | /** 45 | * Get the fields array by reference 46 | * 47 | * @return array the array of field elements 48 | */ 49 | public function &getFields(): array 50 | { 51 | return $this->fields; 52 | } 53 | 54 | /** 55 | * Get parent namespace 56 | * 57 | * @return string parent namespace 58 | */ 59 | private function parentNameSpace(): string 60 | { 61 | $namespaceParts = explode('\\', __NAMESPACE__); 62 | return implode("\\", array_slice($namespaceParts, 0, -1)); 63 | } 64 | 65 | /** 66 | * Returns a field object instance 67 | * 68 | * @param string $name field name 69 | * @param mixed $field field to add, can be an array or a field subclass 70 | * @return Field instance 71 | * @throws FormException 72 | */ 73 | public function getFieldObj(string $name, $field): Field 74 | { 75 | if (is_array($field)) { 76 | $parentNS = $this->parentNameSpace(); 77 | $element_type = isset($field['type']) ? 78 | $this->snakeCaseToPascalCase($field['type']) : 79 | 'textfield'; 80 | 81 | $field_type = $parentNS . "\\Fields\\" . $element_type; 82 | $container_type = $parentNS . "\\Containers\\" . $element_type; 83 | $root_type = $parentNS . "\\" . $element_type; 84 | 85 | if (!class_exists($field_type) && !class_exists($container_type) && !class_exists($root_type)) { 86 | throw new FormException( 87 | "Error adding field. Class \"$field_type\", \"$container_type\", \"$root_type\" not found", 88 | 1 89 | ); 90 | } 91 | 92 | if (class_exists($field_type)) { 93 | $type = $field_type; 94 | } elseif (class_exists($container_type)) { 95 | $type = $container_type; 96 | } else { 97 | $type = $root_type; 98 | } 99 | 100 | if (is_subclass_of($type, 'Degami\PHPFormsApi\Abstracts\Base\Field')) { 101 | /** @var Field $type */ 102 | $field = $type::getInstance($field, $name); 103 | } else { 104 | $field = new $type($field, $name); 105 | } 106 | } elseif ($field instanceof Field) { 107 | $field->setName($name); 108 | } else { 109 | throw new FormException("Error adding field. Array or field subclass expected, ".gettype($field)." given", 1); 110 | } 111 | 112 | return $field; 113 | } 114 | 115 | /** 116 | * Check if field is a field container 117 | * 118 | * @param Field $field field instance 119 | * @return boolean true if field is a field container 120 | */ 121 | public function isFieldContainer(Field $field): bool 122 | { 123 | return $field instanceof FieldsContainer && !($field instanceof ComposedField); 124 | } 125 | 126 | /** 127 | * add markup helper 128 | * 129 | * @param string $markup markup to add 130 | * @param array $options 131 | * @return Element 132 | */ 133 | public function addMarkup(string $markup, array $options = []): Element 134 | { 135 | static $lastMarkupIndex = 0; 136 | return $this->addField('_markup_'.time().'_'.$lastMarkupIndex++, [ 137 | 'type' => 'markup', 138 | 'container_tag' => null, 139 | 'value' => $markup, 140 | ] + $options); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/fonts/Lato-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/degami/php-forms-api/fec01af913d6f0591c8a151f0eb16f9915f1a076/src/fonts/Lato-Regular.ttf -------------------------------------------------------------------------------- /src/interfaces/FieldInterface.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELD INTERFACE #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Interfaces; 17 | 18 | use Degami\Basics\Html\BaseElement; 19 | use Degami\Basics\Html\TagElement; 20 | use Degami\PHPFormsApi\Form; 21 | 22 | /** 23 | * field interface 24 | */ 25 | interface FieldInterface 26 | { 27 | 28 | /** 29 | * this function tells to the form if this element is a value that needs to be 30 | * included into parent values() function call result 31 | * 32 | * @return boolean include_me 33 | */ 34 | public function isAValue() : bool; // tells if component value is passed on the parent values() function call 35 | 36 | /** 37 | * Pre-render hook 38 | * 39 | * @param Form $form form object 40 | */ 41 | public function preRender(Form $form); 42 | 43 | /** 44 | * The function that actually renders the html field 45 | * 46 | * @param Form $form form object 47 | * 48 | * @return string|BaseElement the field html 49 | */ 50 | public function renderField(Form $form); // renders html 51 | 52 | /** 53 | * Process / set field value 54 | * 55 | * @param mixed $value value to set 56 | */ 57 | public function processValue($value); 58 | 59 | /** 60 | * Check element validity 61 | * 62 | * @return boolean TRUE if element is valid 63 | */ 64 | public function isValid() : bool; 65 | 66 | /** 67 | * Return form elements values into this element 68 | * 69 | * @return mixed form values 70 | */ 71 | public function getValues(); 72 | 73 | /** 74 | * which element should return the add_field() function 75 | * 76 | * @return string one of 'parent' or 'this' 77 | */ 78 | public function onAddReturn() : string; 79 | } 80 | -------------------------------------------------------------------------------- /src/interfaces/FieldsContainerInterface.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | /* ######################################################### 13 | #### FIELD INTERFACE #### 14 | ######################################################### */ 15 | 16 | namespace Degami\PHPFormsApi\Interfaces; 17 | 18 | use Degami\PHPFormsApi\Abstracts\Base\Element; 19 | use Degami\PHPFormsApi\Abstracts\Base\FieldsContainer; 20 | use Degami\PHPFormsApi\Form; 21 | 22 | /** 23 | * fields container interface 24 | */ 25 | interface FieldsContainerInterface extends FieldInterface 26 | { 27 | 28 | /** 29 | * Add field to form 30 | * 31 | * @param string $name field name 32 | * @param mixed $field field to add, can be an array or a field subclass 33 | * @return FieldsContainer 34 | */ 35 | public function addField(string $name, $field) : Element; 36 | 37 | /** 38 | * remove field from form 39 | * 40 | * @param string $name field name 41 | * @return FieldsContainer 42 | */ 43 | public function removeField(string $name) : FieldsContainer; 44 | 45 | /** 46 | * on_add_return overload 47 | * 48 | * @return string 'this' 49 | */ 50 | public function onAddReturn(): string; 51 | } 52 | -------------------------------------------------------------------------------- /src/php_forms_api_bootstrap.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | 13 | if ((function_exists('session_status') && session_status() != PHP_SESSION_NONE) || trim(session_id()) != '') { 14 | @ini_set('session.gc_maxlifetime', FORMS_SESSION_TIMEOUT); 15 | @session_set_cookie_params(FORMS_SESSION_TIMEOUT); 16 | } 17 | -------------------------------------------------------------------------------- /src/php_forms_api_defines.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT https://opensource.org/licenses/mit-license.php 10 | * @link https://github.com/degami/php-forms-api 11 | */ 12 | 13 | /* 14 | * Turn on error reporting during development 15 | */ 16 | // error_reporting(E_ALL); 17 | // ini_set('display_errors', TRUE); 18 | // ini_set('display_startup_errors', TRUE); 19 | 20 | namespace Degami\PHPFormsApi; 21 | 22 | /* 23 | * PHP Forms API library configuration 24 | */ 25 | 26 | if (!defined('FORMS_DEFAULT_FORM_CONTAINER_TAG')) { 27 | define('FORMS_DEFAULT_FORM_CONTAINER_TAG', 'div'); 28 | } 29 | if (!defined('FORMS_DEFAULT_FORM_CONTAINER_CLASS')) { 30 | define('FORMS_DEFAULT_FORM_CONTAINER_CLASS', 'form-container'); 31 | } 32 | if (!defined('FORMS_DEFAULT_FIELD_CONTAINER_TAG')) { 33 | define('FORMS_DEFAULT_FIELD_CONTAINER_TAG', 'div'); 34 | } 35 | if (!defined('FORMS_DEFAULT_FIELD_CONTAINER_CLASS')) { 36 | define('FORMS_DEFAULT_FIELD_CONTAINER_CLASS', 'form-item'); 37 | } 38 | if (!defined('FORMS_DEFAULT_FIELD_LABEL_CLASS')) { 39 | define('FORMS_DEFAULT_FIELD_LABEL_CLASS', ''); 40 | } 41 | if (!defined('FORMS_FIELD_ADDITIONAL_CLASS')) { 42 | define('FORMS_FIELD_ADDITIONAL_CLASS', ''); 43 | } 44 | if (!defined('FORMS_VALIDATE_EMAIL_DNS')) { 45 | define('FORMS_VALIDATE_EMAIL_DNS', true); 46 | } 47 | if (!defined('FORMS_VALIDATE_EMAIL_BLOCKED_DOMAINS')) { 48 | define('FORMS_VALIDATE_EMAIL_BLOCKED_DOMAINS', 'mailinator.com|guerrillamail.com'); 49 | } 50 | if (!defined('FORMS_BASE_PATH')) { 51 | define('FORMS_BASE_PATH', ''); 52 | } 53 | if (!defined('FORMS_XSS_ALLOWED_TAGS')) { 54 | define('FORMS_XSS_ALLOWED_TAGS', 'a|em|strong|cite|code|ul|ol|li|dl|dt|dd'); 55 | } 56 | if (!defined('FORMS_SESSION_TIMEOUT')) { 57 | define('FORMS_SESSION_TIMEOUT', 7200); 58 | } 59 | if (!defined('FORMS_ERRORS_ICON')) { 60 | define( 61 | 'FORMS_ERRORS_ICON', 62 | '' 63 | ); 64 | } 65 | if (!defined('FORMS_ERRORS_TEMPLATE')) { 66 | define( 67 | 'FORMS_ERRORS_TEMPLATE', 68 | '
    ' . FORMS_ERRORS_ICON . '
      %s
    ' 69 | ); 70 | } 71 | if (!defined('FORMS_HIGHLIGHTS_ICON')) { 72 | define( 73 | 'FORMS_HIGHLIGHTS_ICON', 74 | '' 75 | ); 76 | } 77 | if (!defined('FORMS_HIGHLIGHTS_TEMPLATE')) { 78 | define( 79 | 'FORMS_HIGHLIGHTS_TEMPLATE', 80 | '
    ' . FORMS_HIGHLIGHTS_ICON . '
      %s
    ' 81 | ); 82 | } 83 | --------------------------------------------------------------------------------