Completed
Push — 328-fieldmap-screen-design-upd... ( 082d11...51ef39 )
by Jonathan
31s queued 15s
created

Object_Sync_Sf_Mapping::get_fieldmaps()   C

Complexity

Conditions 12
Paths 13

Size

Total Lines 51
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
cc 12
eloc 38
c 3
b 1
f 0
nc 13
nop 3
dl 0
loc 51
rs 6.9666

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
	public $debug;
56
57
	/**
58
	 * Constructor which sets up links between the systems
59
	 *
60
	 * @param object $wpdb A WPDB object.
61
	 * @param string $version The plugin version.
62
	 * @param string $slug The plugin slug.
63
	 * @param object $logging Object_Sync_Sf_Logging.
64
	 * @param string $option_prefix The plugin option prefix
65
	 * @throws \Exception
66
	 */
67
	public function __construct( $wpdb, $version, $slug, $logging, $option_prefix = '' ) {
68
		$this->wpdb          = $wpdb;
69
		$this->version       = $version;
70
		$this->slug          = $slug;
71
		$this->option_prefix = isset( $option_prefix ) ? $option_prefix : 'object_sync_for_salesforce_';
72
		$this->logging       = $logging;
73
74
		$this->fieldmap_table   = $this->wpdb->prefix . 'object_sync_sf_field_map';
75
		$this->object_map_table = $this->wpdb->prefix . 'object_sync_sf_object_map';
76
77
		/*
78
		 * These parameters are how we define when syncing should occur on each field map.
79
		 * They get used in the admin settings, as well as the push/pull methods to see if something should happen.
80
		 * It is unclear why the Drupal module used bit flags, but it seems reasonable to keep the convention.
81
		*/
82
		$this->sync_off              = 0x0000;
83
		$this->sync_wordpress_create = 0x0001;
84
		$this->sync_wordpress_update = 0x0002;
85
		$this->sync_wordpress_delete = 0x0004;
86
		$this->sync_sf_create        = 0x0008;
87
		$this->sync_sf_update        = 0x0010;
88
		$this->sync_sf_delete        = 0x0020;
89
90
		// Define which events are initialized by which system.
91
		$this->wordpress_events  = array( $this->sync_wordpress_create, $this->sync_wordpress_update, $this->sync_wordpress_delete );
92
		$this->salesforce_events = array( $this->sync_sf_create, $this->sync_sf_update, $this->sync_sf_delete );
93
94
		// Constants for the directions to map things.
95
		$this->direction_wordpress_sf = 'wp_sf';
96
		$this->direction_sf_wordpress = 'sf_wp';
97
		$this->direction_sync         = 'sync';
98
99
		$this->direction_wordpress  = array( $this->direction_wordpress_sf, $this->direction_sync );
100
		$this->direction_salesforce = array( $this->direction_sf_wordpress, $this->direction_sync );
101
102
		// This is used when we map a record with default or Master.
103
		$this->salesforce_default_record_type = 'default';
104
105
		// Salesforce has multipicklists and they have a delimiter.
106
		$this->array_delimiter = ';';
107
		// What data types in Salesforce should be an array?
108
		$this->array_types_from_salesforce = array( 'multipicklist' );
109
		// What data types in Salesforce should be a date field?
110
		$this->date_types_from_salesforce = array( 'date', 'datetime' );
111
		// What data types in Salesforce should be an integer?
112
		$this->int_types_from_salesforce = array( 'integer', 'boolean' );
113
114
		// Max length for a mapping field.
115
		$this->name_length = 128;
116
117
		// Statuses for object sync.
118
		$this->status_success = 1;
119
		$this->status_error   = 0;
120
121
		$this->debug = get_option( $this->option_prefix . 'debug_mode', false );
122
123
	}
