Completed
Push — master ( 48bc46...861ddb )
by Jonathan
04:46 queued 34s
created

Object_Sync_Sf_Mapping::delete_fieldmap()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 7
c 0
b 0
f 0
dl 0
loc 9
rs 10
cc 2
nc 2
nop 1
1
<?php
2
/**
3
 * Class file for the Object_Sync_Sf_Mapping class.
4
 *
5
 * @file
6
 */
7
8
if ( ! class_exists( 'Object_Sync_Salesforce' ) ) {
9
	die();
10
}
11
12
/**
13
 * Map objects and records between WordPress and Salesforce
14
 */
15
class Object_Sync_Sf_Mapping {
16
17
	protected $wpdb;
18
	protected $version;
19
	protected $slug;
20
	protected $logging;
21
	protected $option_prefix;
22
23
	protected $fieldmap_table;
24
	protected $object_map_table;
25
26
	public $sync_off;
27
	public $sync_wordpress_create;
28
	public $sync_wordpress_update;
29
	public $sync_wordpress_delete;
30
	public $sync_sf_create;
31
	public $sync_sf_update;
32
	public $sync_sf_delete;
33
	public $wordpress_events;
34
	public $salesforce_events;
35
36
	public $direction_wordpress_sf;
37
	public $direction_sf_wordpress;
38
	public $direction_sync;
39
40
	public $direction_wordpress;
41
	public $direction_salesforce;
42
43
	public $salesforce_default_record_type;
44
45
	public $array_delimiter;
46
	public $array_types_from_salesforce;
47
	public $date_types_from_salesforce;
48
	public $int_types_from_salesforce;
49
50
	public $name_length;
51
52
	public $status_success;
53
	public $status_error;
54
55
	/**
56
	 * Constructor which sets up links between the systems
57
	 *
58
	 * @param object $wpdb A WPDB object.
59
	 * @param string $version The plugin version.
60
	 * @param string $slug The plugin slug.
61
	 * @param object $logging Object_Sync_Sf_Logging.
62
	 * @param string $option_prefix The plugin option prefix
63
	 * @throws \Exception
64
	 */
65
	public function __construct( $wpdb, $version, $slug, $logging, $option_prefix = '' ) {
66
		$this->wpdb          = $wpdb;
67
		$this->version       = $version;
68
		$this->slug          = $slug;
69
		$this->option_prefix = isset( $option_prefix ) ? $option_prefix : 'object_sync_for_salesforce_';
70
		$this->logging       = $logging;
71
72
		$this->fieldmap_table   = $this->wpdb->prefix . 'object_sync_sf_field_map';
73
		$this->object_map_table = $this->wpdb->prefix . 'object_sync_sf_object_map';
74
75
		/*
76
		 * These parameters are how we define when syncing should occur on each field map.
77
		 * They get used in the admin settings, as well as the push/pull methods to see if something should happen.
78
		 * It is unclear why the Drupal module used bit flags, but it seems reasonable to keep the convention.
79
		*/
80
		$this->sync_off              = 0x0000;
81
		$this->sync_wordpress_create = 0x0001;
82
		$this->sync_wordpress_update = 0x0002;
83
		$this->sync_wordpress_delete = 0x0004;
84
		$this->sync_sf_create        = 0x0008;
85
		$this->sync_sf_update        = 0x0010;
86
		$this->sync_sf_delete        = 0x0020;
87
88
		// Define which events are initialized by which system.
89
		$this->wordpress_events  = array( $this->sync_wordpress_create, $this->sync_wordpress_update, $this->sync_wordpress_delete );
90
		$this->salesforce_events = array( $this->sync_sf_create, $this->sync_sf_update, $this->sync_sf_delete );
91
92
		// Constants for the directions to map things.
93
		$this->direction_wordpress_sf = 'wp_sf';
94
		$this->direction_sf_wordpress = 'sf_wp';
95
		$this->direction_sync         = 'sync';
96
97
		$this->direction_wordpress  = array( $this->direction_wordpress_sf, $this->direction_sync );
98
		$this->direction_salesforce = array( $this->direction_sf_wordpress, $this->direction_sync );
99
100
		// This is used when we map a record with default or Master.
101
		$this->salesforce_default_record_type = 'default';
102
103
		// Salesforce has multipicklists and they have a delimiter.
104
		$this->array_delimiter = ';';
105
		// What data types in Salesforce should be an array?
106
		$this->array_types_from_salesforce = array( 'multipicklist' );
107
		// What data types in Salesforce should be a date field?
108
		$this->date_types_from_salesforce = array( 'date', 'datetime' );
109
		// What data types in Salesforce should be an integer?
110
		$this->int_types_from_salesforce = array( 'integer', 'boolean' );
111
112
		// Max length for a mapping field.
113
		$this->name_length = 128;
114
115
		// Statuses for object sync.
116
		$this->status_success = 1;
117
		$this->status_error   = 0;
118
119
		$this->debug = get_option( $this->option_prefix . 'debug_mode', false );
0 ignored issues
show
Bug Best Practice introduced by
The property debug does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
120
121
	}
122
123
	/**
124
	 * Create a fieldmap row between a WordPress and Salesforce object
125
	 *
126
	 * @param array $posted The results of $_POST.
127
	 * @param array $wordpress_fields The fields for the WordPress side of the mapping.
128
	 * @param array $salesforce_fields The fields for the Salesforce side of the mapping.
129
	 * @throws \Exception
130
	 */
131
	public function create_fieldmap( $posted = array(), $wordpress_fields = array(), $salesforce_fields = array() ) {
132
		$data = $this->setup_fieldmap_data( $posted, $wordpress_fields, $salesforce_fields );
133
		if ( version_compare( $this->version, '1.2.5', '>=' ) ) {
134
			$data['version'] = $this->version;
135
		}
136
		$insert = $this->wpdb->insert( $this->fieldmap_table, $data );
137
		if ( 1 === $insert ) {
138
			return $this->wpdb->insert_id;
139
		} else {
140
			return false;
141
		}
142
	}
143
144
	/**
145
	 * Get one or more fieldmap rows between a WordPress and Salesforce object
146
	 *
147
	 * @param int   $id The ID of a desired mapping.
148
	 * @param array $conditions Array of key=>value to match the mapping by.
149
	 * @param bool  $reset Unused parameter.
150
	 * @return Array $map a single mapping or $mappings, an array of mappings.
151
	 * @throws \Exception
152
	 */
153
	public function get_fieldmaps( $id = null, $conditions = array(), $reset = false ) {
0 ignored issues
show
Unused Code introduced by
The parameter $reset is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

153
	public function get_fieldmaps( $id = null, $conditions = array(), /** @scrutinizer ignore-unused */ $reset = false ) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
154
		$table = $this->fieldmap_table;
155
		if ( null !== $id ) { // get one fieldmap.
156
			$map                                    = $this->wpdb->get_row( 'SELECT * FROM ' . $table . ' WHERE id = ' . $id, ARRAY_A );
157
			$map['salesforce_record_types_allowed'] = maybe_unserialize( $map['salesforce_record_types_allowed'] );
158
159
			$map['fields']        = maybe_unserialize( $map['fields'] );
160
			$map['sync_triggers'] = maybe_unserialize( $map['sync_triggers'] );
161
			return $map;
162
		} elseif ( ! empty( $conditions ) ) { // get multiple but with a limitation.
163
			$mappings    = array();
164
			$record_type = '';
165
166
			// Assemble the SQL.
167
			if ( ! empty( $conditions ) ) {
168
				$where = ' WHERE ';
169
				$i     = 0;
170
				foreach ( $conditions as $key => $value ) {
171
					if ( 'salesforce_record_type' === $key ) {
172
						$record_type = sanitize_text_field( $value );
173
					} else {
174
						$i++;
175
						if ( $i > 1 ) {
176
							$where .= ' AND ';
177
						}
178
						$where .= '`' . $key . '` = "' . $value . '"';
179
					}
180
				}
181
			} else {
182
				$where = '';
183
			}
184
185
			$mappings = $this->wpdb->get_results( 'SELECT * FROM ' . $table . $where . ' ORDER BY `weight`', ARRAY_A );
186
187
			if ( ! empty( $mappings ) ) {
188
				$mappings = $this->prepare_fieldmap_data( $mappings, $record_type );
189
			}
190
191
			return $mappings;
192
193
		} else { // get all of the mappings. ALL THE MAPPINGS.
194
195
			// if the version is greater than or equal to 1.5.0, the fieldmap table has a pull_to_drafts column
196
			if ( version_compare( $this->version, '1.5.0', '>=' ) ) {
197
				$mappings = $this->wpdb->get_results( "SELECT `id`, `label`, `wordpress_object`, `salesforce_object`, `salesforce_record_types_allowed`, `salesforce_record_type_default`, `fields`, `pull_trigger_field`, `sync_triggers`, `push_async`, `push_drafts`, `pull_to_drafts`, `weight`, `version` FROM $table", ARRAY_A ); // WPCS: unprepared SQL OK.
198
			} elseif ( version_compare( $this->version, '1.2.5', '>=' ) ) {
199
				// if the version is greater than or equal to 1.2.5, the fieldmap table has a version column
200
				$mappings = $this->wpdb->get_results( "SELECT `id`, `label`, `wordpress_object`, `salesforce_object`, `salesforce_record_types_allowed`, `salesforce_record_type_default`, `fields`, `pull_trigger_field`, `sync_triggers`, `push_async`, `push_drafts`, `weight`, `version` FROM $table", ARRAY_A ); // WPCS: unprepared SQL OK.
201
			} else {
202
				$mappings = $this->wpdb->get_results( "SELECT `id`, `label`, `wordpress_object`, `salesforce_object`, `salesforce_record_types_allowed`, `salesforce_record_type_default`, `fields`, `pull_trigger_field`, `sync_triggers`, `push_async`, `push_drafts`, `weight` FROM $table", ARRAY_A ); // WPCS: unprepared SQL OK.
203
			}
204
205
			if ( ! empty( $mappings ) ) {
206
				$mappings = $this->prepare_fieldmap_data( $mappings );
207
			}
208
209
			return $mappings;
210
		} // End if().
211
	}
212
213
	/**
214
	 * For a mapping, get the fieldmaps associated with it.
215
	 *
216
	 * @param Array $mapping The mapping for which we are getting the fieldmaps.
217
	 * @param Array $directions The direction of the mapping: from WP to SF or vice-versa.
218
	 * @see Object_Sync_Sf_Salesforce_Pull::get_pull_query()
219
	 *
220
	 * @return Array of mapped fields
221
	 */
222
	public function get_mapped_fields( $mapping, $directions = array() ) {
223
		$mapped_fields = array();
224
		foreach ( $mapping['fields'] as $fields ) {
225
			if ( empty( $directions ) || in_array( $fields['direction'], $directions, true ) ) {
226
227
				// in version 1.2.0, we provided an option for API name vs label for Salesforce fields
228
				if ( version_compare( $this->version, '1.2.0', '>=' ) && isset( $fields['salesforce_field']['name'] ) ) {
229
					$array_key = 'name';
230
				} else {
231
					$array_key = 'label';
232
				}
233
234
				// Some field map types (Relation) store a collection of SF objects.
235
				if ( is_array( $fields['salesforce_field'] ) && ! isset( $fields['salesforce_field'][ $array_key ] ) ) {
236
					foreach ( $fields['salesforce_field'] as $sf_field ) {
237
						$mapped_fields[ $sf_field[ $array_key ] ] = $sf_field[ $array_key ];
238
					}
239
				} else { // The rest are just a name/value pair.
240
					$mapped_fields[ $fields['salesforce_field'][ $array_key ] ] = $fields['salesforce_field'][ $array_key ];
241
				}
242
			}
243
		}
244
245
		if ( ! empty( $this->get_mapped_record_types ) ) {
246
			$mapped_fields['RecordTypeId'] = 'RecordTypeId';
247
		}
248
249
		return $mapped_fields;
250
	}
251
252
	/**
253
	 * Get the mapped record types for a given mapping.
254
	 *
255
	 * @param Array $mapping A mapping from which we wish to estract the record type.
256
	 * @return Array of mappings. Empty if the mapping's record type is default, else full of the record types.
257
	 */
258
	public function get_mapped_record_types( $mapping ) {
259
		return $mapping['salesforce_record_type_default'] === $this->salesforce_default_record_type ? array() : array_filter( maybe_unserialize( $mapping['salesforce_record_types_allowed'] ) );
260
	}
261
262
	/**
263
	 * Update a fieldmap row between a WordPress and Salesforce object
264
	 *
265
	 * @param array $posted It's $_POST.
266
	 * @param array $wordpress_fields The fields for the WordPress side of the mapping.
267
	 * @param array $salesforce_fields The fields for the Salesforce side of the mapping.
268
	 * @param int   $id The ID of the mapping.
269
	 * @return $map
0 ignored issues
show
Documentation Bug introduced by
The doc comment $map at position 0 could not be parsed: Unknown type name '$map' at position 0 in $map.
Loading history...
270
	 * @throws \Exception
271
	 */
272
	public function update_fieldmap( $posted = array(), $wordpress_fields = array(), $salesforce_fields = array(), $id = '' ) {
273
		$data = $this->setup_fieldmap_data( $posted, $wordpress_fields, $salesforce_fields );
274
		if ( version_compare( $this->version, '1.2.5', '>=' ) && ! isset( $data['updated'] ) ) {
275
			$data['version'] = $this->version;
276
		}
277
		$update = $this->wpdb->update(
278
			$this->fieldmap_table,
279
			$data,
280
			array(
281
				'id' => $id,
282
			)
283
		);
284
		if ( false === $update ) {
285
			return false;
286
		} else {
287
			return true;
288
		}
289
	}
290
291
	/**
292
	 * Setup fieldmap data
293
	 * Sets up the database entry for mapping the object types between Salesforce and WordPress
294
	 *
295
	 * @param array $posted It's $_POST.
296
	 * @param array $wordpress_fields The fields for the WordPress side of the mapping.
297
	 * @param array $salesforce_fields The fields for the Salesforce side of the mapping.
298
	 * @return $data
0 ignored issues
show
Documentation Bug introduced by
The doc comment $data at position 0 could not be parsed: Unknown type name '$data' at position 0 in $data.
Loading history...
299
	 */
300
	private function setup_fieldmap_data( $posted = array(), $wordpress_fields = array(), $salesforce_fields = array() ) {
301
		$data = array(
302
			'label'             => $posted['label'],
303
			'name'              => sanitize_title( $posted['label'] ),
304
			'salesforce_object' => $posted['salesforce_object'],
305
			'wordpress_object'  => $posted['wordpress_object'],
306
		);
307
		if ( isset( $posted['wordpress_field'] ) && is_array( $posted['wordpress_field'] ) && isset( $posted['salesforce_field'] ) && is_array( $posted['salesforce_field'] ) ) {
308
			$setup['fields'] = array();
309
			foreach ( $posted['wordpress_field'] as $key => $value ) {
310
				$method_key = array_search( $value, array_column( $wordpress_fields, 'key' ), true );
311
				if ( ! isset( $posted['direction'][ $key ] ) ) {
312
					$posted['direction'][ $key ] = 'sync';
313
				}
314
				if ( ! isset( $posted['is_prematch'][ $key ] ) ) {
315
					$posted['is_prematch'][ $key ] = false;
316
				}
317
				if ( ! isset( $posted['is_key'][ $key ] ) ) {
318
					$posted['is_key'][ $key ] = false;
319
				}
320
				if ( ! isset( $posted['is_delete'][ $key ] ) ) {
321
					$posted['is_delete'][ $key ] = false;
322
				}
323
				if ( false === $posted['is_delete'][ $key ] ) {
324
					// I think it's good to over-mention that updateable is really how the Salesforce api spells it.
325
					$updateable_key = array_search( $posted['salesforce_field'][ $key ], array_column( $salesforce_fields, 'name' ), true );
326
327
					$salesforce_field_attributes = array();
328
					foreach ( $salesforce_fields[ $updateable_key ] as $sf_key => $sf_value ) {
329
						if ( isset( $sf_value ) && ! is_array( $sf_value ) ) {
330
							$salesforce_field_attributes[ $sf_key ] = esc_attr( $sf_value );
331
						} elseif ( ! empty( $sf_value ) && is_array( $sf_value ) ) {
332
							$salesforce_field_attributes[ $sf_key ] = maybe_unserialize( $sf_value );
0 ignored issues
show
Bug introduced by
$sf_value of type array is incompatible with the type string expected by parameter $original of maybe_unserialize(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

332
							$salesforce_field_attributes[ $sf_key ] = maybe_unserialize( /** @scrutinizer ignore-type */ $sf_value );
Loading history...
333
						} else {
334
							$salesforce_field_attributes[ $sf_key ] = '';
335
						}
336
					}
337
338
					$setup['fields'][ $key ] = array(
339
						'wordpress_field'  => array(
340
							'label'   => sanitize_text_field( $posted['wordpress_field'][ $key ] ),
341
							'methods' => maybe_unserialize( $wordpress_fields[ $method_key ]['methods'] ),
342
							'type'    => isset( $wordpress_fields[ $method_key ]['type'] ) ? sanitize_text_field( $wordpress_fields[ $method_key ]['type'] ) : 'text',
343
						),
344
						'salesforce_field' => $salesforce_field_attributes,
345
						'is_prematch'      => sanitize_text_field( $posted['is_prematch'][ $key ] ),
346
						'is_key'           => sanitize_text_field( $posted['is_key'][ $key ] ),
347
						'direction'        => sanitize_text_field( $posted['direction'][ $key ] ),
348
						'is_delete'        => sanitize_text_field( $posted['is_delete'][ $key ] ),
349
					);
350
351
					// If the WordPress key or the Salesforce key are blank, remove this incomplete mapping.
352
					// This prevents https://github.com/MinnPost/object-sync-for-salesforce/issues/82 .
353
					if (
354
						empty( $setup['fields'][ $key ]['wordpress_field']['label'] )
355
						||
356
						empty( $setup['fields'][ $key ]['salesforce_field']['name'] )
357
					) {
358
						unset( $setup['fields'][ $key ] );
359
					}
360
				}
361
			} // End foreach() on WordPress fields.
362
			$data['fields'] = maybe_serialize( $setup['fields'] );
363
		} elseif ( isset( $posted['fields'] ) && is_array( $posted['fields'] ) ) {
364
			// if $posted['fields'] is already set, use that
365
			$data['fields'] = maybe_serialize( $posted['fields'] );
366
		} // End if() WordPress fields are present.
367
368
		if ( isset( $posted['salesforce_record_types_allowed'] ) ) {
369
			$data['salesforce_record_types_allowed'] = maybe_serialize( $posted['salesforce_record_types_allowed'] );
370
		} else {
371
			$data['salesforce_record_types_allowed'] = maybe_serialize(
372
				array(
373
					$this->salesforce_default_record_type => $this->salesforce_default_record_type,
374
				)
375
			);
376
		}
377
		if ( isset( $posted['salesforce_record_type_default'] ) ) {
378
			$data['salesforce_record_type_default'] = $posted['salesforce_record_type_default'];
379
		} else {
380
			$data['salesforce_record_type_default'] = maybe_serialize( $this->salesforce_default_record_type );
381
		}
382
		if ( isset( $posted['pull_trigger_field'] ) ) {
383
			$data['pull_trigger_field'] = $posted['pull_trigger_field'];
384
		}
385
		if ( isset( $posted['sync_triggers'] ) && is_array( $posted['sync_triggers'] ) ) {
386
			$setup['sync_triggers'] = array();
387
			foreach ( $posted['sync_triggers'] as $key => $value ) {
388
				$setup['sync_triggers'][ $key ] = esc_html( $posted['sync_triggers'][ $key ] );
389
			}
390
		} else {
391
			$setup['sync_triggers'] = array();
392
		}
393
		$data['sync_triggers'] = maybe_serialize( $setup['sync_triggers'] );
394
		if ( isset( $posted['pull_trigger_field'] ) ) {
395
			$data['pull_trigger_field'] = $posted['pull_trigger_field'];
396
		}
397
		$data['push_async']     = isset( $posted['push_async'] ) ? $posted['push_async'] : '';
398
		$data['push_drafts']    = isset( $posted['push_drafts'] ) ? $posted['push_drafts'] : '';
399
		$data['pull_to_drafts'] = isset( $posted['pull_to_drafts'] ) ? $posted['pull_to_drafts'] : '';
400
		$data['weight']         = isset( $posted['weight'] ) ? $posted['weight'] : '';
401
		return $data;
402
	}
403
404
	/**
405
	 * Delete a fieldmap row between a WordPress and Salesforce object
406
	 *
407
	 * @param int $id The ID of a field mapping.
408
	 * @return Boolean
409
	 * @throws \Exception
410
	 */
411
	public function delete_fieldmap( $id = '' ) {
412
		$data   = array(
413
			'id' => $id,
414
		);
415
		$delete = $this->wpdb->delete( $this->fieldmap_table, $data );
416
		if ( 1 === $delete ) {
417
			return true;
418
		} else {
419
			return false;
420
		}
421
	}
422
423
	/**
424
	 * Create an object map row between a WordPress and Salesforce object
425
	 *
426
	 * @param array $posted It's $_POST.
427
	 * @return false|Int of field mapping between WordPress and Salesforce objects
428
	 * @throws \Exception
429
	 */
430
	public function create_object_map( $posted = array() ) {
431
		$data            = $this->setup_object_map_data( $posted );
432
		$data['created'] = current_time( 'mysql' );
433
		// Check to see if we don't know the salesforce id and it is not a temporary id, or if this is pending.
434
		// If it is using a temporary id, the map will get updated after it finishes running; it won't call this method unless there's an error, which we should log.
435
		if ( substr( $data['salesforce_id'], 0, 7 ) !== 'tmp_sf_' || ( isset( $data['action'] ) && 'pending' === $data['action'] ) ) {
0 ignored issues
show
introduced by
Found "!== '". Use Yoda Condition checks, you must
Loading history...
436
			unset( $data['action'] );
437
			$insert = $this->wpdb->insert( $this->object_map_table, $data );
438
		} else {
439
			$status = 'error';
440
			if ( isset( $this->logging ) ) {
441
				$logging = $this->logging;
442
			} elseif ( class_exists( 'Object_Sync_Sf_Logging' ) ) {
443
				$logging = new Object_Sync_Sf_Logging( $this->wpdb, $this->version );
444
			}
445
			$logging->setup(
446
				sprintf(
447
					// translators: %1$s is the name of a WordPress object. %2$s is the id of that object.
448
					esc_html__( 'Error Mapping: error caused by trying to map the WordPress %1$s with ID of %2$s to Salesforce ID starting with "tmp_sf_", which is invalid.', 'object-sync-for-salesforce' ),
449
					esc_attr( $data['wordpress_object'] ),
450
					absint( $data['wordpress_id'] )
451
				),
452
				'',
453
				0,
454
				0,
455
				$status
456
			);
457
			return false;
458
		}
459
		if ( 1 === $insert ) {
460
			return $this->wpdb->insert_id;
461
		} elseif ( false !== strpos( $this->wpdb->last_error, 'Duplicate entry' ) ) {
462
			// this error should never happen now, I think. But let's watch and see.
463
			$mapping = $this->load_all_by_salesforce( $data['salesforce_id'] )[0];
464
			$id      = $mapping['id'];
465
			$status  = 'error';
466
			if ( isset( $this->logging ) ) {
467
				$logging = $this->logging;
468
			} elseif ( class_exists( 'Object_Sync_Sf_Logging' ) ) {
469
				$logging = new Object_Sync_Sf_Logging( $this->wpdb, $this->version );
470
			}
471
			$logging->setup(
472
				sprintf(
473
					// translators: %1$s is the status word "Error". %1$s is the Id of a Salesforce object. %2$s is the ID of a mapping object.
474
					esc_html__( 'Error: Mapping: there is already a WordPress object mapped to the Salesforce object %1$s and the mapping object ID is %2$s', 'object-sync-for-salesforce' ),
475
					esc_attr( $data['salesforce_id'] ),
476
					absint( $id )
477
				),
478
				print_r( $mapping, true ), // log whatever we have for the mapping object, so print the array
0 ignored issues
show
introduced by
The use of function print_r() is discouraged
Loading history...
479
				0,
480
				0,
481
				$status
482
			);
483
			return $id;
484
		} else {
485
			return false;
486
		}
487
	}
488
489
	/**
490
	 * Get all object map rows between WordPress and Salesforce objects.
491
	 *
492
	 * This replaces previous functionality that would return a single object map if there was only one, rather than a multi-dimensional array.
493
	 *
494
	 * @param array $conditions Limitations on the SQL query for object mapping rows.
495
	 * @param bool $reset Unused parameter.
496
	 * @return $mappings
0 ignored issues
show
Documentation Bug introduced by
The doc comment $mappings at position 0 could not be parsed: Unknown type name '$mappings' at position 0 in $mappings.
Loading history...
497
	 */
498
	public function get_all_object_maps( $conditions = array(), $reset = false ) {
0 ignored issues
show
Unused Code introduced by
The parameter $reset is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

498
	public function get_all_object_maps( $conditions = array(), /** @scrutinizer ignore-unused */ $reset = false ) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
499
		$table = $this->object_map_table;
500
		$order = ' ORDER BY object_updated, created';
501
		if ( ! empty( $conditions ) ) { // get multiple but with a limitation.
502
			$mappings = array();
503
504
			if ( ! empty( $conditions ) ) {
505
				$where = ' WHERE ';
506
				$i     = 0;
507
				foreach ( $conditions as $key => $value ) {
508
					$i++;
509
					if ( $i > 1 ) {
510
						$where .= ' AND ';
511
					}
512
					$where .= '`' . $key . '` = "' . $value . '"';
513
				}
514
			} else {
515
				$where = '';
516
			}
517
518
			$mappings = $this->wpdb->get_results( 'SELECT * FROM ' . $table . $where . $order, ARRAY_A );
519
		} else { // get all of the mappings. ALL THE MAPPINGS.
520
			$mappings = $this->wpdb->get_results( 'SELECT * FROM ' . $table . $order, ARRAY_A );
521
		}
522
523
		return $mappings;
524
525
	}
526
527
	/**
528
	 * Get one or more object map rows between WordPress and Salesforce objects
529
	 *
530
	 * @deprecated since 1.8.0
531
	 * @param array $conditions Limitations on the SQL query for object mapping rows.
532
	 * @param bool  $reset Unused parameter.
533
	 * @return $map or $mappings
0 ignored issues
show
Documentation Bug introduced by
The doc comment $map at position 0 could not be parsed: Unknown type name '$map' at position 0 in $map.
Loading history...
534
	 * @throws \Exception
535
	 */
536
	public function get_object_maps( $conditions = array(), $reset = false ) {
0 ignored issues
show
Unused Code introduced by
The parameter $reset is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

536
	public function get_object_maps( $conditions = array(), /** @scrutinizer ignore-unused */ $reset = false ) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
537
		$table = $this->object_map_table;
538
		$order = ' ORDER BY object_updated, created';
539
		if ( ! empty( $conditions ) ) { // get multiple but with a limitation.
540
			$mappings = array();
541
542
			if ( ! empty( $conditions ) ) {
543
				$where = ' WHERE ';
544
				$i     = 0;
545
				foreach ( $conditions as $key => $value ) {
546
					$i++;
547
					if ( $i > 1 ) {
548
						$where .= ' AND ';
549
					}
550
					$where .= '`' . $key . '` = "' . $value . '"';
551
				}
552
			} else {
553
				$where = '';
554
			}
555
556
			$mappings = $this->wpdb->get_results( 'SELECT * FROM ' . $table . $where . $order, ARRAY_A );
557
			if ( ! empty( $mappings ) && 1 === $this->wpdb->num_rows ) {
558
				$mappings = $mappings[0];
559
			}
560
		} else { // get all of the mappings. ALL THE MAPPINGS.
561
			$mappings = $this->wpdb->get_results( 'SELECT * FROM ' . $table . $order, ARRAY_A );
562
			if ( ! empty( $mappings ) && 1 === $this->wpdb->num_rows ) {
563
				$mappings = $mappings[0];
564
			}
565
		}
566
567
		return $mappings;
568
569
	}
570
571
	/**
572
	 * Update an object map row between a WordPress and Salesforce object
573
	 *
574
	 * @param array $posted It's $_POST.
575
	 * @param array $id The ID of the object map row.
576
	 * @return $map
0 ignored issues
show
Documentation Bug introduced by
The doc comment $map at position 0 could not be parsed: Unknown type name '$map' at position 0 in $map.
Loading history...
577
	 * @throws \Exception
578
	 */
579
	public function update_object_map( $posted = array(), $id = '' ) {
580
		$data = $this->setup_object_map_data( $posted );
581
		if ( ! isset( $data['object_updated'] ) ) {
582
			$data['object_updated'] = current_time( 'mysql' );
583
		}
584
		$update = $this->wpdb->update(
585
			$this->object_map_table,
586
			$data,
587
			array(
588
				'id' => $id,
589
			)
590
		);
591
		if ( false === $update ) {
592
			return false;
593
		} else {
594
			return true;
595
		}
596
	}
597
598
	/**
599
	 * Setup the data for the object map
600
	 *
601
	 * @param array $posted It's $_POST.
602
	 * @return $data Filtered array with only the keys that are in the object map database table. Strips out things from WordPress form if they're present.
0 ignored issues
show
Documentation Bug introduced by
The doc comment $data at position 0 could not be parsed: Unknown type name '$data' at position 0 in $data.
Loading history...
603
	 */
604
	private function setup_object_map_data( $posted = array() ) {
605
		$allowed_fields   = $this->wpdb->get_col( "DESC {$this->object_map_table}", 0 );
606
		$allowed_fields[] = 'action'; // we use this in both directions even though it isn't in the database; we remove it from the array later if it is present
607
608
		$data = array_intersect_key( $posted, array_flip( $allowed_fields ) );
609
		return $data;
610
	}
611
612
	/**
613
	 * Delete an object map row between a WordPress and Salesforce object
614
	 *
615
	 * @param int|array $id The ID or IDs of the object map row(s).
616
	 * @throws \Exception
617
	 */
618
	public function delete_object_map( $id = '' ) {
619
		if ( is_string( $id ) || is_int( $id ) ) {
620
			$data   = array(
621
				'id' => $id,
622
			);
623
			$delete = $this->wpdb->delete( $this->object_map_table, $data );
624
			if ( 1 === $delete ) {
625
				return true;
626
			} else {
627
				return false;
628
			}
629
		} elseif ( is_array( $id ) ) {
0 ignored issues
show
introduced by
The condition is_array($id) is always true.
Loading history...
630
			$ids    = implode( ',', array_map( 'absint', $id ) );
631
			$delete = $this->wpdb->query( "DELETE FROM $this->object_map_table WHERE ID IN ($ids)" );
632
			if ( false !== $delete ) {
633
				return true;
634
			} else {
635
				return false;
636
			}
637
		}
638
	}
639
640
	/**
641
	 * Generate a temporary ID to store while waiting for a push or pull to complete, before the record has been assigned a new ID
642
	 *
643
	 * @param string $direction Whether this is part of a push or pull action
644
	 * @return $id is a temporary string that will be replaced if the modification is successful
0 ignored issues
show
Documentation Bug introduced by
The doc comment $id at position 0 could not be parsed: Unknown type name '$id' at position 0 in $id.
Loading history...
645
	 */
646
	public function generate_temporary_id( $direction ) {
647
		if ( 'push' === $direction ) {
648
			$prefix = 'tmp_sf_';
649
		} elseif ( 'pull' === $direction ) {
650
			$prefix = 'tmp_wp_';
651
		}
652
		$id = uniqid( $prefix, true );
653
		return $id;
654
	}
655
656
	/**
657
	 * Returns Salesforce object mappings for a given WordPress object.
658
	 *
659
	 * @param string $object_type Type of object to load.
660
	 * @param int    $object_id Unique identifier of the target object to load.
661
	 * @param bool   $reset Whether or not the cache should be cleared and fetch from current data.
662
	 *
663
	 * @return SalesforceMappingObject
0 ignored issues
show
Bug introduced by
The type SalesforceMappingObject was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
664
	 *   The requested SalesforceMappingObject or FALSE if none was found.
665
	 */
666
	public function load_all_by_wordpress( $object_type, $object_id, $reset = false ) {
667
		$conditions = array(
668
			'wordpress_id'     => $object_id,
669
			'wordpress_object' => $object_type,
670
		);
671
		return $this->get_all_object_maps( $conditions, $reset );
672
	}
673
674
	/**
675
	 * Returns one or more Salesforce object mappings for a given WordPress object.
676
	 *
677
	 * @deprecated since 1.8.0
678
	 * @param string $object_type Type of object to load.
679
	 * @param int    $object_id Unique identifier of the target object to load.
680
	 * @param bool   $reset Whether or not the cache should be cleared and fetch from current data.
681
	 *
682
	 * @return SalesforceMappingObject
683
	 *   The requested SalesforceMappingObject or FALSE if none was found.
684
	 */
685
	public function load_by_wordpress( $object_type, $object_id, $reset = false ) {
686
		$conditions = array(
687
			'wordpress_id'     => $object_id,
688
			'wordpress_object' => $object_type,
689
		);
690
		return $this->get_object_maps( $conditions, $reset );
0 ignored issues
show
Deprecated Code introduced by
The function Object_Sync_Sf_Mapping::get_object_maps() has been deprecated: since 1.8.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

690
		return /** @scrutinizer ignore-deprecated */ $this->get_object_maps( $conditions, $reset );

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
691
	}
692
693
	/**
694
	 * Returns Salesforce object mappings for a given Salesforce object.
695
	 *
696
	 * @param string $salesforce_id Type of object to load.
697
	 * @param bool   $reset Whether or not the cache should be cleared and fetch from current data.
698
	 *
699
	 * @return array $maps all the fieldmaps that match the Salesforce Id
700
	 */
701
	public function load_all_by_salesforce( $salesforce_id, $reset = false ) {
702
		$conditions = array(
703
			'salesforce_id' => $salesforce_id,
704
		);
705
706
		$maps = $this->get_all_object_maps( $conditions, $reset );
707
708
		return $maps;
709
	}
710
711
	/**
712
	 * Returns one or more Salesforce object mappings for a given Salesforce object.
713
	 *
714
	 * @deprecated since 1.8.0
715
	 * @param string $salesforce_id Type of object to load.
716
	 * @param bool   $reset Whether or not the cache should be cleared and fetch from current data.
717
	 *
718
	 * @return array $map
719
	 *   The most recent fieldmap
720
	 */
721
	public function load_by_salesforce( $salesforce_id, $reset = false ) {
722
		$conditions = array(
723
			'salesforce_id' => $salesforce_id,
724
		);
725
726
		$map = $this->get_object_maps( $conditions, $reset );
0 ignored issues
show
Deprecated Code introduced by
The function Object_Sync_Sf_Mapping::get_object_maps() has been deprecated: since 1.8.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

726
		$map = /** @scrutinizer ignore-deprecated */ $this->get_object_maps( $conditions, $reset );

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
727
728
		if ( isset( $map[0] ) && is_array( $map[0] ) && count( $map ) > 1 ) {
729
			$status = 'notice';
730
			$log    = '';
731
			$log   .= 'Mapping: there is more than one mapped WordPress object for the Salesforce object ' . $salesforce_id . '. These WordPress IDs are: ';
732
			$i      = 0;
733
			foreach ( $map as $mapping ) {
734
				$i++;
735
				if ( isset( $mapping['wordpress_id'] ) ) {
736
					$log .= 'object type: ' . $mapping['wordpress_object'] . ', id: ' . $mapping['wordpress_id'];
737
				}
738
				if ( count( $map ) !== $i ) {
739
					$log .= '; ';
740
				} else {
741
					$log .= '.';
742
				}
743
			}
744
			$map = $map[0];
745
			// Create log entry for multiple maps.
746
			if ( isset( $this->logging ) ) {
747
				$logging = $this->logging;
748
			} elseif ( class_exists( 'Object_Sync_Sf_Logging' ) ) {
749
				$logging = new Object_Sync_Sf_Logging( $this->wpdb, $this->version );
750
			}
751
			$logging->setup(
752
				sprintf(
753
					// translators: %1$s is the Id of a Salesforce object.
754
					esc_html__( 'Notice: Mapping: there is more than one mapped WordPress object for the Salesforce object %2$s', 'object-sync-for-salesforce' ),
755
					esc_attr( $salesforce_id )
756
				),
757
				$log,
758
				0,
759
				0,
760
				$status
761
			);
762
		} // End if().
763
764
		return $map;
765
	}
766
767
	/**
768
	 * Map values between WordPress and Salesforce objects.
769
	 *
770
	 * @param array  $mapping Mapping object.
771
	 * @param array  $object WordPress or Salesforce object data.
772
	 * @param array  $trigger The thing that triggered this mapping.
773
	 * @param bool   $use_soap Flag to enforce use of the SOAP API.
774
	 * @param bool   $is_new Indicates whether a mapping object for this entity already exists.
775
	 * @param string $object_id_field optionally pass the object id field name
776
	 *
777
	 * @return array Associative array of key value pairs.
778
	 */
779
	public function map_params( $mapping, $object, $trigger, $use_soap = false, $is_new = true, $object_id_field = '' ) {
0 ignored issues
show
Unused Code introduced by
The parameter $is_new is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

779
	public function map_params( $mapping, $object, $trigger, $use_soap = false, /** @scrutinizer ignore-unused */ $is_new = true, $object_id_field = '' ) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
780
781
		$params = array();
782
783
		$has_missing_required_salesforce_field = false;
784
		foreach ( $mapping['fields'] as $fieldmap ) {
785
786
			$wordpress_haystack  = array_values( $this->wordpress_events );
787
			$salesforce_haystack = array_values( $this->salesforce_events );
788
789
			$fieldmap['wordpress_field']['methods'] = maybe_unserialize( $fieldmap['wordpress_field']['methods'] );
790
791
			$wordpress_field = $fieldmap['wordpress_field']['label'];
792
793
			if ( version_compare( $this->version, '1.2.0', '>=' ) && isset( $fieldmap['salesforce_field']['name'] ) ) {
794
				$salesforce_field = $fieldmap['salesforce_field']['name'];
795
				// Load the type of the Salesforce field. We can use this to handle Salesforce field value issues that come up based on what the field sends into WordPress or expects from WordPress.
796
				$salesforce_field_type = $fieldmap['salesforce_field']['type'];
797
			} else {
798
				$salesforce_field = $fieldmap['salesforce_field']['label'];
799
			}
800
801
			// A WordPress event caused this.
802
			if ( in_array( $trigger, array_values( $wordpress_haystack ), true ) ) {
803
804
				// Is the field in WordPress an array, if we unserialize it? Salesforce wants it to be an imploded string.
805
				if ( is_array( maybe_unserialize( $object[ $wordpress_field ] ) ) ) {
806
					$object[ $wordpress_field ] = implode( $this->array_delimiter, $object[ $wordpress_field ] );
807
				}
808
809
				if ( isset( $salesforce_field_type ) ) {
810
					// Is the Salesforce field a date, and is the WordPress value a valid date?
811
					// According to https://salesforce.stackexchange.com/questions/57032/date-format-with-salesforce-rest-api
812
					if ( in_array( $salesforce_field_type, $this->date_types_from_salesforce ) ) {
813
						if ( '' === $object[ $wordpress_field ] ) {
814
							$object[ $wordpress_field ] = null;
815
						} else {
816
							if ( false !== strtotime( $object[ $wordpress_field ] ) ) {
817
								$timestamp = strtotime( $object[ $wordpress_field ] );
818
							} else {
819
								$timestamp = $object[ $wordpress_field ];
820
							}
821
							if ( 'datetime' === $salesforce_field_type ) {
822
								$object[ $wordpress_field ] = date_i18n( 'c', $timestamp );
823
							} else {
824
								$object[ $wordpress_field ] = date_i18n( 'Y-m-d', $timestamp );
825
							}
826
						}
827
					}
828
829
					// Boolean SF fields only want real boolean values. NULL is also not allowed.
830
					if ( 'boolean' === $salesforce_field_type ) {
831
						$object[ $wordpress_field ] = (bool) $object[ $wordpress_field ];
832
					}
833
				}
834
835
				$params[ $salesforce_field ] = $object[ $wordpress_field ];
836
837
				// If the field is a key in Salesforce, remove it from $params to avoid upsert errors from Salesforce,
838
				// but still put its name in the params array so we can check for it later.
839
				if ( '1' === $fieldmap['is_key'] ) {
840
					if ( ! $use_soap ) {
841
						unset( $params[ $salesforce_field ] );
842
					}
843
					$params['key'] = array(
844
						'salesforce_field' => $salesforce_field,
845
						'wordpress_field'  => $wordpress_field,
846
						'value'            => $object[ $wordpress_field ],
847
					);
848
				}
849
850
				// If the field is a prematch in Salesforce, put its name in the params array so we can check for it later.
851
				if ( '1' === $fieldmap['is_prematch'] ) {
852
					$params['prematch'] = array(
853
						'salesforce_field' => $salesforce_field,
854
						'wordpress_field'  => $wordpress_field,
855
						'value'            => $object[ $wordpress_field ],
856
					);
857
				}
858
859
				// Skip fields that aren't being pushed to Salesforce.
860
				if ( ! in_array( $fieldmap['direction'], array_values( $this->direction_wordpress ), true ) ) {
861
					// The trigger is a WordPress trigger, but the fieldmap direction is not a WordPress direction.
862
					unset( $params[ $salesforce_field ] );
863
				}
864
865
				// I think it's good to over-mention that updateable is really how the Salesforce api spells it.
866
				// Skip fields that aren't updateable when mapping params because Salesforce will error otherwise.
867
				// This happens after dealing with the field types because key and prematch should still be available to the plugin, even if the values are not updateable in Salesforce.
868
				if ( 1 !== (int) $fieldmap['salesforce_field']['updateable'] ) {
869
					unset( $params[ $salesforce_field ] );
870
				}
871
872
				// This case means the following:
873
				//    this field is expected by the fieldmap
874
				//    Salesforce's api reports that this field is required
875
				//    we do not have a WordPress value for this field, or it's empty
876
				//    it also means the field has not been unset by prematch, updateable, key, or directional flags prior to this check.
877
				// When this happens, we should flag that we're missing a required Salesforce field
878
				if ( in_array( $salesforce_field, $params ) && false === filter_var( $fieldmap['salesforce_field']['nillable'], FILTER_VALIDATE_BOOLEAN ) && ( ! isset( $object[ $wordpress_field ] ) || '' === $object[ $wordpress_field ] ) ) {
879
					$has_missing_required_salesforce_field = true;
880
				}
881
882
				// we don't need a continue with the unset methods because there's no array being created down here
883
			} elseif ( in_array( $trigger, $salesforce_haystack, true ) ) {
884
885
				// A Salesforce event caused this.
886
887
				if ( isset( $salesforce_field_type ) && isset( $object[ $salesforce_field ] ) && ! is_null( $object[ $salesforce_field ] ) ) {
888
					// Salesforce provides multipicklist values as a delimited string. If the
889
					// destination field in WordPress accepts multiple values, explode the string into an array and then serialize it.
890
					if ( in_array( $salesforce_field_type, $this->array_types_from_salesforce ) ) {
891
						$object[ $salesforce_field ] = explode( $this->array_delimiter, $object[ $salesforce_field ] );
892
					}
893
894
					// Handle specific data types from Salesforce.
895
					switch ( $salesforce_field_type ) {
896
						case ( in_array( $salesforce_field_type, $this->date_types_from_salesforce ) ):
897
							$format = get_option( 'date_format', 'U' );
898
							if ( isset( $fieldmap['wordpress_field']['type'] ) && 'datetime' === $fieldmap['wordpress_field']['type'] ) {
899
								$format = 'Y-m-d H:i:s';
900
							}
901
							$object[ $salesforce_field ] = date_i18n( $format, strtotime( $object[ $salesforce_field ] ) );
902
							break;
903
						case ( in_array( $salesforce_field_type, $this->int_types_from_salesforce ) ):
904
							$object[ $salesforce_field ] = isset( $object[ $salesforce_field ] ) ? (int) $object[ $salesforce_field ] : 0;
905
							break;
906
						case 'text':
907
							$object[ $salesforce_field ] = (string) $object[ $salesforce_field ];
908
							break;
909
						case 'url':
910
							$object[ $salesforce_field ] = esc_url_raw( $object[ $salesforce_field ] );
911
							break;
912
					}
913
				}
914
915
				// Make an array because we need to store the methods for each field as well.
916
				if ( isset( $object[ $salesforce_field ] ) && '' !== $object[ $salesforce_field ] ) {
917
					$params[ $wordpress_field ]          = array();
918
					$params[ $wordpress_field ]['value'] = $object[ $salesforce_field ];
919
				} else {
920
					// If we try to save certain fields with empty values, WordPress will silently start skipping stuff. This keeps that from happening.
921
					continue;
922
				}
923
924
				// If the field is a key in Salesforce, disregard since this is caused by a Salesforce event. We're setting up data to be stored in WordPress here, and WordPress is not concerned with external key designations in Salesforce.
925
926
				// If the field is a prematch in Salesforce, put its name in the params array so we can check for it later.
927
				if ( '1' === $fieldmap['is_prematch'] ) {
928
					$params['prematch'] = array(
929
						'salesforce_field' => $salesforce_field,
930
						'wordpress_field'  => $wordpress_field,
931
						'value'            => $object[ $salesforce_field ],
932
						'method_match'     => isset( $fieldmap['wordpress_field']['methods']['match'] ) ? $fieldmap['wordpress_field']['methods']['match'] : $fieldmap['wordpress_field']['methods']['read'],
933
						'method_read'      => $fieldmap['wordpress_field']['methods']['read'],
934
						'method_create'    => $fieldmap['wordpress_field']['methods']['create'],
935
						'method_update'    => $fieldmap['wordpress_field']['methods']['update'],
936
					);
937
				}
938
939
				// Skip fields that aren't being pulled from Salesforce.
940
				if ( ! in_array( $fieldmap['direction'], array_values( $this->direction_salesforce ), true ) ) {
941
					// The trigger is a Salesforce trigger, but the fieldmap direction is not a Salesforce direction.
942
					unset( $params[ $wordpress_field ] );
943
					// we also need to continue here, so it doesn't create an empty array below for fields that are WordPress -> Salesforce only
944
					continue;
945
				}
946
947
				switch ( $trigger ) {
948
					case $this->sync_sf_create:
949
						$params[ $wordpress_field ]['method_modify'] = $fieldmap['wordpress_field']['methods']['create'];
950
						break;
951
					case $this->sync_sf_update:
952
						$params[ $wordpress_field ]['method_modify'] = $fieldmap['wordpress_field']['methods']['update'];
953
						break;
954
					case $this->sync_sf_delete:
955
						$params[ $wordpress_field ]['method_modify'] = $fieldmap['wordpress_field']['methods']['delete'];
956
						break;
957
				}
958
959
				$params[ $wordpress_field ]['method_read'] = $fieldmap['wordpress_field']['methods']['read'];
960
961
			} // End if().
962
		} // End foreach().
963
964
		if ( true === $has_missing_required_salesforce_field ) {
965
			update_option( $this->option_prefix . 'missing_required_data_id_' . $object[ $object_id_field ], true, false );
966
			return array();
967
		}
968
969
		return $params;
970
971
	}
972
973
	/**
974
	 * Prepare field map data for use
975
	 *
976
	 * @param array  $mappings Array of fieldmaps.
977
	 * @param string $record_type Optional Salesforce record type to see if it is allowed or not.
978
	 *
979
	 * @return array $mappings Associative array of field maps ready to use
980
	 */
981
	private function prepare_fieldmap_data( $mappings, $record_type = '' ) {
982
983
		foreach ( $mappings as $id => $mapping ) {
984
			$mappings[ $id ]['salesforce_record_types_allowed'] = maybe_unserialize( $mapping['salesforce_record_types_allowed'] );
985
			$mappings[ $id ]['fields']                          = maybe_unserialize( $mapping['fields'] );
986
			$mappings[ $id ]['sync_triggers']                   = maybe_unserialize( $mapping['sync_triggers'] );
987
			if ( '' !== $record_type && ! in_array( $record_type, $mappings[ $id ]['salesforce_record_types_allowed'], true ) ) {
988
				unset( $mappings[ $id ] );
989
			}
990
		}
991
992
		return $mappings;
993
994
	}
995
996
	/**
997
	 * Check object map table to see if there have been any failed object map create attempts
998
	 *
999
	 * @return array $errors Associative array of rows that failed to finish from either system
1000
	 */
1001
	public function get_failed_object_maps() {
1002
		$table       = $this->object_map_table;
1003
		$errors      = array();
1004
		$push_errors = $this->wpdb->get_results( 'SELECT * FROM ' . $table . ' WHERE salesforce_id LIKE "tmp_sf_%"', ARRAY_A );
1005
		$pull_errors = $this->wpdb->get_results( 'SELECT * FROM ' . $table . ' WHERE wordpress_id LIKE "tmp_wp_%"', ARRAY_A );
1006
		if ( ! empty( $push_errors ) ) {
1007
			$errors['push_errors'] = $push_errors;
1008
		}
1009
		if ( ! empty( $pull_errors ) ) {
1010
			$errors['pull_errors'] = $pull_errors;
1011
		}
1012
		return $errors;
1013
	}
1014
1015
	/**
1016
	 * Check object map table to see if there have been any failed object map create attempts
1017
	 *
1018
	 * @param int   $id The ID of a desired mapping.
1019
	 *
1020
	 * @return array $error Associative array of single row that failed to finish based on id
1021
	 */
1022
	public function get_failed_object_map( $id ) {
1023
		$table     = $this->object_map_table;
1024
		$error     = array();
1025
		$error_row = $this->wpdb->get_row( 'SELECT * FROM ' . $table . ' WHERE id = "' . $id . '"', ARRAY_A );
1026
		if ( ! empty( $error_row ) ) {
1027
			$error = $error_row;
1028
		}
1029
		return $error;
1030
	}
1031
1032
}
1033