PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 4.3.13
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v4.3.13
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 4.3.13, at app/Services/FormBuilder/FormBuilder.php

364 lines 12.5 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 \FluentForm\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 \FluentForm\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 = '', $atts = [])
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 if(strpos($formBody, '{dynamic.')) {
73 $formClass .= ' ff_has_dynamic_smartcode';
74 wp_enqueue_script('fluentform-advanced');
75 }
76
77 $formClass = apply_filters('fluentform_form_class', $formClass, $form);
78
79 if ($form->has_payment) {
80 $formClass .= ' fluentform_has_payment';
81 }
82
83 $formAttributes = apply_filters('fluent_form_html_attributes', [
84 'data-form_id' => $form->id,
85 'id' => 'fluentform_'.$form->id,
86 'class' => $formClass,
87 'data-form_instance' => $instanceCssClass,
88 'method' => 'POST'
89 ], $form);
90
91 $formAtts = $this->buildAttributes($formAttributes);
92
93 ob_start();
94
95 $wrapperClasses = trim('fluentform fluentform_wrapper_'.$form->id.' '.ArrayHelper::get($atts, 'css_classes'));
96
97 echo "<div class='".$wrapperClasses."'>";
98
99 do_action('fluentform_before_form_render', $form);
100
101 echo "<form ".$formAtts.">";
102
103 do_action('fluentform_form_element_start', $form);
104
105 echo "<input type='hidden' name='__fluent_form_embded_post_id' value='" . get_the_ID() . "' />";
106
107 wp_nonce_field(
108 'fluentform-submit-form',
109 '_fluentform_' . $form->id . '_fluentformnonce',
110 true,
111 true
112 );
113
114 fluentFormPrintUnescapedInternalString($formBody);
115
116 echo "</form><div id='fluentform_" . $form->id . "_errors' class='ff-errors-in-stack ";
117
118 echo esc_attr($extraCssClass) . "_errors " . $instanceCssClass . "_errors'></div></div>";
119
120 do_action('fluentform_after_form_render', $form);
121
122 return ob_get_clean();
123 }
124
125
126 public function buildFormBody($form)
127 {
128 $hasStepWrapper = isset($form->fields['stepsWrapper']) && $form->fields['stepsWrapper'];
129
130 ob_start();
131
132 $stepCounter = 1;
133
134 foreach ($form->fields['fields'] as $item) {
135
136 if ($hasStepWrapper && $item['element'] == 'form_step') {
137 $stepCounter++;
138 }
139
140 $this->setUniqueIdentifier($item);
141
142 $item = apply_filters('fluentform_before_render_item', $item, $form);
143
144 do_action('fluentform_render_item_' . $item['element'], $item, $form);
145
146 $this->extractValidationRules($item);
147
148 $this->extractConditionalLogic($item);
149 }
150
151 if ($hasStepWrapper) {
152 do_action('fluentform_render_item_step_end', $form->fields['stepsWrapper']['stepEnd'], $form);
153 } else {
154 do_action('fluentform_render_item_submit_button', $form->fields['submitButton'], $form);
155 }
156
157 $content = ob_get_clean();
158
159 if ($hasStepWrapper) {
160 $startElement = $form->fields['stepsWrapper']['stepStart'];
161
162 $steps = ArrayHelper::get($startElement, 'settings.step_titles');
163
164 // check if $stepCounter == count()
165 if ($stepCounter > count($steps)) {
166 $fillCount = $stepCounter - count($steps);
167 foreach (range(1, $fillCount) as $item) {
168 $steps[] = '';
169 }
170 $startElement['settings']['step_titles'] = $steps;
171 }
172
173 $this->setUniqueIdentifier($startElement);
174
175 ob_start();
176
177 do_action('fluentform_render_item_step_start', $startElement, $form);
178
179 $stepStatrt = ob_get_clean();
180
181 $content = $stepStatrt.$content;
182 }
183
184 return $content;
185 }
186
187 /**
188 * Set unique name/data-name for an element
189 * @param array &$item
190 * @return void
191 */
192 protected function setUniqueIdentifier(&$item)
193 {
194 if (isset($item['columns'])) {
195 $item['attributes']['data-name'] = 'ff_cn_id_'.$this->containerCounter;
196 $this->containerCounter++;
197 foreach ($item['columns'] as &$column) {
198 foreach ($column['fields'] as &$field) {
199 $this->setUniqueIdentifier($field);
200 }
201 }
202 } else {
203 if (!isset($item['attributes']['name'])) {
204 if($this->form) {
205 if(empty($this->form->attr_name_index)) {
206 $this->form->attr_name_index = 1;
207 } else {
208 $this->form->attr_name_index += 1;
209 }
210 $uniqueId = $this->form->id.'_'.$this->form->attr_name_index;
211 } else {
212 $uniqueId = uniqid(rand(), true);
213 }
214
215 $item['attributes']['name'] = $item['element'] . '-' . $uniqueId;
216 }
217 $item['attributes']['data-name'] = $item['attributes']['name'];
218 $this->fieldLists[] = $item['element'];
219 }
220 }
221
222 /**
223 * Recursively extract validation rules from a given element
224 * @param array $item
225 * @return void
226 */
227 protected function extractValidationRules($item)
228 {
229 if (isset($item['columns'])) {
230 foreach ($item['columns'] as $column) {
231 foreach ($column['fields'] as $field) {
232 $this->extractValidationRules($field);
233 }
234 }
235 } elseif (isset($item['fields'])) {
236 $rootName = $item['attributes']['name'];
237 foreach ($item['fields'] as $key => $innerItem) {
238 if ($item['element'] == 'address' || $item['element'] == 'input_name') {
239 $itemName = $innerItem['attributes']['name'];
240 $innerItem['attributes']['name'] = $rootName . '[' . $itemName . ']';
241 } else {
242 if ($item['element'] == 'input_repeat' || $item['element'] == 'repeater_field') {
243
244
245 if(empty($innerItem['settings']['validation_rules']['email'])) {
246 unset($innerItem['settings']['validation_rules']['email']);
247 }
248 $innerItem['attributes']['name'] = $rootName . '[' . $key . ']';
249 } else {
250 $innerItem['attributes']['name'] = $rootName;
251 }
252 }
253 $this->extractValidationRule($innerItem);
254 }
255 } elseif ($item['element'] == 'tabular_grid') {
256 $gridName = $item['attributes']['name'];
257 $gridRows = $item['settings']['grid_rows'];
258 $gridType = $item['settings']['tabular_field_type'];
259 foreach ($gridRows as $rowKey => $rowValue) {
260 if ($gridType == 'radio') {
261 $item['attributes']['name'] = $gridName . '[' . $rowKey . ']';
262 $this->extractValidationRule($item);
263 } else {
264 $item['attributes']['name'] = $gridName . '[' . $rowKey . ']';
265 $this->extractValidationRule($item);
266 }
267 }
268 } elseif ($item['element'] == 'chained_select') {
269 $chainedSelectName = $item['attributes']['name'];
270 foreach ($item['settings']['data_source']['headers'] as $select) {
271 $item['attributes']['name'] = $chainedSelectName . '[' . $select . ']';
272 $this->extractValidationRule($item);
273 }
274 } else {
275 $this->extractValidationRule($item);
276 }
277 }
278
279 /**
280 * Extract validation rules from a given element
281 * @param array $item
282 * @return void
283 */
284 protected function extractValidationRule($item)
285 {
286 if (isset($item['settings']['validation_rules'])) {
287 $rules = $item['settings']['validation_rules'];
288 foreach ($rules as $ruleName => $rule) {
289 if(isset($rule['message'])) {
290 $rules[$ruleName]['message'] = apply_filters('fluentform_validation_message_'.$ruleName, $rule['message'], $item);
291 $rules[$ruleName]['message'] = apply_filters('fluentform_validation_message_'.$item['element'].'_'.$ruleName, $rule['message'], $item);
292 }
293 }
294 $rules = apply_filters('fluentform_item_rules_' . $item['element'], $rules, $item);
295 $this->validationRules[ $item['attributes']['name'] ] = $rules;
296 }
297 }
298
299 /**
300 * Extract conditipnal logic from a given element
301 * @param array $item
302 * @return void
303 */
304 protected function extractConditionalLogic($item)
305 {
306 // If container like element, then recurse
307 if (isset($item['columns'])) {
308 $containerConditions = false;
309 if (isset($item['settings']['conditional_logics'])) {
310 $conditionals = $item['settings']['conditional_logics'];
311 if (isset($conditionals['status'])) {
312 if ($conditionals['status'] && $conditionals['conditions']) {
313 $containerConditions = $item['settings']['conditional_logics'];
314 $this->conditions[$item['attributes']['data-name']] = $containerConditions;
315 }
316 }
317 }
318
319 foreach ($item['columns'] as $column) {
320 foreach ($column['fields'] as $field) {
321 if($containerConditions) {
322 $field['container_conditions'] = $containerConditions;
323 }
324 $this->extractConditionalLogic($field);
325 }
326 }
327 } elseif (isset($item['settings']['conditional_logics'])) {
328 $conditionals = $item['settings']['conditional_logics'];
329 if (isset($conditionals['status'])) {
330 if ($conditionals['status'] && $conditionals['conditions']) {
331 $this->conditions[$item['attributes']['data-name']] = $item['settings']['conditional_logics'];
332 }
333 }
334 if(isset($item['container_conditions'])) {
335 if(!isset($this->conditions[$item['attributes']['data-name']])) {
336 $this->conditions[$item['attributes']['data-name']] = [
337 'conditions' => [],
338 'status' => false,
339 'type' => 'any'
340 ];
341 }
342 $this->conditions[$item['attributes']['data-name']]['container_condition'] = $item['container_conditions'];
343 }
344 }
345 }
346
347 /**
348 * Build attributes for any html element
349 * @param array $attributes
350 * @return string [Compiled key='value' attributes]
351 */
352 protected function buildAttributes($attributes, $form = null)
353 {
354 $atts = '';
355 foreach ($attributes as $key => $value) {
356 if ($value || $value === 0 || $value === '0') {
357 $value = htmlspecialchars($value);
358 $atts .= $key.'="'.$value.'" ';
359 }
360 }
361 return $atts;
362 }
363 }
364