124
125
	/**
126
	 * Create a fieldmap row between a WordPress and Salesforce object
127
	 *
128
	 * @param array $posted The results of $_POST.
129
	 * @param array $wordpress_fields The fields for the WordPress side of the mapping.
130
	 * @param array $salesforce_fields The fields for the Salesforce side of the mapping.
131
	 * @throws \Exception
132
	 */
133
	public function create_fieldmap( $posted = array(), $wordpress_fields = array(), $salesforce_fields = array() ) {
134
		$data = $this->setup_fieldmap_data( $posted, $wordpress_fields, $salesforce_fields );
135
		if ( version_compare( $this->version, '1.2.5', '>=' ) ) {
136
			$data['version'] = $this->version;
137
		}
138
		$insert = $this->wpdb->insert( $this->fieldmap_table, $data );
139
		if ( 1 === $insert ) {
140
			return $this->wpdb->insert_id;
141
		} else {
142
			return false;
143
		}
144
	}
145
146
	/**
147
	 * Get one or more fieldmap rows between a WordPress and Salesforce object
148
	 *
149
	 * @param int   $id The ID of a desired mapping.
150
	 * @param array $conditions Array of key=>value to match the mapping by.
151
	 * @param bool  $reset Unused parameter.
152
	 * @return array $map a single mapping or $mappings, an array of mappings.
153
	 * @throws \Exception
154
	 */
155
	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

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

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

512
	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...
513
		$table = $this->object_map_table;
514
		$order = ' ORDER BY object_updated, created';
515
		if ( ! empty( $conditions ) ) { // get multiple but with a limitation.
516
			$mappings = array();
517
518
			if ( ! empty( $conditions ) ) {
519
				$where = ' WHERE ';
520
				$i     = 0;
521
				foreach ( $conditions as $key => $value ) {
522
					$i++;
523
					if ( $i > 1 ) {
524
						$where .= ' AND ';
525
					}
526
					$where .= '`' . $key . '` = "' . $value . '"';
527
				}
528
			} else {
529
				$where = '';
530
			}
531
532
			$mappings = $this->wpdb->get_results( 'SELECT * FROM ' . $table . $where . $order, ARRAY_A );
533
		} else { // get all of the mappings. ALL THE MAPPINGS.
534
			$mappings = $this->wpdb->get_results( 'SELECT * FROM ' . $table . $order, ARRAY_A );
535
		}
536
537
		return $mappings;
538
539
	}
540
541
	/**
542
	 * Get one or more object map rows between WordPress and Salesforce objects
543
	 *
544
	 * @deprecated since 1.8.0
545
	 * @param array $conditions Limitations on the SQL query for object mapping rows.
546
	 * @param bool  $reset Unused parameter.
547
	 * @return array $map or $mappings
548
	 * @throws \Exception
549
	 */
550
	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

550
	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...
551
		$table = $this->object_map_table;
552
		$order = ' ORDER BY object_updated, created';
553
		if ( ! empty( $conditions ) ) { // get multiple but with a limitation.
554
			$mappings = array();
555
556
			if ( ! empty( $conditions ) ) {
557
				$where = ' WHERE ';
558
				$i     = 0;
559
				foreach ( $conditions as $key => $value ) {
560
					$i++;
561
					if ( $i > 1 ) {
562
						$where .= ' AND ';
563
					}
564
					$where .= '`' . $key . '` = "' . $value . '"';
565
				}
566
			} else {
567
				$where = '';
568
			}
569
570
			$mappings = $this->wpdb->get_results( 'SELECT * FROM ' . $table . $where . $order, ARRAY_A );
571
			if ( ! empty( $mappings ) && 1 === $this->wpdb->num_rows ) {
572
				$mappings = $mappings[0];
573
			}
574
		} else { // get all of the mappings. ALL THE MAPPINGS.
575
			$mappings = $this->wpdb->get_results( 'SELECT * FROM ' . $table . $order, ARRAY_A );
576
			if ( ! empty( $mappings ) && 1 === $this->wpdb->num_rows ) {
577
				$mappings = $mappings[0];
578
			}
579
		}
