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

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