PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 3.6.50
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v3.6.50
6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 3.6.65 All 196 releases
fluentform / app / Services / FormBuilder / FormBuilder.php

FormBuilder.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 3.6.50, at app/Services/FormBuilder/FormBuilder.php

354 lines 12.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentForm\App\Services\FormBuilder;
4
5 use FluentForm\App\Helpers\Helper;
6 use FluentForm\Framework\Helpers\ArrayHelper;
7
8 class FormBuilder
9 {
10 /**
11 * The Applivcation instance
12 * @var Framework\Foundation\Application
13 */
14 protected $app = null;
15
16 protected $form = null;
17
18 /**
19 * Conditional logic for elements
20 * @var array
21 */
22 public $conditions = array();
23
24 /**
25 * Validation rules for elements
26 * @var array
27 */
28 public $validationRules = array();
29
30 public $tabIndex = 1;
31
32 public $fieldLists = [];
33
34 public $containerCounter;
35
36 /**
37 * Construct the form builder instance
38 * @param Framework\Foundation\Application $app
39 */
40 public function __construct($app)
41 {
42 $this->app = $app;
43 $this->containerCounter = 1;
44 }
45
46 /**
47 * Render the form
48 * @param \StdClass $form [Form entry from database]
49 * @return mixed
50 */
51 public function build($form, $extraCssClass = '', $instanceCssClass = '')
52 {
53 $this->form = $form;
54 $hasStepWrapper = isset($form->fields['stepsWrapper']) && $form->fields['stepsWrapper'];
55
56 $labelPlacement = $form->settings['layout']['labelPlacement'];
57
58 $formClass = "frm-fluent-form fluent_form_{$form->id} ff-el-form-{$labelPlacement}";
59
60 if ($extraCssClass) $formClass .= " {$extraCssClass}";
61
62 if ($hasStepWrapper) {
63 $formClass .= ' ff-form-has-steps';
64 }
65
66 if ($extraFormClass = Helper::formExtraCssClass($form)) {
67 $formClass .= ' ' . $extraFormClass;
68 }
69
70 $formBody = $this->buildFormBody($form);
71
72 $formClass = apply_filters('fluentform_form_class', $formClass, $form);
73
74 if ($form->has_payment) {
75 $formClass .= ' fluentform_has_payment';
76 }
77
78 $formAttributes = apply_filters('fluent_form_html_attributes', [
79 'data-form_id' => $form->id,
80 'id' => 'fluentform_'.$form->id,
81 'class' => $formClass,
82 'data-form_instance' => $instanceCssClass
83 ], $form);
84
85 $formAtts = $this->buildAttributes($formAttributes);
86
87 ob_start();
88
89 echo "<div class='fluentform fluentform_wrapper_".$form->id."'>";
90
91 do_action('fluentform_before_form_render', $form);
92
93 echo "<form ".$formAtts.">";
94
95 do_action('fluentform_form_element_start', $form);
96
97 echo "<input type='hidden' name='__fluent_form_embded_post_id' value='" . get_the_ID() . "' />";
98
99 wp_nonce_field(
100 'fluentform-submit-form',
101 '_fluentform_' . $form->id . '_fluentformnonce',
102 true,
103 true
104 );
105
106 echo $formBody;
107
108 echo "</form><div id='fluentform_" . $form->id . "_errors' class='ff-errors-in-stack ";
109
110 echo $extraCssClass . "_errors " . $instanceCssClass . "_errors'></div></div>";
111
112 do_action('fluentform_after_form_render', $form);
113
114 return ob_get_clean();
115 }
116
117
118 public function buildFormBody($form)
119 {
120 $hasStepWrapper = isset($form->fields['stepsWrapper']) && $form->fields['stepsWrapper'];
121
122 ob_start();
123
124 $stepCounter = 1;
125
126 foreach ($form->fields['fields'] as $item) {
127
128 if ($hasStepWrapper && $item['element'] == 'form_step') {
129 $stepCounter++;
130 }
131
132 $this->setUniqueIdentifier($item);
133
134 $item = apply_filters('fluentform_before_render_item', $item, $form);
135
136 do_action('fluentform_render_item_' . $item['element'], $item, $form);
137
138 $this->extractValidationRules($item);
139
140 $this->extractConditionalLogic($item);
141 }
142
143 if ($hasStepWrapper) {
144 do_action('fluentform_render_item_step_end', $form->fields['stepsWrapper']['stepEnd'], $form);
145 } else {
146 do_action('fluentform_render_item_submit_button', $form->fields['submitButton'], $form);
147 }
148
149 $content = ob_get_clean();
150
151 if ($hasStepWrapper) {
152 $startElement = $form->fields['stepsWrapper']['stepStart'];
153
154 $steps = ArrayHelper::get($startElement, 'settings.step_titles');
155
156 // check if $stepCounter == count()
157 if ($stepCounter > count($steps)) {
158 $fillCount = $stepCounter - count($steps);
159 foreach (range(1, $fillCount) as $item) {
160 $steps[] = '';
161 }
162 $startElement['settings']['step_titles'] = $steps;
163 }
164
165 $this->setUniqueIdentifier($startElement);
166
167 ob_start();
168
169 do_action('fluentform_render_item_step_start', $startElement, $form);
170
171 $stepStatrt = ob_get_clean();
172
173 $content = $stepStatrt.$content;
174 }
175
176 return $content;
177 }
178
179 /**
180 * Set unique name/data-name for an element
181 * @param array &$item
182 * @return void
183 */
184 protected function setUniqueIdentifier(&$item)
185 {
186 if (isset($item['columns'])) {
187 $item['attributes']['data-name'] = 'ff_cn_id_'.$this->containerCounter;
188 $this->containerCounter++;
189 foreach ($item['columns'] as &$column) {
190 foreach ($column['fields'] as &$field) {
191 $this->setUniqueIdentifier($field);
192 }
193 }
194 } else {
195 if (!isset($item['attributes']['name'])) {
196 if($this->form) {
197 if(empty($this->form->attr_name_index)) {
198 $this->form->attr_name_index = 1;
199 } else {
200 $this->form->attr_name_index += 1;
201 }
202 $uniqueId = $this->form->id.'_'.$this->form->attr_name_index;
203 } else {
204 $uniqueId = uniqid(rand(), true);
205 }
206
207 $item['attributes']['name'] = $item['element'] . '-' . $uniqueId;
208 }
209 $item['attributes']['data-name'] = $item['attributes']['name'];
210 $this->fieldLists[] = $item['element'];
211 }
212 }
213
214 /**
215 * Recursively extract validation rules from a given element
216 * @param array $item
217 * @return void
218 */
219 protected function extractValidationRules($item)
220 {
221 if (isset($item['columns'])) {
222 foreach ($item['columns'] as $column) {
223 foreach ($column['fields'] as $field) {
224 $this->extractValidationRules($field);
225 }
226 }
227 } elseif (isset($item['fields'])) {
228 $rootName = $item['attributes']['name'];
229 foreach ($item['fields'] as $key => $innerItem) {
230 if ($item['element'] == 'address' || $item['element'] == 'input_name') {
231 $itemName = $innerItem['attributes']['name'];
232 $innerItem['attributes']['name'] = $rootName . '[' . $itemName . ']';
233 } else {
234 if ($item['element'] == 'input_repeat' || $item['element'] == 'repeater_field') {
235 if(!empty($innerItem['settings']['validation_rules']['email'])) {
236 unset($innerItem['settings']['validation_rules']['email']);
237 }
238 $innerItem['attributes']['name'] = $rootName . '[' . $key . ']';
239 } else {
240 $innerItem['attributes']['name'] = $rootName;
241 }
242 }
243 $this->extractValidationRule($innerItem);
244 }
245 } elseif ($item['element'] == 'tabular_grid') {
246 $gridName = $item['attributes']['name'];
247 $gridRows = $item['settings']['grid_rows'];
248 $gridType = $item['settings']['tabular_field_type'];
249 foreach ($gridRows as $rowKey => $rowValue) {
250 if ($gridType == 'radio') {
251 $item['attributes']['name'] = $gridName . '[' . $rowKey . ']';
252 $this->extractValidationRule($item);
253 } else {
254 $item['attributes']['name'] = $gridName . '[' . $rowKey . ']';
255 $this->extractValidationRule($item);
256 }
257 }
258 } elseif ($item['element'] == 'chained_select') {
259 $chainedSelectName = $item['attributes']['name'];
260 foreach ($item['settings']['data_source']['headers'] as $select) {
261 $item['attributes']['name'] = $chainedSelectName . '[' . $select . ']';
262 $this->extractValidationRule($item);
263 }
264 } else {
265 $this->extractValidationRule($item);
266 }
267 }
268
269 /**
270 * Extract validation rules from a given element
271 * @param array $item
272 * @return void
273 */
274 protected function extractValidationRule($item)
275 {
276 if (isset($item['settings']['validation_rules'])) {
277 $rules = $item['settings']['validation_rules'];
278 foreach ($rules as $ruleName => $rule) {
279 if(isset($rule['message'])) {
280 $rules[$ruleName]['message'] = apply_filters('fluentform_validation_message_'.$ruleName, $rule['message'], $item);
281 $rules[$ruleName]['message'] = apply_filters('fluentform_validation_message_'.$item['element'].'_'.$ruleName, $rule['message'], $item);
282 }
283 }
284 $rules = apply_filters('fluentform_item_rules_' . $item['element'], $rules, $item);
285 $this->validationRules[ $item['attributes']['name'] ] = $rules;
286 }
287 }
288
289 /**
290 * Extract conditipnal logic from a given element
291 * @param array $item
292 * @return void
293 */
294 protected function extractConditionalLogic($item)
295 {
296 // If container like element, then recurse
297 if (isset($item['columns'])) {
298 $containerConditions = false;
299 if (isset($item['settings']['conditional_logics'])) {
300 $conditionals = $item['settings']['conditional_logics'];
301 if (isset($conditionals['status'])) {
302 if ($conditionals['status'] && $conditionals['conditions']) {
303 $containerConditions = $item['settings']['conditional_logics'];
304 $this->conditions[$item['attributes']['data-name']] = $containerConditions;
305 }
306 }
307 }
308
309 foreach ($item['columns'] as $column) {
310 foreach ($column['fields'] as $field) {
311 if($containerConditions) {
312 $field['container_conditions'] = $containerConditions;
313 }
314 $this->extractConditionalLogic($field);
315 }
316 }
317 } elseif (isset($item['settings']['conditional_logics'])) {
318 $conditionals = $item['settings']['conditional_logics'];
319 if (isset($conditionals['status'])) {
320 if ($conditionals['status'] && $conditionals['conditions']) {
321 $this->conditions[$item['attributes']['data-name']] = $item['settings']['conditional_logics'];
322 }
323 }
324 if(isset($item['container_conditions'])) {
325 if(!isset($this->conditions[$item['attributes']['data-name']])) {
326 $this->conditions[$item['attributes']['data-name']] = [
327 'conditions' => [],
328 'status' => false,
329 'type' => 'any'
330 ];
331 }
332 $this->conditions[$item['attributes']['data-name']]['container_condition'] = $item['container_conditions'];
333 }
334 }
335 }
336
337 /**
338 * Build attributes for any html element
339 * @param array $attributes
340 * @return string [Compiled key='value' attributes]
341 */
342 protected function buildAttributes($attributes, $form = null)
343 {
344 $atts = '';
345 foreach ($attributes as $key => $value) {
346 if ($value || $value === 0 || $value === '0') {
347 $value = htmlspecialchars($value);
348 $atts .= $key.'="'.$value.'" ';
349 }
350 }
351 return $atts;
352 }
353 }
354