580
581
		return $mappings;
582
583
	}
584
585
	/**
586
	 * Update an object map row between a WordPress and Salesforce object
587
	 *
588
	 * @param array $posted It's $_POST.
589
	 * @param array $id The ID of the object map row.
590
	 * @return boolean
591
	 * @throws \Exception
592
	 */
593
	public function update_object_map( $posted = array(), $id = '' ) {
594
		$data = $this->setup_object_map_data( $posted );
595
		if ( ! isset( $data['object_updated'] ) ) {
596
			$data['object_updated'] = current_time( 'mysql' );
597
		}
598
		$update = $this->wpdb->update(
599
			$this->object_map_table,
600
			$data,
601
			array(
602
				'id' => $id,
603
			)
604
		);
605
		if ( false === $update ) {
606
			return false;
607
		} else {
608
			return true;
609
		}
610
	}
611
612
	/**
613
	 * Setup the data for the object map
614
	 *
615
	 * @param array $posted It's $_POST.
616
	 * @return array $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.
617
	 */
618
	private function setup_object_map_data( $posted = array() ) {
619
		$allowed_fields   = $this->wpdb->get_col( "DESC {$this->object_map_table}", 0 );
620
		$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
621
622
		$data = array_intersect_key( $posted, array_flip( $allowed_fields ) );
623
		return $data;
624
	}
625
626
	/**
627
	 * Delete an object map row between a WordPress and Salesforce object
628
	 *
629
	 * @param int|array $id The ID or IDs of the object map row(s).
630
	 * @return boolean
631
	 * @throws \Exception
632
	 */
633
	public function delete_object_map( $id = '' ) {
634
		if ( is_string( $id ) || is_int( $id ) ) {
635
			$data   = array(
636
				'id' => $id,
637
			);
638
			$delete = $this->wpdb->delete( $this->object_map_table, $data );
639
			if ( 1 === $delete ) {
640
				return true;
641
			} else {
642
				return false;
643
			}
644
		} elseif ( is_array( $id ) ) {
0 ignored issues
show
introduced by
The condition is_array($id) is always true.
Loading history...
645
			$ids    = implode( ',', array_map( 'absint', $id ) );
646
			$delete = $this->wpdb->query( "DELETE FROM $this->object_map_table WHERE ID IN ($ids)" );
647
			if ( false !== $delete ) {
648
				return true;
649
			} else {
650
				return false;
651
			}
652
		}
653
	}
654
655
	/**
656
	 * Generate a temporary ID to store while waiting for a push or pull to complete, before the record has been assigned a new ID
657
	 *
658
	 * @param string $direction Whether this is part of a push or pull action
659
	 * @return string $id is a temporary string that will be replaced if the modification is successful
660
	 */
661
	public function generate_temporary_id( $direction ) {
662
		if ( 'push' === $direction ) {
663
			$prefix = 'tmp_sf_';
664
		} elseif ( 'pull' === $direction ) {
665
			$prefix = 'tmp_wp_';
666
		}
667
		$id = uniqid( $prefix, true );
668
		return $id;
669
	}
670
671
	/**
672
	 * Returns Salesforce object mappings for a given WordPress object.
673
	 *
674
	 * @param string $object_type Type of object to load.
675
	 * @param int    $object_id Unique identifier of the target object to load.
676
	 * @param bool   $reset Whether or not the cache should be cleared and fetch from current data.
677
	 *
678
	 * @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...
679
	 *   The requested SalesforceMappingObject or FALSE if none was found.
680
	 */
681
	public function load_all_by_wordpress( $object_type, $object_id, $reset = false ) {
682
		$conditions = array(
683
			'wordpress_id'     => $object_id,
684
			'wordpress_object' => $object_type,
685
		);
686
		return $this->get_all_object_maps( $conditions, $reset );
687
	}
