PluginProbe
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder / 3.3.1
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder v3.3.1
3.3.1 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 All 138 releases
← All changes | includes/Core/Integration/Integrations.php +308 -149 1.93.3.1 View file →
@@ -5,186 +5,345 @@
5 5 * @package BitForms
6 6 */
7 7
8 8 namespace BitCode\BitForm\Core\Integration;
9 +
9 10 use BitCode\BitForm\Core\Database\FormEntryModel;
10 11 use BitCode\BitForm\Core\Database\FormModel;
12 +use BitCode\BitForm\Core\Util\ApiResponse;
13 +use BitCode\BitForm\Core\Util\IpTool;
14 +use BitCode\BitForm\Core\Util\Log;
11 15 use BitCode\BitForm\Core\Util\SmartTags;
16 +use BitCode\BitForm\Core\Util\Utilities;
12 17 /**
13 18 * Provides details of available integration and helps to
14 19 * execute available integrations
15 20 */
16 21
17 -use WP_Error;
18 22 use FilesystemIterator;
19 23
20 24 final class Integrations
21 25 {
22 - public $integrations = array();
26 + public $integrations = [];
27 + private static $_instance = null;
23 28
24 - /**
25 - * Undocumented function
26 - *
27 - * @return all
28 - */
29 - public function getAllIntegrations()
30 - {
31 - return $this->allIntegrations();
29 + /**
30 + * Undocumented function
31 + */
32 + public static function getInstance()
33 + {
34 + if (null === self::$_instance) {
35 + self::$_instance = new Integrations();
32 36 }
33 - /**
34 - * Undocumented function
35 - *
36 - * @return void
37 - */
38 - protected function allIntegrations()
39 - {
40 - $dirs = new FilesystemIterator(__DIR__);
41 - foreach ($dirs as $dirInfo) {
42 - if ($dirInfo->isDir()) {
43 - $integartionBaseName = basename($dirInfo);
44 - if (
45 - file_exists(__DIR__ . '/' . $integartionBaseName)
46 - && file_exists(__DIR__ . '/' . $integartionBaseName . '/' . $integartionBaseName . 'Handler.php')
47 - ) {
48 - $integrations[] = $integartionBaseName;
49 - }
50 - }
37 + return self::$_instance;
38 + }
39 +
40 + /**
41 + * Undocumented function
42 + *
43 + * @return array
44 + */
45 + public function getAllIntegrations()
46 + {
47 + return $this->allIntegrations();
48 + }
49 +
50 + /**
51 + * Undocumented function
52 + *
53 + * @return array
54 + */
55 + protected function allIntegrations()
56 + {
57 + $dirs = new FilesystemIterator(__DIR__);
58 + foreach ($dirs as $dirInfo) {
59 + if ($dirInfo->isDir()) {
60 + $integrationsBaseName = basename($dirInfo);
61 + if (
62 + file_exists(__DIR__ . '/' . $integrationsBaseName)
63 + && file_exists(__DIR__ . '/' . $integrationsBaseName . '/' . $integrationsBaseName . 'Handler.php')
64 + ) {
65 + $integrations[] = $integrationsBaseName;
51 66 }
52 - return $integrations;
67 + }
53 68 }
54 - /**
55 - * Checks a Integration Exists or not
56 - *
57 - * @param String $name Name of Integration
58 - * @return boolean
59 - */
60 - protected static function isExists($name)
61 - {
62 - if (file_exists(__DIR__ . '/' . $name) && file_exists(__DIR__ . '/' . $name . '/' . $name . 'Handler.php')) {
63 - return __NAMESPACE__ . "\\{$name}\\{$name}Handler";
64 - } else if (class_exists("BitCode\\BitFormPro\\Integration\\{$name}\\{$name}Handler")) {
65 - return "BitCode\\BitFormPro\\Integration\\{$name}\\{$name}Handler";
66 - } else {
67 - return false;
68 - }
69 + return $integrations;
70 + }
71 +
72 + /**
73 + * Checks a Integration Exists or not
74 + *
75 + * @param string $name Name of Integration
76 + * @return boolean | string
77 + */
78 + protected static function isExists($name)
79 + {
80 + $path = Utilities::getRealPath(__DIR__, $name);
81 + if (!empty($path) && $fileName = Utilities::getRealPath(__DIR__ . "/{$path}", "{$name}Handler.php")) {
82 + $className = Utilities::getFileNameExceptExtension($fileName);
83 + return __NAMESPACE__ . "\\{$path}\\{$className}";
69 84 }
70 - /**
71 - * This function helps to get single intgration information
72 - *
73 - * @return bool setIntegration()
74 - */
75 - public function getIntegration($integartionBaseName)
76 - {
77 - return $this->setIntegration($integartionBaseName);
85 +
86 + if (!defined('BITFORMPRO_PLUGIN_DIR_PATH')) {
87 + return false;
78 88 }
79 89
80 - public function registerAjax()
81 - {
82 - $dirs = new FilesystemIterator(__DIR__);
83 - foreach ($dirs as $dirInfo) {
84 - if ($dirInfo->isDir()) {
85 - $integartionBaseName = basename($dirInfo);
86 - if (
87 - file_exists(__DIR__ . '/' . $integartionBaseName)
88 - && file_exists(__DIR__ . '/' . $integartionBaseName . '/' . $integartionBaseName . 'Handler.php')
89 - ) {
90 - $integration = __NAMESPACE__ . "\\{$integartionBaseName}\\{$integartionBaseName}Handler";
91 - if (method_exists($integration, 'registerAjax')) {
92 - $integration::registerAjax();
93 - // (new $integration(0, 0))->registerAjax();
94 - }
95 - /* $handler = new $integration($integrationID, $formID);
96 - $handler->execute($integrationHandler, $integrationDetails, $fieldValues); */
97 - }
98 - }
90 + $proPath = BITFORMPRO_PLUGIN_DIR_PATH . '/includes/Integration';
91 + $proNamespace = 'BitCode\\BitFormPro\\Integration';
92 + $path = Utilities::getRealPath($proPath, $name);
93 + if (!empty($path) && $fileName = Utilities::getRealPath("{$proPath}/{$path}", "{$name}Handler.php")) {
94 + $className = Utilities::getFileNameExceptExtension($fileName);
95 + return "{$proNamespace}\\{$path}\\{$className}";
96 + }
97 +
98 + return false;
99 + }
100 +
101 + /**
102 + * This function helps to get single integration information
103 + *
104 + * @return bool setIntegration()
105 + */
106 + public function getIntegration($integrationBaseName)
107 + {
108 + return $this->setIntegration($integrationBaseName);
109 + }
110 +
111 + public function registerAjax()
112 + {
113 + $dirs = new FilesystemIterator(__DIR__);
114 + foreach ($dirs as $dirInfo) {
115 + if ($dirInfo->isDir()) {
116 + $integrationBaseName = basename($dirInfo);
117 + if (
118 + file_exists(__DIR__ . '/' . $integrationBaseName)
119 + && file_exists(__DIR__ . '/' . $integrationBaseName . '/' . $integrationBaseName . 'Handler.php')
120 + ) {
121 + $integration = __NAMESPACE__ . "\\{$integrationBaseName}\\{$integrationBaseName}Handler";
122 + if (method_exists($integration, 'registerAjax')) {
123 + $integration::registerAjax();
124 + // (new $integration(0, 0))->registerAjax();
125 + }
126 + /* $handler = new $integration($integrationID, $formID);
127 + $handler->execute($integrationHandler, $integrationDetails, $fieldValues); */
99 128 }
129 + }
100 130 }
131 + }
101 132
102 - protected static function entryDeleted($formId,$entryId){
103 - $formModel = new FormModel();
104 - $formContent = $formModel->get(
105 - [
106 - "id",
107 - "form_content",
108 - ],
109 - array(
110 - 'id' => $formId,
111 - )
133 + protected static function entryDeleted($formId, $entryId)
134 + {
135 + $formModel = new FormModel();
136 + $formContent = $formModel->get(
137 + [
138 + 'id',
139 + 'form_content',
140 + ],
141 + [
142 + 'id' => $formId,
143 + ]
144 + );
145 + if (!is_wp_error($formContent)) {
146 + $content = \json_decode($formContent[0]->form_content);
147 + if (isset($content->additional->enabled->submission)) {
148 + global $wpdb;
149 + $prefix = $wpdb->prefix;
150 + $formEntryModel = new FormEntryModel();
151 + $formEntryModel->bulkDelete(
152 + [
153 + "`{$prefix}bitforms_form_entries`.`id`" => $entryId,
154 + "`{$prefix}bitforms_form_entries`.`form_id`" => $formId,
155 + ]
112 156 );
113 - if(!is_wp_error($formContent)){
114 - $content = \json_decode($formContent[0]->form_content);
115 - if(isset($content->additional->enabled->submission)){
116 - global $wpdb;
117 - $prefix = $wpdb->prefix;
118 - $formEntryModel = new FormEntryModel();
119 - $formEntryModel->bulkDelete(
120 - array(
121 - "`{$prefix}bitforms_form_entries`.`id`" => $entryId,
122 - "`{$prefix}bitforms_form_entries`.`form_id`" => $formId,
123 - )
124 - );
125 - }
157 + }
158 + }
159 + }
160 +
161 + public static function specialTagFields($fieldMap)
162 + {
163 + $specialTagFieldValue = [];
164 +
165 + foreach ($fieldMap as $value) {
166 + $triggerValue = $value->formField;
167 + $specialTagFieldValue[$value->formField] = SmartTags::getSmartTagValue($triggerValue);
168 + }
169 + return $specialTagFieldValue;
170 + }
171 +
172 + /**
173 + * This function helps to execute Integration
174 + *
175 + * @param array $integrations List of integration to execute.
176 + * Element will be json string like {"id":1}
177 + * @param array $fieldValues Values of submitted fields
178 + * @param integer $formID ID of current form
179 + *
180 + * @return void Nothing to return
181 + */
182 + public static function executeIntegrations($integrations, $fieldValues, $formID, $logID = null, $entryID = 0)
183 + {
184 + $integrationHandler = new IntegrationHandler($formID);
185 + $logResponse = new ApiResponse();
186 + $intThatNeedNoFileHandling = ['ACF', 'MetaBox', 'Pods']; //these takes raw file and upload it
187 + $baseFieldValues = $fieldValues;
188 + $entryDetails = [
189 + 'formId' => $formID,
190 + 'entryId' => $entryID,
191 + 'fieldValues' => $fieldValues
192 + ];
193 + if (is_array($integrations)) {
194 + foreach ($integrations as $integrationIDStr) {
195 + if (!is_string($integrationIDStr)) {
196 + return;
126 197 }
127 - }
198 + $currentFieldValues = $baseFieldValues;
199 + $integrationID = intval(Utilities::jsonObj($integrationIDStr)->id ?? 0, 10);
200 + if (!empty($integrationID) && is_int($integrationID)) {
201 + $integrationResult
202 + = $integrationHandler->getAIntegration($integrationID);
203 + $integrationDetails = is_wp_error($integrationResult) ? null : $integrationResult[0];
204 + // Honor enable/disable: a disabled integration is never executed.
205 + if (!is_null($integrationDetails) && isset($integrationDetails->status) && empty($integrationDetails->status)) {
206 + continue;
207 + }
208 + $integrationName = is_null($integrationDetails) ? null : ucfirst(str_replace(' ', '', $integrationDetails->integration_type));
209 + if ('Brevo(SendinBlue)' === $integrationName) {
210 + $integrationName = 'SendinBlue';
211 + }
212 + if (!is_null($integrationName) && static::isExists($integrationName)) {
213 + if (!in_array($integrationName, $intThatNeedNoFileHandling)) {
214 + $currentFieldValues = IntegrationHandler::handleFileUrl($currentFieldValues, $formID, $entryID);
215 + }
216 + $integration = static::isExists($integrationName);
217 + $handler = new $integration($integrationID, $formID);
218 + $integDetails = is_string($integrationDetails->integration_details) ? json_decode($integrationDetails->integration_details) : $integrationDetails->integration_details;
219 + if (isset($integDetails->field_map)) {
220 + $sptagData = self::specialTagFields($integDetails->field_map);
221 + $currentFieldValues = $currentFieldValues + $sptagData;
222 + }
223 + // fresh time budget per handler: a chain of slow integrations (30s HTTP
224 + // timeout each) must not be killed by max_execution_time mid-loop
225 + if (\function_exists('set_time_limit') && false === strpos((string) ini_get('disable_functions'), 'set_time_limit')) {
226 + set_time_limit(60);
227 + }
228 + try {
229 + $handler->execute($integrationHandler, $integrationDetails, $currentFieldValues, $entryID, $logID);
230 + } catch (\Throwable $executionError) {
231 + // one failing integration must not abort the remaining ones
232 + Log::debug_log('[+] Integration execution threw: ' . $executionError->getMessage());
233 + $logResponse->apiResponse(
234 + $logID,
235 + $integrationID,
236 + ['type' => 'record', 'type_name' => $integrationName ?: 'Integration'],
237 + 'errors',
238 + $executionError->getMessage(),
239 + $entryDetails
240 + );
241 + }
242 + } else {
243 + do_action('bitform_integration_run_failure', $integrationID, $formID);
128 244
129 - public static function specialTagFields($fieldMap)
130 - {
131 - $specialTagFieldValue = [];
132 - $data = SmartTags::getPostUserData(true);
133 - $specialTagFields = SmartTags::smartTagFieldKeys();
245 + $errorMsg = apply_filters('bitform_filter_integration_run_failure_message', __('Integration execution failed', 'bit-form'), $integrationID, $formID);
134 246
135 - foreach ($fieldMap as $value) {
136 - $triggerValue = $value->formField;
137 - if (in_array($triggerValue, $specialTagFields)) {
138 - $specialTagFieldValue[$value->formField] = SmartTags::getSmartTagValue($triggerValue, $data);
139 - }
247 + Log::debug_log('[+] Integration execution failed: ' . $errorMsg);
248 +
249 + $logResponse->apiResponse(
250 + $logID,
251 + $integrationID,
252 + ['type' => 'record', 'type_name' => $integrationName || 'Integration'],
253 + 'errors',
254 + $errorMsg,
255 + $entryDetails
256 + );
257 + }
140 258 }
141 - return $specialTagFieldValue;
259 + }
142 260 }
261 + }
143 262
144 - /**
145 - * This function helps to execute Integration
146 - *
147 - * @param Array $integrations List of integrstion to execute.
148 - * Element will be json string like {"id":1}
149 - * @param Array $fieldValues Values of submitted fields
150 - * @param Integer $formID ID of current form
151 - *
152 - * @return void Nothing to return
153 - */
154 - public static function executeIntegrations($integrations, $fieldValues, $formID, $logID=null, $entryID = 0)
155 - {
156 - $integrationHandler = new IntegrationHandler($formID);
157 - if (is_array($integrations)) {
158 - foreach ($integrations as $integrationIDStr) {
159 - $integrationID = intval(json_decode($integrationIDStr)->id, 10);
160 - if (!empty($integrationID) && is_int($integrationID)) {
161 - $integrationResult
162 - = $integrationHandler->getAIntegration($integrationID);
163 - $integrationDetails = is_wp_error($integrationResult) ? null : $integrationResult[0];
164 - $integrationName = is_null($integrationDetails) ? null : ucfirst(str_replace(' ', '', $integrationDetails->integration_type));
165 - if (!is_null($integrationName) && static::isExists($integrationName)) {
166 - $integration = static::isExists($integrationName);
167 - $handler = new $integration($integrationID, $formID);
168 - $integDetails = is_string($integrationDetails->integration_details) ? json_decode($integrationDetails->integration_details) : $integrationDetails->integration_details;
169 - if (isset($integDetails->field_map)) {
170 - $sptagData = self::specialTagFields($integDetails->field_map);
171 - $fieldValues = $fieldValues + $sptagData;
172 - }
173 - $handler->execute($integrationHandler, $integrationDetails, $fieldValues, $entryID, $logID);
174 - }
175 - }
176 - }
177 - }
263 + public static function integrationExecutionHelper($integrations, $fieldValue, $formID, $entryID, $logID)
264 + {
265 + if (empty($integrations) || empty($formID)) {
266 + return;
178 267 }
268 + $trnasientData = get_transient("bitform_trigger_transient_{$entryID}");
269 + $trnasientData = is_string($trnasientData) ? json_decode($trnasientData) : $trnasientData;
270 + if (!empty($trnasientData['fields'])) {
271 + $fieldValue = array_merge($fieldValue, $trnasientData['fields']);
272 + }
273 + foreach ($integrations as $key => $value) {
274 + self::executeIntegrations($value, $fieldValue, $formID, $logID, $entryID);
275 + }
276 + self::entryDeleted($formID, $entryID);
277 + }
179 278
180 - public static function integrationExecutionHelper($integrations, $fieldValue, $formID, $entryID, $logID)
181 - {
182 - if (empty($integrations) || empty($formID)) {
183 - return;
184 - }
185 - foreach ($integrations as $key => $value) {
186 - self::executeIntegrations($value, $fieldValue, $formID, $logID, $entryID);
187 - }
188 - self::entryDeleted($formID,$entryID);
279 + /**
280 + * This function helps to save connected integration app
281 + *
282 + * @return wp_error | mixed
283 + */
284 + public function saveConnectedIntegrationApp($appConfig)
285 + {
286 + // error_log('[+] saveConnectedIntegrationApp: ' . print_r($appConfig, true));
287 + $connectionName = $appConfig->name;
288 + $connectionType = $appConfig->type;
289 + // $connectionDetails = wp_json_encode($appConfig);
290 +
291 + if (empty($appConfig->details)) {
292 + unset($appConfig->name, $appConfig->id);
293 +
294 + $connectionDetails = !is_string($appConfig) ?
295 + wp_json_encode($appConfig) : $appConfig;
296 + } else {
297 + $connectionDetails = !is_string($appConfig->details) ?
298 + wp_json_encode($appConfig->details) : $appConfig->details;
189 299 }
300 + $connectionCategory = 'connected_integration_apps';
301 +
302 + // saveIntegration reads user_details['id'|'ip'|'time']; without them the insert
303 + // raises null-offset warnings and stores null user_id/created_at
304 + $integrationHandler = new IntegrationHandler(0, IpTool::getUserDetail());
305 +
306 + return $integrationHandler->saveIntegration($connectionName, $connectionType, $connectionDetails, $connectionCategory);
307 + }
308 +
309 + // get connectd integration app
310 + public function getConnectedIntegrationApp($integration_type = null)
311 + {
312 + $connectionCategory = 'connected_integration_apps';
313 +
314 + $integrationHandler = new IntegrationHandler(0);
315 + $allConnectedIntegApps = $integrationHandler->getAllIntegration($connectionCategory, $integration_type);
316 +
317 + if (!is_wp_error($allConnectedIntegApps)) {
318 + foreach ($allConnectedIntegApps as $integrationkey => $integrationValue) {
319 + $integrationData = [
320 + 'id' => $integrationValue->id,
321 + 'name' => $integrationValue->integration_name,
322 + 'type' => $integrationValue->integration_type,
323 + ];
324 + $allConnectedIntegApps[$integrationkey]->integration_details = wp_json_encode(array_merge(
325 + $integrationData,
326 + is_string($integrationValue->integration_details) ?
327 + (array) json_decode($integrationValue->integration_details) :
328 + $integrationValue->integration_details
329 + ));
330 + }
331 + }
332 + return $allConnectedIntegApps;
333 + }
334 +
335 + public function deleteConnectedApp($appId)
336 + {
337 + $integrationHandler = new IntegrationHandler(0);
338 +
339 + return $integrationHandler->deleteIntegration($appId);
340 + }
341 +
342 + public function renameConnectedApp($appId, $name)
343 + {
344 + // User details carry the time renameConnectedApp() stamps into updated_at.
345 + $integrationHandler = new IntegrationHandler(0, IpTool::getUserDetail());
346 +
347 + return $integrationHandler->renameConnectedApp($appId, $name);
348 + }
190 349 }