PluginProbe
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder / 3.2.2
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder v3.2.2
V-3.3.0 3.2.2 3.2.1 3.2.0 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 V3.0.3 V3.0.2 -3.0.1 V_3.0.0 1.1.1 1.1.8 1.2 1.3 1.4 1.4.18 1.5.2 1.9 2.0 2.10.0 2.10.1 2.10.2 All 137 releases
bit-form / includes / Core / WorkFlow / Actions.php

Actions.php in Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder 3.2.2, at includes/Core/WorkFlow/Actions.php

304 lines 11.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace BitCode\BitForm\Core\WorkFlow;
4
5 use BitCode\BitForm\Core\Integration\IntegrationHandler;
6 use BitCode\BitForm\Core\Messages\SuccessMessageHandler;
7 use BitCode\BitForm\Core\Util\Utilities;
8
9 final class Actions
10 {
11 private static $_formID;
12
13 public function __construct($formId)
14 {
15 static::$_formID = $formId;
16 }
17
18 /**
19 * Resolve the field key a workflow action points at.
20 *
21 * Both arguments come straight out of stored workflow/form JSON, so neither shape is guaranteed
22 * — hence the runtime checks rather than type hints.
23 *
24 * @param mixed $actionDetail one action row decoded from the workflow JSON
25 * @param mixed $fieldData field map keyed by field name
26 *
27 * @return string|null null when the action points at a field the form no longer has
28 */
29 private static function resolveFieldKey($actionDetail, $fieldData)
30 {
31 if (!is_object($actionDetail) || !isset($actionDetail->field) || !\is_array($fieldData)) {
32 return null;
33 }
34 $field = $actionDetail->field;
35 if (!\is_string($field) && !\is_int($field)) {
36 return null;
37 }
38 if (!isset($fieldData[$field]) || !\is_array($fieldData[$field]) || !isset($fieldData[$field]['key'])) {
39 return null;
40 }
41 $key = $fieldData[$field]['key'];
42
43 return \is_string($key) || \is_int($key) ? (string) $key : null;
44 }
45
46 public function setValue($actionDetail, $fieldData, $fields)
47 {
48 $fk = self::resolveFieldKey($actionDetail, $fieldData);
49 if (null !== $fk && isset($fields->{$fk}) && !empty($actionDetail->val)) {
50 $fieldType = isset($fields->{$fk}->typ) ? $fields->{$fk}->typ : '';
51 $evalMathExpr = preg_match('/month|date/', (string) $fieldType);
52 $fields->{$fk}->val = '';
53 $actionValue = Helper::replaceFieldWithValue($actionDetail->val, $fieldData, !(bool) $evalMathExpr);
54 $fields->{$fk}->val = $actionValue;
55 $fieldData[$actionDetail->field]['value'] = $actionValue;
56 }
57 return [$fields, $fieldData];
58 }
59
60 public function getActionValue($actionDetail, $fieldData, $fields)
61 {
62 $actionValue = '';
63 $fk = self::resolveFieldKey($actionDetail, $fieldData);
64 if (null !== $fk && isset($fields->{$fk}) && !empty($actionDetail->val)) {
65 $fieldType = isset($fields->{$fk}->typ) ? $fields->{$fk}->typ : '';
66 $evalMathExpr = preg_match('/month|date/', (string) $fieldType);
67 $fields->{$fk}->val = '';
68 $actionValue = Helper::replaceFieldWithValue($actionDetail->val, $fieldData, !(bool) $evalMathExpr);
69 }
70 return $actionValue;
71 }
72
73 public function getActiveListIndex($actionDetail, $fieldData, $fields)
74 {
75 $activeList = $this->getActionValue($actionDetail, $fieldData, $fields);
76 $activeListIndex = 0;
77 $fk = self::resolveFieldKey($actionDetail, $fieldData);
78 if (null === $fk || !isset($fields->{$fk}->optionsList)) {
79 return $activeListIndex;
80 }
81 $optionsList = $fields->{$fk}->optionsList;
82 if (!\is_array($optionsList) && !\is_object($optionsList)) {
83 return $activeListIndex;
84 }
85 foreach ($optionsList as $key => $optionObj) {
86 $valueArr = (array) $optionObj;
87 if (empty($valueArr)) {
88 continue;
89 }
90 $listName = array_keys($valueArr)[0];
91 if ($listName === $activeList) {
92 $activeListIndex = $key;
93 break;
94 }
95 }
96
97 return $activeListIndex;
98 }
99
100 public function show($fields, $fieldData, $actionDetail)
101 {
102 $fk = self::resolveFieldKey($actionDetail, $fieldData);
103 if (null === $fk || !isset($fields->{$fk})) {
104 return;
105 }
106 Helper::setNestedProperty($fields, "{$fk}->valid->hide", false);
107 if (isset($fields->{$fk}->typ) && 'hidden' === $fields->{$fk}->typ) {
108 $fields->{$fk}->typ = 'text';
109 }
110 }
111
112 public function setFieldProperty($actions, $fieldData, $fields)
113 {
114 if (empty($actions)) {
115 return [$fields, $fieldData];
116 }
117 foreach ($actions as $actionDetail) {
118 // resolveFieldKey() must run *before* $fields is indexed: the old condition built the
119 // dynamic property name from $fieldData[...]['key'] inside its own isset(), so the missing
120 // key warned before isset() ever got a chance to short-circuit.
121 $fk = self::resolveFieldKey($actionDetail, $fieldData);
122 if (null === $fk || empty($actionDetail->action) || !isset($fields->{$fk}) || empty($fields->{$fk})) {
123 continue;
124 }
125 switch ($actionDetail->action) {
126 case 'value':
127 $data = $this->setValue($actionDetail, $fieldData, $fields);
128 $fields = $data[0];
129 $fieldData = $data[1];
130 break;
131 case 'hide':
132 Helper::setNestedProperty($fields, "{$fk}->valid->hide", true);
133 break;
134 case 'disable':
135 Helper::setNestedProperty($fields, "{$fk}->valid->disabled", true);
136 break;
137 case 'show':
138 $this->show($fields, $fieldData, $actionDetail);
139 break;
140 case 'enable':
141 Helper::setNestedProperty($fields, "{$fk}->valid->disabled", false);
142 break;
143 case 'readonly':
144 Helper::setNestedProperty($fields, "{$fk}->valid->readonly", true);
145 break;
146 case 'writeable':
147 Helper::setNestedProperty($fields, "{$fk}->valid->readonly", false);
148 break;
149 case 'required':
150 Helper::setNestedProperty($fields, "{$fk}->valid->required", true);
151 break;
152 case 'limit':
153 Helper::setNestedProperty($fields, "{$fk}->valid->limit", true);
154 break;
155 case 'min':
156 Helper::setNestedProperty($fields, "{$fk}->valid->min", true);
157 break;
158 case 'max':
159 Helper::setNestedProperty($fields, "{$fk}->valid->max", true);
160 break;
161 case 'activelist':
162 // setNestedProperty() creates the intermediate `valid`/`config` object when a legacy
163 // field JSON does not carry one; the direct writes here used to auto-vivify it and
164 // emit an undefined-property warning on every run.
165 Helper::setNestedProperty($fields, "{$fk}->config->activeList", $this->getActiveListIndex($actionDetail, $fieldData, $fields));
166 break;
167 case 'lbl':
168 case 'ct':
169 $fields->{$fk}->lbl = $this->getActionValue($actionDetail, $fieldData, $fields);
170 break;
171 case 'sub-titl':
172 $fields->{$fk}->subtitle = $this->getActionValue($actionDetail, $fieldData, $fields);
173 break;
174 case 'hlp-txt':
175 $fields->{$fk}->helperTxt = $this->getActionValue($actionDetail, $fieldData, $fields);
176 break;
177 case 'placeholder':
178 $fields->{$fk}->ph = $this->getActionValue($actionDetail, $fieldData, $fields);
179 break;
180 case 'title':
181 $fields->{$fk}->title = $this->getActionValue($actionDetail, $fieldData, $fields);
182 break;
183 }
184 }
185 return [$fields, $fieldData];
186 }
187
188 public function setOnSubmitSetFieldValue($actions, $fieldValue)
189 {
190 if (empty($actions)) {
191 return $fieldValue;
192 }
193 foreach ($actions as $actionDetail) {
194 if (!empty($actionDetail->action) && !empty($actionDetail->field)) {
195 switch ($actionDetail->action) {
196 case 'value':
197 if (!empty($actionDetail->val)) {
198 $fieldValue[$actionDetail->field] = '';
199 $actionValue = Helper::replaceFieldWithValue($actionDetail->val, $fieldValue);
200 $fieldValue[$actionDetail->field] = $actionValue;
201 }
202 break;
203 }
204 }
205 }
206 return $fieldValue;
207 }
208
209 public function setOnFormSuccess($data, $actions, $fieldValue, $entryID)
210 {
211 if (empty($actions)) {
212 return $data;
213 }
214
215 foreach ($actions as $successActionDetail) {
216 $id = $successActionDetail->details->id;
217 if (!empty($id)) {
218 switch ($successActionDetail->type) {
219 case 'successMsg':
220 $data['workFlowReturnable'] = $this->confirmationMessage($data['workFlowReturnable'], $id, $fieldValue, $entryID);
221 break;
222 case 'redirectPage':
223 $data['workFlowReturnable'] = $this->redirectPage($data['workFlowReturnable'], $id, $fieldValue);
224 break;
225 case 'webHooks':
226 if (!$data['isWebHookQueued']) {
227 $data['isWebHookQueued'] = true;
228 }
229 $data['integrationsToExc'][] = $id;
230 break;
231 case 'mailNotify':
232 $data['mailData'][] = $successActionDetail->details;
233 break;
234 case 'dblOptin':
235 $data['dblOptin'][] = $successActionDetail->details;
236 break;
237 case 'integ':
238 $data['integrationsToExc'][] = $id;
239 break;
240 default:
241 break;
242 }
243 }
244 }
245 return $data;
246 }
247
248 public function confirmationMessage($workFlowReturnable, $successActionDetailId, $fieldValue, $entryID = null)
249 {
250 $id = Utilities::jsonObj($successActionDetailId)->id ?? null;
251 $messageHandler = new SuccessMessageHandler(static::$_formID);
252 $message = $messageHandler->getAMessage($id);
253 if (!is_wp_error($message) && !empty($message)) {
254 $msgConfig = Utilities::jsonObj($message[0]->message_config ?? '');
255 // Honor enable/disable: a disabled confirmation message is skipped so the default confirmation applies.
256 if (isset($msgConfig->status) && empty($msgConfig->status)) {
257 return $workFlowReturnable;
258 }
259 $messageContent = $message[0]->message_content;
260
261 // replace pdf link and password
262 if (class_exists('\BitCode\BitFormPro\Admin\DownloadFile') && !empty($entryID)) {
263 $downloadFile = new \BitCode\BitFormPro\Admin\DownloadFile();
264 $messageContent = $downloadFile->replacePdfShortCodeToLink($messageContent, static::$_formID, $entryID);
265 $messageContent = $downloadFile->replaceShortCodeToPdfPassword($messageContent, static::$_formID, $entryID);
266 }
267
268 $workFlowReturnable['message'] = Helper::replaceFieldWithValue($messageContent, $fieldValue, true, static::$_formID, true);
269 if (!empty($workFlowReturnable['message'])) {
270 $workFlowReturnable['message'] = do_shortcode($workFlowReturnable['message']);
271 }
272 $workFlowReturnable['msg_id'] = $message[0]->id;
273 $msgConfig = Utilities::jsonObj($message[0]->message_config ?? '');
274 if (!empty($msgConfig->autoHide)) {
275 $workFlowReturnable['msg_duration'] = abs(floatval($msgConfig->duration ?? 0) * 1000);
276 }
277 // expose the form's after-submission behaviour ('reset' | 'hide' | 'keep') to the frontend
278 if (isset($msgConfig->afterSubmit)) {
279 $workFlowReturnable['afterSubmit'] = $msgConfig->afterSubmit;
280 }
281 }
282 return $workFlowReturnable;
283 }
284
285 public function redirectPage($workFlowReturnable, $successActionDetailId, $fieldValue)
286 {
287 $id = Utilities::jsonObj($successActionDetailId)->id ?? null;
288 $integrationHandler = new IntegrationHandler(static::$_formID);
289 $redirectPage = $integrationHandler->getAIntegration($id, 'form', 'redirectPage');
290 if (!is_wp_error($redirectPage) && !empty($redirectPage)) {
291 // Honor enable/disable: a disabled redirect is skipped.
292 if (isset($redirectPage[0]->status) && empty($redirectPage[0]->status)) {
293 return $workFlowReturnable;
294 }
295 $url = Utilities::jsonObj($redirectPage[0]->integration_details ?? '')->url ?? '';
296 if (!empty($url)) {
297 $url = Helper::replaceFieldWithValue($url, $fieldValue);
298 }
299 $workFlowReturnable['redirectPage'] = empty($url) ? false : esc_url_raw($url);
300 }
301 return $workFlowReturnable;
302 }
303 }
304