688
689
	/**
690
	 * Returns one or more Salesforce object mappings for a given WordPress object.
691
	 *
692
	 * @deprecated since 1.8.0
693
	 * @param string $object_type Type of object to load.
694
	 * @param int    $object_id Unique identifier of the target object to load.
695
	 * @param bool   $reset Whether or not the cache should be cleared and fetch from current data.
696
	 *
697
	 * @return SalesforceMappingObject
698
	 *   The requested SalesforceMappingObject or FALSE if none was found.
699
	 */
700
	public function load_by_wordpress( $object_type, $object_id, $reset = false ) {
701
		$conditions = array(
702
			'wordpress_id'     => $object_id,
703
			'wordpress_object' => $object_type,
704
		);
705
		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

705
		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...
706
	}
707
708
	/**
709
	 * Returns Salesforce object mappings for a given Salesforce object.
710
	 *
711
	 * @param string $salesforce_id Type of object to load.
712
	 * @param bool   $reset Whether or not the cache should be cleared and fetch from current data.
713
	 *
714
	 * @return array $maps all the object maps that match the Salesforce Id
715
	 */
716
	public function load_all_by_salesforce( $salesforce_id, $reset = false ) {
717
		$conditions = array(
718
			'salesforce_id' => $salesforce_id,
719
		);
720
721
		$maps = $this->get_all_object_maps( $conditions, $reset );
722
723
		return $maps;
724
	}
725
726
	/**
727
	 * Returns one or more Salesforce object mappings for a given Salesforce object.
728
	 *
729
	 * @deprecated since 1.8.0
730
	 * @param string $salesforce_id Type of object to load.
731
	 * @param bool   $reset Whether or not the cache should be cleared and fetch from current data.
732
	 *
733
	 * @return array $map
734
	 *   The most recent fieldmap
735
	 */
736
	public function load_by_salesforce( $salesforce_id, $reset = false ) {
737
		$conditions = array(
738
			'salesforce_id' => $salesforce_id,
739
		);
740
741
		$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

741
		$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...
742
743
		if ( isset( $map[0] ) && is_array( $map[0] ) && count( $map ) > 1 ) {
744
			$status = 'notice';
745
			$log    = '';
746
			$log   .= 'Mapping: there is more than one mapped WordPress object for the Salesforce object ' . $salesforce_id . '. These WordPress IDs are: ';
747
			$i      = 0;
748
			foreach ( $map as $mapping ) {
749
				$i++;
750
				if ( isset( $mapping['wordpress_id'] ) ) {
751
					$log .= 'object type: ' . $mapping['wordpress_object'] . ', id: ' . $mapping['wordpress_id'];
752
				}
753
				if ( count( $map ) !== $i ) {
754
					$log .= '; ';
755
				} else {
756
					$log .= '.';
757
				}
758
			}
759
			$map = $map[0];
760
			// Create log entry for multiple maps.
761
			if ( isset( $this->logging ) ) {
762
				$logging = $this->logging;
763
			} elseif ( class_exists( 'Object_Sync_Sf_Logging' ) ) {
764
				$logging = new Object_Sync_Sf_Logging( $this->wpdb, $this->version );
765
			}
766
			$logging->setup(
767
				sprintf(
768
					// translators: %1$s is the Id of a Salesforce object.
769
					esc_html__( 'Notice: Mapping: there is more than one mapped WordPress object for the Salesforce object %2$s', 'object-sync-for-salesforce' ),
770
					esc_attr( $salesforce_id )
771
				),
772
				$log,
773
				0,
774
				0,
775
				$status
776
			);
777
		} // End if().
778
779
		return $map;
780
	}
781
782
	/**
783
	 * Map values between WordPress and Salesforce objects.
784
	 *
785
	 * @param array  $mapping The fieldmap that maps these types together.
786
	 * @param array  $object WordPress or Salesforce object data.
787
	 * @param array  $trigger The thing that triggered this mapping.
788
	 * @param bool   $use_soap Flag to enforce use of the SOAP API.
789
	 * @param bool   $is_new Indicates whether a mapping object for this entity already exists.
790
	 * @param string $object_id_field optionally pass the object id field name
791
	 *
792
	 * @return array Associative array of key value pairs.
793
	 */
794
	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

794
	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...
795
796
		$params = array();
797
798
		// these are the triggers that define whether the action was from WordPress or Salesforce.
799
		$wordpress_haystack  = array_values( $this->wordpress_events );
800
		$salesforce_haystack = array_values( $this->salesforce_events );
801
802
		$has_missing_required_salesforce_field = false;
803
		foreach ( $mapping['fields'] as $fieldmap ) {
804
805
			$fieldmap['wordpress_field']['methods'] = maybe_unserialize( $fieldmap['wordpress_field']['methods'] );
806
807
			$wordpress_field = $fieldmap['wordpress_field']['label'];
808
809
			if ( version_compare( $this->version, '1.2.0', '>=' ) && isset( $fieldmap['salesforce_field']['name'] ) ) {
810
				$salesforce_field = $fieldmap['salesforce_field']['name'];
811
				// 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.
812
				$salesforce_field_type = $fieldmap['salesforce_field']['type'];
813
			} else {
814
				$salesforce_field = $fieldmap['salesforce_field']['label'];
815
			}
816
817
			// A WordPress event caused this.
818
			if ( in_array( $trigger, array_values( $wordpress_haystack ), true ) ) {
819
820
				// Is the field in WordPress an array, if we unserialize it? Salesforce wants it to be an imploded string.
821
				if ( is_array( maybe_unserialize( $object[ $wordpress_field ] ) ) ) {
822
					// if the WordPress field is a list of capabilities (the source field is wp_capabilities), we need to get the array keys from WordPress to send them to Salesforce.
823
					if ( 'wp_capabilities' === $wordpress_field ) {
824
						$object[ $wordpress_field ] = implode( $this->array_delimiter, array_keys( $object[ $wordpress_field ] ) );
825
					} else {
826
						$object[ $wordpress_field ] = implode( $this->array_delimiter, $object[ $wordpress_field ] );
827
					}
828
				}
829
830
				if ( isset( $salesforce_field_type ) ) {
831
					// Is the Salesforce field a date, and is the WordPress value a valid date?
832
					// According to https://salesforce.stackexchange.com/questions/57032/date-format-with-salesforce-rest-api
833
					if ( in_array( $salesforce_field_type, $this->date_types_from_salesforce, true ) ) {
834
						if ( '' === $object[ $wordpress_field ] ) {
835
							$object[ $wordpress_field ] = null;
836
						} else {
837
							if ( false !== strtotime( $object[ $wordpress_field ] ) ) {
838
								$timestamp = strtotime( $object[ $wordpress_field ] );
839
							} else {
840
								$timestamp = $object[ $wordpress_field ];
841
							}
842
							if ( 'datetime' === $salesforce_field_type ) {
843
								$object[ $wordpress_field ] = date_i18n( 'c', $timestamp );
844
							} else {
845
								$object[ $wordpress_field ] = date_i18n( 'Y-m-d', $timestamp );
846
							}
847
						}
848
					}
849
850
					// Boolean SF fields only want real boolean values. NULL is also not allowed.
851
					if ( 'boolean' === $salesforce_field_type ) {
852
						$object[ $wordpress_field ] = (bool) $object[ $wordpress_field ];
853
					}
854
				}
855
856
				$params[ $salesforce_field ] = $object[ $wordpress_field ];
857
858
				// If the field is a key in Salesforce, remove it from $params to avoid upsert errors from Salesforce,
859
				// but still put its name in the params array so we can check for it later.
860
				if ( '1' === $fieldmap['is_key'] ) {
861
					if ( ! $use_soap ) {
862
						unset( $params[ $salesforce_field ] );
863
					}
864
					$params['key'] = array(
865
						'salesforce_field' => $salesforce_field,
866
						'wordpress_field'  => $wordpress_field,
867
						'value'            => $object[ $wordpress_field ],
868
					);
869
				}
870
871
				// If the field is a prematch in Salesforce, put its name in the params array so we can check for it later.
872
				if ( '1' === $fieldmap['is_prematch'] ) {
873
					$params['prematch'] = array(
874
						'salesforce_field' => $salesforce_field,
875
						'wordpress_field'  => $wordpress_field,
876
						'value'            => $object[ $wordpress_field ],
877
					);
878
				}
879
880
				// Skip fields that aren't being pushed to Salesforce.
881
				if ( ! in_array( $fieldmap['direction'], array_values( $this->direction_wordpress ), true ) ) {
882
					// The trigger is a WordPress trigger, but the fieldmap direction is not a WordPress direction.
883
					unset( $params[ $salesforce_field ] );
884
				}
885
886
				// I think it's good to over-mention that updateable is really how the Salesforce api spells it.
887
				// Skip fields that aren't updateable when mapping params because Salesforce will error otherwise.
888
				// 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.
889
				if ( 1 !== (int) $fieldmap['salesforce_field']['updateable'] ) {
890
					unset( $params[ $salesforce_field ] );
891
				}
892
893
				// This case means the following:
894
				//    this field is expected by the fieldmap
895
				//    Salesforce's api reports that this field is required
896
				//    we do not have a WordPress value for this field, or it's empty
897
				//    it also means the field has not been unset by prematch, updateable, key, or directional flags prior to this check.
898
				// When this happens, we should flag that we're missing a required Salesforce field
899
				if ( in_array( $salesforce_field, $params, true ) && false === filter_var( $fieldmap['salesforce_field']['nillable'], FILTER_VALIDATE_BOOLEAN ) && ( ! isset( $object[ $wordpress_field ] ) || '' === $object[ $wordpress_field ] ) ) {
900
					$has_missing_required_salesforce_field = true;
901
				}
902
903
				// we don't need a continue with the unset methods because there's no array being created down here
904
			} elseif ( in_array( $trigger, $salesforce_haystack, true ) ) {
905
906
				// A Salesforce event caused this.
907
908
				if ( isset( $salesforce_field_type ) && isset( $object[ $salesforce_field ] ) && ! is_null( $object[ $salesforce_field ] ) ) {
909
					// Salesforce provides multipicklist values as a delimited string. If the
910
					// destination field in WordPress accepts multiple values, explode the string into an array and then serialize it.
911
					if ( in_array( $salesforce_field_type, $this->array_types_from_salesforce, true ) ) {
912
						$object[ $salesforce_field ] = explode( $this->array_delimiter, $object[ $salesforce_field ] );
913
						// if the WordPress field is a list of capabilities (the destination field is wp_capabilities), we need to set the array for WordPress to save it.
914
						if ( 'wp_capabilities' === $wordpress_field ) {
915
							$capabilities = array();
916
							foreach ( $object[ $salesforce_field ] as $capability ) {
917
								$capabilities[ $capability ] = true;
918
							}
919
							$object[ $salesforce_field ] = $capabilities;
920
						}
921
					}
922
923
					// Handle specific data types from Salesforce.
924
					switch ( $salesforce_field_type ) {
925
						case ( in_array( $salesforce_field_type, $this->date_types_from_salesforce, true ) ):
926
							$format = get_option( 'date_format', 'U' );
927
							if ( isset( $fieldmap['wordpress_field']['type'] ) && 'datetime' === $fieldmap['wordpress_field']['type'] ) {
928
								$format = 'Y-m-d H:i:s';
929
							}
930
							if ( 'tribe_events' === $mapping['wordpress_object'] && class_exists( 'Tribe__Events__Main' ) ) {
931
								$format = 'Y-m-d H:i:s';
932
							}
933
							if ( 'datetime' === $salesforce_field_type ) {
934
								// Note: the Salesforce REST API appears to always return datetimes as GMT values. We should retrieve them that way, then format them to deal with them in WordPress appropriately.
935
								// We should not do any converting unless it's a datetime, because if it's a date, Salesforce stores it as midnight. We don't want to convert that.
936
								$object[ $salesforce_field ] = get_date_from_gmt( $object[ $salesforce_field ], 'Y-m-d\TH:i:s\Z' ); // convert from GMT to local date/time based on WordPress time zone setting.
937
							}
938
							$object[ $salesforce_field ] = date_i18n( $format, strtotime( $object[ $salesforce_field ] ) );
939
							break;
940
						case ( in_array( $salesforce_field_type, $this->int_types_from_salesforce, true ) ):
941
							$object[ $salesforce_field ] = isset( $object[ $salesforce_field ] ) ? (int) $object[ $salesforce_field ] : 0;
942
							break;
943
						case 'text':
944
							$object[ $salesforce_field ] = (string) $object[ $salesforce_field ];
945
							break;
946
						case 'url':
947
							$object[ $salesforce_field ] = esc_url_raw( $object[ $salesforce_field ] );
948
							break;
949
					}
950
951
					// set a default WordPress status value, if there is one and it's not already set by the object map
952
					$post_status = array_search( 'post_status', array_column( $fieldmap['wordpress_field'], 'label' ), true );
953
					if ( false === $post_status ) {
954
						error_log( 'there is no post status' );
955
					} else {
956
						error_log( 'there is a post status' );
957
					}
958
				}
959
960
				// Make an array because we need to store the methods for each field as well.
961
				if ( isset( $object[ $salesforce_field ] ) && '' !== $object[ $salesforce_field ] ) {
962
					$params[ $wordpress_field ]          = array();
963
					$params[ $wordpress_field ]['value'] = $object[ $salesforce_field ];
964
				} else {
965
					// If we try to save certain fields with empty values, WordPress will silently start skipping stuff. This keeps that from happening.
966
					continue;
967
				}
968
969
				// 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.
970
971
				// If the field is a prematch in Salesforce, put its name in the params array so we can check for it later.
972
				if ( '1' === $fieldmap['is_prematch'] ) {
973
					$params['prematch'] = array(
974
						'salesforce_field' => $salesforce_field,
975
						'wordpress_field'  => $wordpress_field,
976
						'value'            => $object[ $salesforce_field ],
977
						'method_match'     => isset( $fieldmap['wordpress_field']['methods']['match'] ) ? $fieldmap['wordpress_field']['methods']['match'] : $fieldmap['wordpress_field']['methods']['read'],
978
						'method_read'      => $fieldmap['wordpress_field']['methods']['read'],
979
						'method_create'    => $fieldmap['wordpress_field']['methods']['create'],
980
						'method_update'    => $fieldmap['wordpress_field']['methods']['update'],
981
					);
982
				}
983
984
				// Skip fields that aren't being pulled from Salesforce.
985
				if ( ! in_array( $fieldmap['direction'], array_values( $this->direction_salesforce ), true ) ) {
986
					// The trigger is a Salesforce trigger, but the fieldmap direction is not a Salesforce direction.
987
					unset( $params[ $wordpress_field ] );
988
					// we also need to continue here, so it doesn't create an empty array below for fields that are WordPress -> Salesforce only
989
					continue;
990
				}
991
992
				switch ( $trigger ) {
993
					case $this->sync_sf_create:
994
						$params[ $wordpress_field ]['method_modify'] = $fieldmap['wordpress_field']['methods']['create'];
995
						break;
996
					case $this->sync_sf_update:
997
						$params[ $wordpress_field ]['method_modify'] = $fieldmap['wordpress_field']['methods']['update'];
998
						break;
999
					case $this->sync_sf_delete:
1000
						$params[ $wordpress_field ]['method_modify'] = $fieldmap['wordpress_field']['methods']['delete'];
1001
						break;
1002
				}
1003
1004
				$params[ $wordpress_field ]['method_read'] = $fieldmap['wordpress_field']['methods']['read'];
1005
1006
			} // End if().
1007
		} // End foreach().
1008
1009
		if ( true === $has_missing_required_salesforce_field ) {
1010
			update_option( $this->option_prefix . 'missing_required_data_id_' . $object[ $object_id_field ], true, false );
1011
			return array();
1012
		}
1013
1014
		return $params;
1015
1016
	}
1017
1018
	/**
1019
	 * Prepare field map data for use
1020
	 *
1021
	 * @param array  $mappings Array of fieldmaps.
1022
	 * @param string $record_type Optional Salesforce record type to see if it is allowed or not.
1023
	 *
1024
	 * @return array $mappings Associative array of field maps ready to use
1025
	 */
1026
	private function prepare_fieldmap_data( $mappings, $record_type = '' ) {
1027
1028
		foreach ( $mappings as $id => $mapping ) {
1029
			$mappings[ $id ]['salesforce_record_types_allowed'] = maybe_unserialize( $mapping['salesforce_record_types_allowed'] );
1030
			$mappings[ $id ]['fields']                          = maybe_unserialize( $mapping['fields'] );
1031
			$mappings[ $id ]['sync_triggers']                   = maybe_unserialize( $mapping['sync_triggers'] );
1032
			// reverse async to get immediately
1033
			if ( true === filter_var( $mappings[ $id ]['push_async'], FILTER_VALIDATE_BOOLEAN ) ) {
1034
				$mappings[ $id ]['push_immediately'] = '';
1035
			} else {
1036
				$mappings[ $id ]['push_immediately'] = '1';
1037
			}
1038
			if ( '' !== $record_type && ! in_array( $record_type, $mappings[ $id ]['salesforce_record_types_allowed'], true ) ) {
1039
				unset( $mappings[ $id ] );
1040
			}
1041
		}
1042
1043
		return $mappings;
1044
1045
	}
1046
1047
	/**
1048
	 * Check object map table to see if there have been any failed object map create attempts
1049
	 *
1050
	 * @return array $errors Associative array of rows that failed to finish from either system
1051
	 */
1052
	public function get_failed_object_maps() {
1053
		$table       = $this->object_map_table;
1054
		$errors      = array();
1055
		$push_errors = $this->wpdb->get_results( 'SELECT * FROM ' . $table . ' WHERE salesforce_id LIKE "tmp_sf_%"', ARRAY_A );
1056
		$pull_errors = $this->wpdb->get_results( 'SELECT * FROM ' . $table . ' WHERE wordpress_id LIKE "tmp_wp_%"', ARRAY_A );
1057
		if ( ! empty( $push_errors ) ) {
1058
			$errors['push_errors'] = $push_errors;
1059
		}
1060
		if ( ! empty( $pull_errors ) ) {
1061
			$errors['pull_errors'] = $pull_errors;
1062
		}
1063
		return $errors;
1064
	}
1065
1066
	/**
1067
	 * Check object map table to see if there have been any failed object map create attempts
1068
	 *
1069
	 * @param int   $id The ID of a desired mapping.
1070
	 *
1071
	 * @return array $error Associative array of single row that failed to finish based on id
1072
	 */
1073
	public function get_failed_object_map( $id ) {
1074
		$table     = $this->object_map_table;
1075
		$error     = array();
1076
		$error_row = $this->wpdb->get_row( 'SELECT * FROM ' . $table . ' WHERE id = "' . $id . '"', ARRAY_A );
1077
		if ( ! empty( $error_row ) ) {
1078
			$error = $error_row;
1079
		}
1080
		return $error;
1081
	}
1082
1083
}
1084