Completed
Branch BUG/escape-localized-variables (bce518)
by
unknown
08:48 queued 39s
created
core/data_migration_scripts/EE_Data_Migration_Class_Base.core.php 1 patch
Indentation   +404 added lines, -404 removed lines patch added patch discarded remove patch
@@ -17,408 +17,408 @@
 block discarded – undo
17 17
 abstract class EE_Data_Migration_Class_Base
18 18
 {
19 19
 
20
-    /**
21
-     * @var $records_to_migrate int count of all that have been migrated
22
-     */
23
-    protected $_records_to_migrate = 0;
24
-
25
-    /**
26
-     *
27
-     * @var $records_migrated int
28
-     */
29
-    protected $_records_migrated = 0;
30
-
31
-    /**
32
-     * Whether this migration script is done or not. This COULD be deduced by
33
-     * _records_to_migrate and _records_migrated, but that might nto be accurate
34
-     *
35
-     * @var string one of EE_Data_migration_Manager::status_* constants
36
-     */
37
-    protected $_status = null;
38
-
39
-    /**
40
-     * internationalized name of this class. Convention is to NOT restate that
41
-     * this class if a migration script or a migration script stage
42
-     *
43
-     * @var string (i18ned)
44
-     */
45
-    protected $_pretty_name = null;
46
-
47
-    /**
48
-     * @var array
49
-     */
50
-    protected $_errors = array();
51
-
52
-    /**
53
-     * @var \EventEspresso\core\services\database\TableManager $table_manager
54
-     */
55
-    protected $_table_manager;
56
-
57
-    /**
58
-     * @var \EventEspresso\core\services\database\TableAnalysis $table_analysis
59
-     */
60
-    protected $_table_analysis;
61
-
62
-
63
-    /**
64
-     * Just initializes the status of the migration
65
-     *
66
-     * @param TableManager  $table_manager
67
-     * @param TableAnalysis $table_analysis
68
-     */
69
-    public function __construct(TableManager $table_manager = null, TableAnalysis $table_analysis = null)
70
-    {
71
-        $this->_table_manager = $table_manager;
72
-        $this->_table_analysis = $table_analysis;
73
-        $this->set_status(EE_Data_Migration_Manager::status_continue);
74
-    }
75
-
76
-
77
-    /**
78
-     * Just gets the pretty name for this migration script or stage
79
-     *
80
-     * @throws EE_Error
81
-     * @return string
82
-     */
83
-    public function pretty_name()
84
-    {
85
-        if ($this->_pretty_name === null) {
86
-            throw new EE_Error(
87
-                sprintf(
88
-                    __(
89
-                        "Please give a pretty name to the migration script stage %s by assigning the property _pretty_name in the constructor",
90
-                        "event_espresso"
91
-                    ),
92
-                    get_class($this)
93
-                )
94
-            );
95
-        }
96
-        return $this->_pretty_name;
97
-    }
98
-
99
-    /**
100
-     *
101
-     * @return int
102
-     */
103
-    public function count_records_to_migrate()
104
-    {
105
-        if ($this->_records_to_migrate == null) {
106
-            $this->_records_to_migrate = $this->_count_records_to_migrate();
107
-        }
108
-        return $this->_records_to_migrate;
109
-    }
110
-
111
-    /**
112
-     * Counts records already migrated. This should only be implemented by EE_Data_Migration_Script_base and
113
-     * EE_Data_migration_Script_Stage
114
-     *
115
-     * @return int
116
-     */
117
-    abstract public function count_records_migrated();
118
-
119
-    /**
120
-     * Counts the records to migrate; the public version may cache it
121
-     *
122
-     * @return int
123
-     */
124
-    abstract protected function _count_records_to_migrate();
125
-
126
-    /**
127
-     * Returns a string indicating the migration script's status.
128
-     *
129
-     * @return string one of EE_Data_Migration_Manager::status_* constants
130
-     * @throws EE_Error
131
-     */
132
-    public function get_status()
133
-    {
134
-        if ($this->_status === null) {
135
-            throw new EE_Error(
136
-                sprintf(
137
-                    __(
138
-                        "Trying to get status of Migration class %s, but it has not been initialized yet. It should be set in the constructor.",
139
-                        "event_espresso"
140
-                    ),
141
-                    get_class($this)
142
-                )
143
-            );
144
-        }
145
-        return $this->_status;
146
-    }
147
-
148
-    /**
149
-     *
150
-     * @param string $status
151
-     * @return void
152
-     */
153
-    protected function set_status($status)
154
-    {
155
-        $this->_status = $status;
156
-    }
157
-
158
-    /**
159
-     * @return array of strings
160
-     */
161
-    abstract public function get_errors();
162
-
163
-    /**
164
-     * Returns the last error that occurred. If none occurred, returns null
165
-     *
166
-     * @return string
167
-     */
168
-    public function get_last_error()
169
-    {
170
-        $errors = $this->get_errors();
171
-        if ($errors) {
172
-            return end($errors);
173
-        } else {
174
-            return null;
175
-        }
176
-    }
177
-
178
-    /**
179
-     * Adds an error to the array of errors on this class.
180
-     *
181
-     * @param string  $error a string describing the error that will be useful for debugging. Consider including all
182
-     *                       the data that led to the error, and a stack trace etc.
183
-     * @param boolean $force force the error to be added (because otherwise we have a limit). If forcing and errors are
184
-     *                       already at their limit, we will purposefully forget the first half
185
-     */
186
-    public function add_error($error, $force = false)
187
-    {
188
-        if (! defined('EE_DMS_ERROR_LIMIT')) {
189
-            $limit = 50;
190
-        } else {
191
-            $limit = EE_DMS_ERROR_LIMIT;
192
-        }
193
-        // make sure errors is an array, see ticket #8261
194
-        if (is_string($this->_errors)) {
195
-            $this->_errors = array($this->_errors);
196
-        }
197
-        if (count($this->_errors) >= $limit) {
198
-            if ($force) {
199
-                // get rid of the first half of the errors and any above the limit
200
-                $this->_errors = array_slice($this->_errors, $limit / 2, $limit / 2);
201
-                $this->_errors[] = "Limit reached; removed first half of errors to save space";
202
-                $this->_errors[] = $error;
203
-            } else {
204
-                $this->_errors[ $limit ] = 'More, but limit reached...';
205
-            }
206
-        } else {
207
-            $this->_errors[] = $error;
208
-        }
209
-    }
210
-
211
-    /**
212
-     * Indicates there was a fatal error and the migration cannot possibly continue
213
-     *
214
-     * @return boolean
215
-     */
216
-    public function is_broken()
217
-    {
218
-        return $this->get_status() == EE_Data_Migration_Manager::status_fatal_error;
219
-    }
220
-
221
-    /**
222
-     * @deprecated since 4.6.12
223
-     */
224
-    public function is_borked()
225
-    {
226
-        EE_Error::doing_it_wrong(
227
-            'is_borked',
228
-            __(
229
-                'The cheeky "is_borked" method had been replaced with the more proper "is_broken"',
230
-                'event_espresso'
231
-            ),
232
-            '4.6.12'
233
-        );
234
-        return $this->is_broken();
235
-    }
236
-
237
-    /**
238
-     * Sets the status to as having a fatal error
239
-     */
240
-    public function set_broken()
241
-    {
242
-        $this->_status = EE_Data_Migration_Manager::status_fatal_error;
243
-    }
244
-
245
-    /**
246
-     *
247
-     * @deprecated since 4.6.12
248
-     */
249
-    public function set_borked()
250
-    {
251
-        EE_Error::doing_it_wrong(
252
-            'is_borked',
253
-            __(
254
-                'The cheeky "is_borked" method had been replaced with the more proper "is_broken"',
255
-                'event_espresso'
256
-            ),
257
-            '4.6.12'
258
-        );
259
-        return $this->set_broken();
260
-    }
261
-
262
-    /**
263
-     * Checks if this thing believes it is completed
264
-     *
265
-     * @return boolean
266
-     */
267
-    public function is_completed()
268
-    {
269
-        return $this->get_status() == EE_Data_Migration_Manager::status_completed;
270
-    }
271
-
272
-    /**
273
-     * Checks if the current script has more to do or not (ie, if it's status is CONTINUE)
274
-     *
275
-     * @return boolean
276
-     */
277
-    public function has_more_to_do()
278
-    {
279
-        return $this->get_status() == EE_Data_Migration_Manager::status_continue;
280
-    }
281
-
282
-    /**
283
-     * Marks that we believe this migration thing is completed
284
-     */
285
-    public function set_completed()
286
-    {
287
-        $this->_status = EE_Data_Migration_Manager::status_completed;
288
-    }
289
-
290
-    /**
291
-     * Marks that we think this migration class can continue to migrate
292
-     */
293
-    public function reattempt()
294
-    {
295
-        $this->_status = EE_Data_Migration_Manager::status_continue;
296
-        $this->add_error(__('Reattempt migration', 'event_espresso'), true);
297
-    }
298
-
299
-    /**
300
-     * A lot like "__sleep()" magic method in purpose, this is meant for persisting this class'
301
-     * properties to the DB. However, we don't want to use __sleep() because its quite
302
-     * possible that this class is defined when it goes to sleep, but NOT available when it
303
-     * awakes (eg, this class is part of an addon that is deactivated at some point).
304
-     */
305
-    public function properties_as_array()
306
-    {
307
-        $properties = get_object_vars($this);
308
-        $properties['class'] = get_class($this);
309
-        unset($properties['_migration_script']);
310
-        unset($properties['_table_manager']);
311
-        unset($properties['_table_analysis']);
312
-        return $properties;
313
-    }
314
-
315
-    /**
316
-     * Sets all of the properties of this script stage to match what's in the array, which is assumed
317
-     * to have been made from the properties_as_array() function.
318
-     *
319
-     * @param array $array_of_properties like what's produced from properties_as_array() method
320
-     */
321
-    abstract public function instantiate_from_array_of_properties($array_of_properties);
322
-
323
-    /**
324
-     * Convenience method for showing a database insertion error
325
-     *
326
-     * @param string $old_table
327
-     * @param array  $old_row_as_array
328
-     * @param string $new_table
329
-     * @param array  $new_row_as_array columns=>values like used in wpdb->insert
330
-     * @param array  $data_types       numerically indexed
331
-     * @return string
332
-     */
333
-    protected function _create_error_message_for_db_insertion(
334
-        $old_table,
335
-        $old_row_as_array,
336
-        $new_table,
337
-        $new_row_as_array,
338
-        $data_types
339
-    ) {
340
-        global $wpdb;
341
-        $old_columns_and_values_for_string = array();
342
-        foreach ($old_row_as_array as $column => $value) {
343
-            $old_columns_and_values_for_string[] = "$column => $value";
344
-        }
345
-        $new_columns_and_values_for_string = array();
346
-        $count = 0;
347
-        foreach ($new_row_as_array as $column => $value) {
348
-            $new_columns_and_values_for_string[] = " $column => $value (" . $data_types[ $count++ ] . ")";
349
-        }
350
-        return sprintf(
351
-            __(
352
-                'Received error "%6$s" inserting row %5$s %1$s %5$s into table %2$s.%5$s Data used was %5$s %3$s %5$s from table %4$s.',
353
-                'event_espresso'
354
-            ),
355
-            implode(", ", $new_columns_and_values_for_string),
356
-            $new_table,
357
-            implode(", ", $old_columns_and_values_for_string),
358
-            $old_table,
359
-            '<br/>',
360
-            $wpdb->last_error
361
-        );
362
-    }
363
-
364
-
365
-    /**
366
-     * Same as json_encode, just avoids putting
367
-     * serialized arrays into the http build query, as that would
368
-     *
369
-     * @param array $array_of_data
370
-     * @return string
371
-     */
372
-    protected function _json_encode($array_of_data)
373
-    {
374
-        // we'd rather NOT serialize the transaction details
375
-        $fields_to_include = array();
376
-        foreach ($array_of_data as $name => $value) {
377
-            $unserialized_data = @unserialize($value);
378
-            if ($unserialized_data === false) {
379
-                $fields_to_include[ $name ] = $value;
380
-            }
381
-        }
382
-        return wp_json_encode($fields_to_include);
383
-    }
384
-
385
-    /**
386
-     * Gets the table manager (or throws an exception if it cannot be retrieved)
387
-     *
388
-     * @return TableManager
389
-     * @throws EE_Error
390
-     */
391
-    protected function _get_table_manager()
392
-    {
393
-        if ($this->_table_manager instanceof TableManager) {
394
-            return $this->_table_manager;
395
-        } else {
396
-            throw new EE_Error(
397
-                sprintf(
398
-                    __('Table manager on migration class %1$s is not set properly.', 'event_espresso'),
399
-                    get_class($this)
400
-                )
401
-            );
402
-        }
403
-    }
404
-
405
-    /**
406
-     * Gets the injected table analyzer, or throws an exception
407
-     *
408
-     * @return TableAnalysis
409
-     * @throws EE_Error
410
-     */
411
-    protected function _get_table_analysis()
412
-    {
413
-        if ($this->_table_analysis instanceof TableAnalysis) {
414
-            return $this->_table_analysis;
415
-        } else {
416
-            throw new EE_Error(
417
-                sprintf(
418
-                    __('Table analysis class on migration class %1$s is not set properly.', 'event_espresso'),
419
-                    get_class($this)
420
-                )
421
-            );
422
-        }
423
-    }
20
+	/**
21
+	 * @var $records_to_migrate int count of all that have been migrated
22
+	 */
23
+	protected $_records_to_migrate = 0;
24
+
25
+	/**
26
+	 *
27
+	 * @var $records_migrated int
28
+	 */
29
+	protected $_records_migrated = 0;
30
+
31
+	/**
32
+	 * Whether this migration script is done or not. This COULD be deduced by
33
+	 * _records_to_migrate and _records_migrated, but that might nto be accurate
34
+	 *
35
+	 * @var string one of EE_Data_migration_Manager::status_* constants
36
+	 */
37
+	protected $_status = null;
38
+
39
+	/**
40
+	 * internationalized name of this class. Convention is to NOT restate that
41
+	 * this class if a migration script or a migration script stage
42
+	 *
43
+	 * @var string (i18ned)
44
+	 */
45
+	protected $_pretty_name = null;
46
+
47
+	/**
48
+	 * @var array
49
+	 */
50
+	protected $_errors = array();
51
+
52
+	/**
53
+	 * @var \EventEspresso\core\services\database\TableManager $table_manager
54
+	 */
55
+	protected $_table_manager;
56
+
57
+	/**
58
+	 * @var \EventEspresso\core\services\database\TableAnalysis $table_analysis
59
+	 */
60
+	protected $_table_analysis;
61
+
62
+
63
+	/**
64
+	 * Just initializes the status of the migration
65
+	 *
66
+	 * @param TableManager  $table_manager
67
+	 * @param TableAnalysis $table_analysis
68
+	 */
69
+	public function __construct(TableManager $table_manager = null, TableAnalysis $table_analysis = null)
70
+	{
71
+		$this->_table_manager = $table_manager;
72
+		$this->_table_analysis = $table_analysis;
73
+		$this->set_status(EE_Data_Migration_Manager::status_continue);
74
+	}
75
+
76
+
77
+	/**
78
+	 * Just gets the pretty name for this migration script or stage
79
+	 *
80
+	 * @throws EE_Error
81
+	 * @return string
82
+	 */
83
+	public function pretty_name()
84
+	{
85
+		if ($this->_pretty_name === null) {
86
+			throw new EE_Error(
87
+				sprintf(
88
+					__(
89
+						"Please give a pretty name to the migration script stage %s by assigning the property _pretty_name in the constructor",
90
+						"event_espresso"
91
+					),
92
+					get_class($this)
93
+				)
94
+			);
95
+		}
96
+		return $this->_pretty_name;
97
+	}
98
+
99
+	/**
100
+	 *
101
+	 * @return int
102
+	 */
103
+	public function count_records_to_migrate()
104
+	{
105
+		if ($this->_records_to_migrate == null) {
106
+			$this->_records_to_migrate = $this->_count_records_to_migrate();
107
+		}
108
+		return $this->_records_to_migrate;
109
+	}
110
+
111
+	/**
112
+	 * Counts records already migrated. This should only be implemented by EE_Data_Migration_Script_base and
113
+	 * EE_Data_migration_Script_Stage
114
+	 *
115
+	 * @return int
116
+	 */
117
+	abstract public function count_records_migrated();
118
+
119
+	/**
120
+	 * Counts the records to migrate; the public version may cache it
121
+	 *
122
+	 * @return int
123
+	 */
124
+	abstract protected function _count_records_to_migrate();
125
+
126
+	/**
127
+	 * Returns a string indicating the migration script's status.
128
+	 *
129
+	 * @return string one of EE_Data_Migration_Manager::status_* constants
130
+	 * @throws EE_Error
131
+	 */
132
+	public function get_status()
133
+	{
134
+		if ($this->_status === null) {
135
+			throw new EE_Error(
136
+				sprintf(
137
+					__(
138
+						"Trying to get status of Migration class %s, but it has not been initialized yet. It should be set in the constructor.",
139
+						"event_espresso"
140
+					),
141
+					get_class($this)
142
+				)
143
+			);
144
+		}
145
+		return $this->_status;
146
+	}
147
+
148
+	/**
149
+	 *
150
+	 * @param string $status
151
+	 * @return void
152
+	 */
153
+	protected function set_status($status)
154
+	{
155
+		$this->_status = $status;
156
+	}
157
+
158
+	/**
159
+	 * @return array of strings
160
+	 */
161
+	abstract public function get_errors();
162
+
163
+	/**
164
+	 * Returns the last error that occurred. If none occurred, returns null
165
+	 *
166
+	 * @return string
167
+	 */
168
+	public function get_last_error()
169
+	{
170
+		$errors = $this->get_errors();
171
+		if ($errors) {
172
+			return end($errors);
173
+		} else {
174
+			return null;
175
+		}
176
+	}
177
+
178
+	/**
179
+	 * Adds an error to the array of errors on this class.
180
+	 *
181
+	 * @param string  $error a string describing the error that will be useful for debugging. Consider including all
182
+	 *                       the data that led to the error, and a stack trace etc.
183
+	 * @param boolean $force force the error to be added (because otherwise we have a limit). If forcing and errors are
184
+	 *                       already at their limit, we will purposefully forget the first half
185
+	 */
186
+	public function add_error($error, $force = false)
187
+	{
188
+		if (! defined('EE_DMS_ERROR_LIMIT')) {
189
+			$limit = 50;
190
+		} else {
191
+			$limit = EE_DMS_ERROR_LIMIT;
192
+		}
193
+		// make sure errors is an array, see ticket #8261
194
+		if (is_string($this->_errors)) {
195
+			$this->_errors = array($this->_errors);
196
+		}
197
+		if (count($this->_errors) >= $limit) {
198
+			if ($force) {
199
+				// get rid of the first half of the errors and any above the limit
200
+				$this->_errors = array_slice($this->_errors, $limit / 2, $limit / 2);
201
+				$this->_errors[] = "Limit reached; removed first half of errors to save space";
202
+				$this->_errors[] = $error;
203
+			} else {
204
+				$this->_errors[ $limit ] = 'More, but limit reached...';
205
+			}
206
+		} else {
207
+			$this->_errors[] = $error;
208
+		}
209
+	}
210
+
211
+	/**
212
+	 * Indicates there was a fatal error and the migration cannot possibly continue
213
+	 *
214
+	 * @return boolean
215
+	 */
216
+	public function is_broken()
217
+	{
218
+		return $this->get_status() == EE_Data_Migration_Manager::status_fatal_error;
219
+	}
220
+
221
+	/**
222
+	 * @deprecated since 4.6.12
223
+	 */
224
+	public function is_borked()
225
+	{
226
+		EE_Error::doing_it_wrong(
227
+			'is_borked',
228
+			__(
229
+				'The cheeky "is_borked" method had been replaced with the more proper "is_broken"',
230
+				'event_espresso'
231
+			),
232
+			'4.6.12'
233
+		);
234
+		return $this->is_broken();
235
+	}
236
+
237
+	/**
238
+	 * Sets the status to as having a fatal error
239
+	 */
240
+	public function set_broken()
241
+	{
242
+		$this->_status = EE_Data_Migration_Manager::status_fatal_error;
243
+	}
244
+
245
+	/**
246
+	 *
247
+	 * @deprecated since 4.6.12
248
+	 */
249
+	public function set_borked()
250
+	{
251
+		EE_Error::doing_it_wrong(
252
+			'is_borked',
253
+			__(
254
+				'The cheeky "is_borked" method had been replaced with the more proper "is_broken"',
255
+				'event_espresso'
256
+			),
257
+			'4.6.12'
258
+		);
259
+		return $this->set_broken();
260
+	}
261
+
262
+	/**
263
+	 * Checks if this thing believes it is completed
264
+	 *
265
+	 * @return boolean
266
+	 */
267
+	public function is_completed()
268
+	{
269
+		return $this->get_status() == EE_Data_Migration_Manager::status_completed;
270
+	}
271
+
272
+	/**
273
+	 * Checks if the current script has more to do or not (ie, if it's status is CONTINUE)
274
+	 *
275
+	 * @return boolean
276
+	 */
277
+	public function has_more_to_do()
278
+	{
279
+		return $this->get_status() == EE_Data_Migration_Manager::status_continue;
280
+	}
281
+
282
+	/**
283
+	 * Marks that we believe this migration thing is completed
284
+	 */
285
+	public function set_completed()
286
+	{
287
+		$this->_status = EE_Data_Migration_Manager::status_completed;
288
+	}
289
+
290
+	/**
291
+	 * Marks that we think this migration class can continue to migrate
292
+	 */
293
+	public function reattempt()
294
+	{
295
+		$this->_status = EE_Data_Migration_Manager::status_continue;
296
+		$this->add_error(__('Reattempt migration', 'event_espresso'), true);
297
+	}
298
+
299
+	/**
300
+	 * A lot like "__sleep()" magic method in purpose, this is meant for persisting this class'
301
+	 * properties to the DB. However, we don't want to use __sleep() because its quite
302
+	 * possible that this class is defined when it goes to sleep, but NOT available when it
303
+	 * awakes (eg, this class is part of an addon that is deactivated at some point).
304
+	 */
305
+	public function properties_as_array()
306
+	{
307
+		$properties = get_object_vars($this);
308
+		$properties['class'] = get_class($this);
309
+		unset($properties['_migration_script']);
310
+		unset($properties['_table_manager']);
311
+		unset($properties['_table_analysis']);
312
+		return $properties;
313
+	}
314
+
315
+	/**
316
+	 * Sets all of the properties of this script stage to match what's in the array, which is assumed
317
+	 * to have been made from the properties_as_array() function.
318
+	 *
319
+	 * @param array $array_of_properties like what's produced from properties_as_array() method
320
+	 */
321
+	abstract public function instantiate_from_array_of_properties($array_of_properties);
322
+
323
+	/**
324
+	 * Convenience method for showing a database insertion error
325
+	 *
326
+	 * @param string $old_table
327
+	 * @param array  $old_row_as_array
328
+	 * @param string $new_table
329
+	 * @param array  $new_row_as_array columns=>values like used in wpdb->insert
330
+	 * @param array  $data_types       numerically indexed
331
+	 * @return string
332
+	 */
333
+	protected function _create_error_message_for_db_insertion(
334
+		$old_table,
335
+		$old_row_as_array,
336
+		$new_table,
337
+		$new_row_as_array,
338
+		$data_types
339
+	) {
340
+		global $wpdb;
341
+		$old_columns_and_values_for_string = array();
342
+		foreach ($old_row_as_array as $column => $value) {
343
+			$old_columns_and_values_for_string[] = "$column => $value";
344
+		}
345
+		$new_columns_and_values_for_string = array();
346
+		$count = 0;
347
+		foreach ($new_row_as_array as $column => $value) {
348
+			$new_columns_and_values_for_string[] = " $column => $value (" . $data_types[ $count++ ] . ")";
349
+		}
350
+		return sprintf(
351
+			__(
352
+				'Received error "%6$s" inserting row %5$s %1$s %5$s into table %2$s.%5$s Data used was %5$s %3$s %5$s from table %4$s.',
353
+				'event_espresso'
354
+			),
355
+			implode(", ", $new_columns_and_values_for_string),
356
+			$new_table,
357
+			implode(", ", $old_columns_and_values_for_string),
358
+			$old_table,
359
+			'<br/>',
360
+			$wpdb->last_error
361
+		);
362
+	}
363
+
364
+
365
+	/**
366
+	 * Same as json_encode, just avoids putting
367
+	 * serialized arrays into the http build query, as that would
368
+	 *
369
+	 * @param array $array_of_data
370
+	 * @return string
371
+	 */
372
+	protected function _json_encode($array_of_data)
373
+	{
374
+		// we'd rather NOT serialize the transaction details
375
+		$fields_to_include = array();
376
+		foreach ($array_of_data as $name => $value) {
377
+			$unserialized_data = @unserialize($value);
378
+			if ($unserialized_data === false) {
379
+				$fields_to_include[ $name ] = $value;
380
+			}
381
+		}
382
+		return wp_json_encode($fields_to_include);
383
+	}
384
+
385
+	/**
386
+	 * Gets the table manager (or throws an exception if it cannot be retrieved)
387
+	 *
388
+	 * @return TableManager
389
+	 * @throws EE_Error
390
+	 */
391
+	protected function _get_table_manager()
392
+	{
393
+		if ($this->_table_manager instanceof TableManager) {
394
+			return $this->_table_manager;
395
+		} else {
396
+			throw new EE_Error(
397
+				sprintf(
398
+					__('Table manager on migration class %1$s is not set properly.', 'event_espresso'),
399
+					get_class($this)
400
+				)
401
+			);
402
+		}
403
+	}
404
+
405
+	/**
406
+	 * Gets the injected table analyzer, or throws an exception
407
+	 *
408
+	 * @return TableAnalysis
409
+	 * @throws EE_Error
410
+	 */
411
+	protected function _get_table_analysis()
412
+	{
413
+		if ($this->_table_analysis instanceof TableAnalysis) {
414
+			return $this->_table_analysis;
415
+		} else {
416
+			throw new EE_Error(
417
+				sprintf(
418
+					__('Table analysis class on migration class %1$s is not set properly.', 'event_espresso'),
419
+					get_class($this)
420
+				)
421
+			);
422
+		}
423
+	}
424 424
 }
Please login to merge, or discard this patch.
4_10_0_stages/EE_DMS_4_10_0_Event_Question_Group.dmsstage.php 2 patches
Indentation   +110 added lines, -110 removed lines patch added patch discarded remove patch
@@ -14,118 +14,118 @@
 block discarded – undo
14 14
 
15 15
 
16 16
 
17
-    /**
18
-     * Just initializes the status of the migration
19
-     */
20
-    public function __construct()
21
-    {
22
-        global $wpdb;
23
-        $this->_pretty_name = __('Event-Question Group Relations', 'event_espresso');
24
-        $this->_old_table = $wpdb->prefix.'esp_event_question_group';
25
-        $this->_extra_where_sql = "WHERE EQG_primary = 0 AND EQG_additional=0";
26
-        parent::__construct();
27
-    }
17
+	/**
18
+	 * Just initializes the status of the migration
19
+	 */
20
+	public function __construct()
21
+	{
22
+		global $wpdb;
23
+		$this->_pretty_name = __('Event-Question Group Relations', 'event_espresso');
24
+		$this->_old_table = $wpdb->prefix.'esp_event_question_group';
25
+		$this->_extra_where_sql = "WHERE EQG_primary = 0 AND EQG_additional=0";
26
+		parent::__construct();
27
+	}
28 28
 
29 29
 
30
-    /**
31
-     * Removes the duplicate event_question_group rows that only had EQG_primary=0. Now we just have one row
32
-     * joining event-to-question-groups with two columns: EQG_primary and EQG_additional, indicating which question
33
-     * groups apply to which category of registrant.
34
-     * @param array $event_question_group an associative array where keys are column names and values are their values.
35
-     * @return null
36
-     */
37
-    protected function _migrate_old_row($event_question_group)
38
-    {
39
-        if (isset($event_question_group['EVT_ID'], $event_question_group['QSG_ID'])) {
40
-            global $wpdb;
41
-            // If the question group was also for primary attendees, we should just update that row.
42
-            // And we delete this row.
43
-            $success = $wpdb->update(
44
-                $this->_old_table,
45
-                ['EQG_additional' => true],  // data
46
-                [
47
-                    'EQG_primary' => true,
48
-                    'EVT_ID' => $event_question_group['EVT_ID'],
49
-                    'QSG_ID' => $event_question_group['QSG_ID']
50
-                ],  // where
51
-                array( '%d' ),   // data format
52
-                array( '%d', '%d', '%d' )  // where format
53
-            );
54
-            if ($success) {
55
-                // Ok it's confirmed: the question group WAS for the primary attendee group too. So
56
-                // now we just need to delete this row.
57
-                $successful_delete = $wpdb->delete(
58
-                    $this->_old_table,
59
-                    [
60
-                        'EQG_ID' => $event_question_group['EQG_ID']
61
-                    ],
62
-                    ['%d']
63
-                );
64
-                if (! $successful_delete) {
65
-                    $this->add_error(
66
-                        sprintf(
67
-                            __('Could not delete old event-question group relation row "%1$s" because "%2$s"', 'event_espresso'),
68
-                            wp_json_encode($event_question_group),
69
-                            $wpdb->last_error
70
-                        )
71
-                    );
72
-                }
73
-            } else {
74
-                // Oh, the question group actually was NOT for the primary attendee. So we just need to update this row
75
-                $wpdb->update(
76
-                    $this->_old_table,
77
-                    ['EQG_additional' => true],  // data
78
-                    [
79
-                        'EVT_ID' => $event_question_group['EVT_ID'],
80
-                        'QSG_ID' => $event_question_group['QSG_ID']
81
-                    ],  // where
82
-                    array( '%d' ),   // data format
83
-                    array( '%d', '%d', '%d' )  // where format
84
-                );
85
-            }
86
-        }
87
-    }
30
+	/**
31
+	 * Removes the duplicate event_question_group rows that only had EQG_primary=0. Now we just have one row
32
+	 * joining event-to-question-groups with two columns: EQG_primary and EQG_additional, indicating which question
33
+	 * groups apply to which category of registrant.
34
+	 * @param array $event_question_group an associative array where keys are column names and values are their values.
35
+	 * @return null
36
+	 */
37
+	protected function _migrate_old_row($event_question_group)
38
+	{
39
+		if (isset($event_question_group['EVT_ID'], $event_question_group['QSG_ID'])) {
40
+			global $wpdb;
41
+			// If the question group was also for primary attendees, we should just update that row.
42
+			// And we delete this row.
43
+			$success = $wpdb->update(
44
+				$this->_old_table,
45
+				['EQG_additional' => true],  // data
46
+				[
47
+					'EQG_primary' => true,
48
+					'EVT_ID' => $event_question_group['EVT_ID'],
49
+					'QSG_ID' => $event_question_group['QSG_ID']
50
+				],  // where
51
+				array( '%d' ),   // data format
52
+				array( '%d', '%d', '%d' )  // where format
53
+			);
54
+			if ($success) {
55
+				// Ok it's confirmed: the question group WAS for the primary attendee group too. So
56
+				// now we just need to delete this row.
57
+				$successful_delete = $wpdb->delete(
58
+					$this->_old_table,
59
+					[
60
+						'EQG_ID' => $event_question_group['EQG_ID']
61
+					],
62
+					['%d']
63
+				);
64
+				if (! $successful_delete) {
65
+					$this->add_error(
66
+						sprintf(
67
+							__('Could not delete old event-question group relation row "%1$s" because "%2$s"', 'event_espresso'),
68
+							wp_json_encode($event_question_group),
69
+							$wpdb->last_error
70
+						)
71
+					);
72
+				}
73
+			} else {
74
+				// Oh, the question group actually was NOT for the primary attendee. So we just need to update this row
75
+				$wpdb->update(
76
+					$this->_old_table,
77
+					['EQG_additional' => true],  // data
78
+					[
79
+						'EVT_ID' => $event_question_group['EVT_ID'],
80
+						'QSG_ID' => $event_question_group['QSG_ID']
81
+					],  // where
82
+					array( '%d' ),   // data format
83
+					array( '%d', '%d', '%d' )  // where format
84
+				);
85
+			}
86
+		}
87
+	}
88 88
 
89
-    /**
90
-     * Gets the rows for the existing table that shouldn't exist in 4.10.
91
-     * Specifically the rows where EQG_primary=false and EQG_additional=false.
92
-     * Gotcha: because the migration is REMOVING rows as it goes, we shouldn't use the offset.
93
-     *
94
-     * @global wpdb $wpdb
95
-     * @param int   $limit
96
-     * @return array of arrays like $wpdb->get_results($sql, ARRAY_A)
97
-     */
98
-    protected function _get_rows($limit)
99
-    {
100
-        global $wpdb;
101
-        $query = "SELECT * FROM {$this->_old_table} {$this->_extra_where_sql} " . $wpdb->prepare(
102
-            "LIMIT %d",
103
-            $limit
104
-        );
105
-        return $wpdb->get_results($query, ARRAY_A);
106
-    }
89
+	/**
90
+	 * Gets the rows for the existing table that shouldn't exist in 4.10.
91
+	 * Specifically the rows where EQG_primary=false and EQG_additional=false.
92
+	 * Gotcha: because the migration is REMOVING rows as it goes, we shouldn't use the offset.
93
+	 *
94
+	 * @global wpdb $wpdb
95
+	 * @param int   $limit
96
+	 * @return array of arrays like $wpdb->get_results($sql, ARRAY_A)
97
+	 */
98
+	protected function _get_rows($limit)
99
+	{
100
+		global $wpdb;
101
+		$query = "SELECT * FROM {$this->_old_table} {$this->_extra_where_sql} " . $wpdb->prepare(
102
+			"LIMIT %d",
103
+			$limit
104
+		);
105
+		return $wpdb->get_results($query, ARRAY_A);
106
+	}
107 107
 
108
-    /**
109
-     * Slight departure from the normal procedure here: because this removes rows from the DB, we need to ensure
110
-     * we count the records first, then do the migration.
111
-     *
112
-     * @param int $num_items
113
-     * @return int number of items ACTUALLY migrated
114
-     */
115
-    public function _migration_step($num_items = 50)
116
-    {
117
-        // Count the items right away. This migration step will be removing those rows, so we need to count them
118
-        // right away to get an accurate count.
119
-        $this->count_records_to_migrate();
120
-        $rows = $this->_get_rows($num_items);
121
-        $items_actually_migrated = 0;
122
-        foreach ($rows as $old_row) {
123
-            $this->_migrate_old_row($old_row);
124
-            $items_actually_migrated++;
125
-        }
126
-        if ($this->count_records_migrated() + $items_actually_migrated >= $this->count_records_to_migrate()) {
127
-            $this->set_completed();
128
-        }
129
-        return $items_actually_migrated;
130
-    }
108
+	/**
109
+	 * Slight departure from the normal procedure here: because this removes rows from the DB, we need to ensure
110
+	 * we count the records first, then do the migration.
111
+	 *
112
+	 * @param int $num_items
113
+	 * @return int number of items ACTUALLY migrated
114
+	 */
115
+	public function _migration_step($num_items = 50)
116
+	{
117
+		// Count the items right away. This migration step will be removing those rows, so we need to count them
118
+		// right away to get an accurate count.
119
+		$this->count_records_to_migrate();
120
+		$rows = $this->_get_rows($num_items);
121
+		$items_actually_migrated = 0;
122
+		foreach ($rows as $old_row) {
123
+			$this->_migrate_old_row($old_row);
124
+			$items_actually_migrated++;
125
+		}
126
+		if ($this->count_records_migrated() + $items_actually_migrated >= $this->count_records_to_migrate()) {
127
+			$this->set_completed();
128
+		}
129
+		return $items_actually_migrated;
130
+	}
131 131
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -42,14 +42,14 @@  discard block
 block discarded – undo
42 42
             // And we delete this row.
43 43
             $success = $wpdb->update(
44 44
                 $this->_old_table,
45
-                ['EQG_additional' => true],  // data
45
+                ['EQG_additional' => true], // data
46 46
                 [
47 47
                     'EQG_primary' => true,
48 48
                     'EVT_ID' => $event_question_group['EVT_ID'],
49 49
                     'QSG_ID' => $event_question_group['QSG_ID']
50
-                ],  // where
51
-                array( '%d' ),   // data format
52
-                array( '%d', '%d', '%d' )  // where format
50
+                ], // where
51
+                array('%d'), // data format
52
+                array('%d', '%d', '%d')  // where format
53 53
             );
54 54
             if ($success) {
55 55
                 // Ok it's confirmed: the question group WAS for the primary attendee group too. So
@@ -61,7 +61,7 @@  discard block
 block discarded – undo
61 61
                     ],
62 62
                     ['%d']
63 63
                 );
64
-                if (! $successful_delete) {
64
+                if ( ! $successful_delete) {
65 65
                     $this->add_error(
66 66
                         sprintf(
67 67
                             __('Could not delete old event-question group relation row "%1$s" because "%2$s"', 'event_espresso'),
@@ -74,13 +74,13 @@  discard block
 block discarded – undo
74 74
                 // Oh, the question group actually was NOT for the primary attendee. So we just need to update this row
75 75
                 $wpdb->update(
76 76
                     $this->_old_table,
77
-                    ['EQG_additional' => true],  // data
77
+                    ['EQG_additional' => true], // data
78 78
                     [
79 79
                         'EVT_ID' => $event_question_group['EVT_ID'],
80 80
                         'QSG_ID' => $event_question_group['QSG_ID']
81
-                    ],  // where
82
-                    array( '%d' ),   // data format
83
-                    array( '%d', '%d', '%d' )  // where format
81
+                    ], // where
82
+                    array('%d'), // data format
83
+                    array('%d', '%d', '%d')  // where format
84 84
                 );
85 85
             }
86 86
         }
@@ -98,7 +98,7 @@  discard block
 block discarded – undo
98 98
     protected function _get_rows($limit)
99 99
     {
100 100
         global $wpdb;
101
-        $query = "SELECT * FROM {$this->_old_table} {$this->_extra_where_sql} " . $wpdb->prepare(
101
+        $query = "SELECT * FROM {$this->_old_table} {$this->_extra_where_sql} ".$wpdb->prepare(
102 102
             "LIMIT %d",
103 103
             $limit
104 104
         );
Please login to merge, or discard this patch.
core/data_migration_scripts/EE_Data_Migration_Script_Base.core.php 1 patch
Indentation   +882 added lines, -882 removed lines patch added patch discarded remove patch
@@ -15,886 +15,886 @@
 block discarded – undo
15 15
 abstract class EE_Data_Migration_Script_Base extends EE_Data_Migration_Class_Base
16 16
 {
17 17
 
18
-    /**
19
-     * Set by client code to indicate this DMS is being ran as part of a proper migration,
20
-     * instead of being used to merely setup (or verify) the database structure.
21
-     * Defaults to TRUE, so client code that's NOT using this DMS as part of a proper migration
22
-     * should call EE_Data_Migration_Script_Base::set_migrating( FALSE )
23
-     *
24
-     * @var boolean
25
-     */
26
-    protected $_migrating = true;
27
-
28
-    /**
29
-     * numerically-indexed array where each value is EE_Data_Migration_Script_Stage object
30
-     *
31
-     * @var EE_Data_Migration_Script_Stage[] $migration_functions
32
-     */
33
-    protected $_migration_stages = array();
34
-
35
-    /**
36
-     * Indicates we've already ran the schema changes that needed to happen BEFORE the data migration
37
-     *
38
-     * @var boolean
39
-     */
40
-    protected $_schema_changes_before_migration_ran = null;
41
-
42
-    /**
43
-     * Indicates we've already ran the schema changes that needed to happen AFTER the data migration
44
-     *
45
-     * @var boolean
46
-     */
47
-    protected $_schema_changes_after_migration_ran = null;
48
-
49
-    /**
50
-     * String which describes what's currently happening in this migration
51
-     *
52
-     * @var string
53
-     */
54
-    protected $_feedback_message;
55
-
56
-    /**
57
-     * Indicates the script's priority. Like wp's add_action and add_filter, lower numbers
58
-     * correspond to earlier execution
59
-     *
60
-     * @var int
61
-     */
62
-    protected $_priority = 5;
63
-
64
-    /**
65
-     * Multi-dimensional array that defines the mapping from OLD table Primary Keys
66
-     * to NEW table Primary Keys.
67
-     * Top-level array keys are OLD table names (minus the "wp_" part),
68
-     * 2nd-level array keys are NEW table names (again, minus the "wp_" part),
69
-     * 3rd-level array keys are the OLD table primary keys
70
-     * and 3rd-level array values are the NEW table primary keys
71
-     *
72
-     * @var array
73
-     */
74
-    protected $_mappings = array();
75
-
76
-    /**
77
-     * @var EE_Data_Migration_Script_Base
78
-     */
79
-    protected $previous_dms;
80
-
81
-
82
-    /**
83
-     * Returns whether or not this data migration script can operate on the given version of the database.
84
-     * Eg, if this migration script can migrate from 3.1.26 or higher (but not anything after 4.0.0), and
85
-     * it's passed a string like '3.1.38B', it should return true.
86
-     * If this DMS is to migrate data from an EE3 addon, you will probably want to use
87
-     * EventEspresso\core\services\database\TableAnalysis::tableExists() to check for old EE3 tables, and
88
-     * EE_Data_Migration_Manager::get_migration_ran() to check that core was already
89
-     * migrated from EE3 to EE4 (ie, this DMS probably relies on some migration data generated
90
-     * during the Core 4.1.0 DMS. If core didn't run that DMS, you probably don't want
91
-     * to run this DMS).
92
-     * If this DMS migrates data from a previous version of this EE4 addon, just
93
-     * comparing $current_database_state_of[ $this->slug() ] will probably suffice.
94
-     * If this DMS should never migrate data, because it's only used to define the initial
95
-     * database state, just return FALSE (and core's activation process will take care
96
-     * of calling its schema_changes_before_migration() and
97
-     * schema_changes_after_migration() for you. )
98
-     *
99
-     * @param array $current_database_state_of keys are EE plugin slugs (eg 'Core', 'Calendar', 'Mailchimp', etc)
100
-     * @return boolean
101
-     */
102
-    abstract public function can_migrate_from_version($current_database_state_of);
103
-
104
-
105
-    /**
106
-     * Performs database schema changes that need to occur BEFORE the data is migrated.
107
-     * Eg, if we were going to change user passwords from plaintext to encoded versions
108
-     * during this migration, this would probably add a new column called something like
109
-     * "encoded_password".
110
-     *
111
-     * @return boolean of success
112
-     */
113
-    abstract public function schema_changes_before_migration();
114
-
115
-
116
-    /**
117
-     * Performs the database schema changes that need to occur AFTER the data has been migrated.
118
-     * Usually this will mean we'll be removing old columns. Eg, if we were changing passwords
119
-     * from plaintext to encoded versions, and we had added a column called "encoded_password",
120
-     * this function would probably remove the old column "password" (which still holds the plaintext password)
121
-     * and possibly rename "encoded_password" to "password"
122
-     *
123
-     * @return boolean of success
124
-     */
125
-    abstract public function schema_changes_after_migration();
126
-
127
-
128
-    /**
129
-     * All children of this must call parent::__construct()
130
-     * at the end of their constructor or suffer the consequences!
131
-     *
132
-     * @param TableManager  $table_manager
133
-     * @param TableAnalysis $table_analysis
134
-     */
135
-    public function __construct(TableManager $table_manager = null, TableAnalysis $table_analysis = null)
136
-    {
137
-        $this->_migration_stages = (array) apply_filters(
138
-            'FHEE__' . get_class($this) . '__construct__migration_stages',
139
-            $this->_migration_stages
140
-        );
141
-        foreach ($this->_migration_stages as $migration_stage) {
142
-            if ($migration_stage instanceof EE_Data_Migration_Script_Stage) {
143
-                $migration_stage->_construct_finalize($this);
144
-            }
145
-        }
146
-        parent::__construct($table_manager, $table_analysis);
147
-    }
148
-
149
-
150
-    /**
151
-     * Place to add hooks and filters for tweaking the migrations page, in order
152
-     * to customize it
153
-     */
154
-    public function migration_page_hooks()
155
-    {
156
-        // by default none are added because we normally like the default look of the migration page
157
-    }
158
-
159
-
160
-    /**
161
-     * Sets the mapping from old table primary keys to new table primary keys.
162
-     * This mapping is automatically persisted as a property on the migration
163
-     *
164
-     * @param string     $old_table with wpdb prefix (wp_). Eg: wp_events_detail
165
-     * @param int|string $old_pk    old primary key. Eg events_detail.id's value
166
-     * @param string     $new_table with wpdb prefix (wp_). Eg: wp_posts
167
-     * @param int|string $new_pk    eg posts.ID
168
-     * @return void
169
-     */
170
-    public function set_mapping($old_table, $old_pk, $new_table, $new_pk)
171
-    {
172
-        // make sure it has the needed keys
173
-        if (! isset($this->_mappings[ $old_table ]) || ! isset($this->_mappings[ $old_table ][ $new_table ])) {
174
-            $this->_mappings[ $old_table ][ $new_table ] = $this->_get_mapping_option($old_table, $new_table);
175
-        }
176
-        $this->_mappings[ $old_table ][ $new_table ][ $old_pk ] = $new_pk;
177
-    }
178
-
179
-
180
-    /**
181
-     * Gets the new primary key, if provided with the OLD table and the primary key
182
-     * of an item in the old table, and the new table
183
-     *
184
-     * @param string     $old_table with wpdb prefix (wp_). Eg: wp_events_detail
185
-     * @param int|string $old_pk    old primary key. Eg events_detail.id's value
186
-     * @param string     $new_table with wpdb prefix (wp_). Eg: wp_posts
187
-     * @return mixed the primary key on the new table
188
-     */
189
-    public function get_mapping_new_pk($old_table, $old_pk, $new_table)
190
-    {
191
-        if (! isset($this->_mappings[ $old_table ]) ||
192
-            ! isset($this->_mappings[ $old_table ][ $new_table ])) {
193
-            // try fetching the option
194
-            $this->_mappings[ $old_table ][ $new_table ] = $this->_get_mapping_option($old_table, $new_table);
195
-        }
196
-        return isset($this->_mappings[ $old_table ][ $new_table ][ $old_pk ])
197
-            ? $this->_mappings[ $old_table ][ $new_table ][ $old_pk ] : null;
198
-    }
199
-
200
-
201
-    /**
202
-     * Gets the old primary key, if provided with the OLD table,
203
-     * and the new table and the primary key of an item in the new table
204
-     *
205
-     * @param string $old_table with wpdb prefix (wp_). Eg: wp_events_detail
206
-     * @param string $new_table with wpdb prefix (wp_). Eg: wp_posts
207
-     * @param mixed  $new_pk
208
-     * @return mixed
209
-     */
210
-    public function get_mapping_old_pk($old_table, $new_table, $new_pk)
211
-    {
212
-        if (! isset($this->_mappings[ $old_table ]) ||
213
-            ! isset($this->_mappings[ $old_table ][ $new_table ])) {
214
-            // try fetching the option
215
-            $this->_mappings[ $old_table ][ $new_table ] = $this->_get_mapping_option($old_table, $new_table);
216
-        }
217
-        if (isset($this->_mappings[ $old_table ][ $new_table ])) {
218
-            $new_pk_to_old_pk = array_flip($this->_mappings[ $old_table ][ $new_table ]);
219
-            if (isset($new_pk_to_old_pk[ $new_pk ])) {
220
-                return $new_pk_to_old_pk[ $new_pk ];
221
-            }
222
-        }
223
-        return null;
224
-    }
225
-
226
-
227
-    /**
228
-     * Gets the mapping array option specified by the table names
229
-     *
230
-     * @param string $old_table_name
231
-     * @param string $new_table_name
232
-     * @return array
233
-     */
234
-    protected function _get_mapping_option($old_table_name, $new_table_name)
235
-    {
236
-        $option = get_option($this->_get_mapping_option_name($old_table_name, $new_table_name), array());
237
-        return $option;
238
-    }
239
-
240
-
241
-    /**
242
-     * Updates the mapping option specified by the table names with the array provided
243
-     *
244
-     * @param string $old_table_name
245
-     * @param string $new_table_name
246
-     * @param array  $mapping_array
247
-     * @return boolean success of updating option
248
-     */
249
-    protected function _set_mapping_option($old_table_name, $new_table_name, $mapping_array)
250
-    {
251
-        $success = update_option($this->_get_mapping_option_name($old_table_name, $new_table_name), $mapping_array, false);
252
-        return $success;
253
-    }
254
-
255
-
256
-    /**
257
-     * Gets the option name for this script to map from $old_table_name to $new_table_name
258
-     *
259
-     * @param string $old_table_name
260
-     * @param string $new_table_name
261
-     * @return string
262
-     */
263
-    protected function _get_mapping_option_name($old_table_name, $new_table_name)
264
-    {
265
-        global $wpdb;
266
-        $old_table_name_sans_wp = str_replace($wpdb->prefix, "", $old_table_name);
267
-        $new_table_name_sans_wp = str_replace($wpdb->prefix, "", $new_table_name);
268
-        $migrates_to = EE_Data_Migration_Manager::instance()->script_migrates_to_version(get_class($this));
269
-        return substr(
270
-            EE_Data_Migration_Manager::data_migration_script_mapping_option_prefix . $migrates_to ['slug'] . '_' . $migrates_to['version'] . '_' . $old_table_name_sans_wp . '_' . $new_table_name_sans_wp,
271
-            0,
272
-            64
273
-        );
274
-    }
275
-
276
-
277
-    /**
278
-     * Counts all the records that will be migrated during this data migration.
279
-     * For example, if we were changing old user passwords from plaintext to encoded versions,
280
-     * this would be a count of all users who have passwords. If we were going to also split
281
-     * attendee records into transactions, registrations, and attendee records, this would include
282
-     * the count of all attendees currently in existence in the DB (ie, users + attendees).
283
-     * If you can't determine how many records there are to migrate, just provide a guess: this
284
-     * number will only be used in calculating the percent complete. If you estimate there to be
285
-     * 100 records to migrate, and it turns out there's 120, we'll just show the migration as being at
286
-     * 99% until the function "migration_step" returns EE_Data_Migration_Script_Base::status_complete.
287
-     *
288
-     * @return int
289
-     */
290
-    protected function _count_records_to_migrate()
291
-    {
292
-        $count = 0;
293
-        foreach ($this->stages() as $stage) {
294
-            $count += $stage->count_records_to_migrate();
295
-        }
296
-        return $count;
297
-    }
298
-
299
-
300
-    /**
301
-     * Returns the number of records updated so far. Usually this is easiest to do
302
-     * by just setting a transient and updating it after each migration_step
303
-     *
304
-     * @return int
305
-     */
306
-    public function count_records_migrated()
307
-    {
308
-        $count = 0;
309
-        foreach ($this->stages() as $stage) {
310
-            $count += $stage->count_records_migrated();
311
-        }
312
-        $this->_records_migrated = $count;
313
-        return $count;
314
-    }
315
-
316
-
317
-    /**
318
-     * @param int $num_records_to_migrate_limit
319
-     * @return int
320
-     * @throws EE_Error
321
-     * @throws Exception
322
-     */
323
-    public function migration_step($num_records_to_migrate_limit)
324
-    {
325
-        // reset the feedback message
326
-        $this->_feedback_message = '';
327
-        // if we haven't yet done the 1st schema changes, do them now. buffer any output
328
-        $this->_maybe_do_schema_changes(true);
329
-
330
-        $num_records_actually_migrated = 0;
331
-        $records_migrated_per_stage = array();
332
-        // setup the 'stage' variable, which should hold the last run stage of the migration  (or none at all if nothing runs)
333
-        $stage = null;
334
-        // get the next stage that isn't complete
335
-        foreach ($this->stages() as $stage) {
336
-            if ($stage->get_status() == EE_Data_Migration_Manager::status_continue) {
337
-                try {
338
-                    $records_migrated_during_stage = $stage->migration_step(
339
-                        $num_records_to_migrate_limit - $num_records_actually_migrated
340
-                    );
341
-                    $num_records_actually_migrated += $records_migrated_during_stage;
342
-                    $records_migrated_per_stage[ $stage->pretty_name() ] = $records_migrated_during_stage;
343
-                } catch (Exception $e) {
344
-                    // yes if we catch an exception here, we consider that migration stage borked.
345
-                    $stage->set_status(EE_Data_Migration_Manager::status_fatal_error);
346
-                    $this->set_status(EE_Data_Migration_Manager::status_fatal_error);
347
-                    $stage->add_error($e->getMessage() . ". Stack-trace:" . $e->getTraceAsString());
348
-                    throw $e;
349
-                }
350
-                // check that the migration stage didn't mark itself as having a fatal error
351
-                if ($stage->is_broken()) {
352
-                    $this->set_broken();
353
-                    throw new EE_Error($stage->get_last_error());
354
-                }
355
-            }
356
-            // once we've migrated all the number we intended to (possibly from different stages), stop migrating
357
-            // or if we had a fatal error
358
-            // or if the current script stopped early- its not done, but it's done all it thinks we should do on this step
359
-            if ($num_records_actually_migrated >= $num_records_to_migrate_limit
360
-                || $stage->is_broken()
361
-                || $stage->has_more_to_do()
362
-            ) {
363
-                break;
364
-            }
365
-        }
366
-        // check if we're all done this data migration...
367
-        // which is indicated by being done early AND the last stage claims to be done
368
-        if ($stage == null) {
369
-            // this migration script apparently has NO stages... which is super weird, but whatever
370
-            $this->set_completed();
371
-            $this->_maybe_do_schema_changes(false);
372
-        } elseif ($num_records_actually_migrated < $num_records_to_migrate_limit && ! $stage->has_more_to_do()) {
373
-            // apparently we're done, because we couldn't migrate the number we intended to
374
-            $this->set_completed();
375
-            $this->_update_feedback_message(array_reverse($records_migrated_per_stage));
376
-            // do schema changes for after the migration now
377
-            // first double-check we haven't already done this
378
-            $this->_maybe_do_schema_changes(false);
379
-        } else {
380
-            // update feedback message, keeping in mind that we show them with the most recent at the top
381
-            $this->_update_feedback_message(array_reverse($records_migrated_per_stage));
382
-        }
383
-        return $num_records_actually_migrated;
384
-    }
385
-
386
-
387
-    /**
388
-     * Updates the feedback message according to what was done during this migration stage.
389
-     *
390
-     * @param array $records_migrated_per_stage KEYS are pretty names for each stage; values are the count of records
391
-     *                                          migrated from that stage
392
-     * @return void
393
-     */
394
-    private function _update_feedback_message($records_migrated_per_stage)
395
-    {
396
-        $feedback_message_array = array();
397
-        foreach ($records_migrated_per_stage as $migration_stage_name => $num_records_migrated) {
398
-            $feedback_message_array[] = sprintf(
399
-                __("Migrated %d records successfully during %s", "event_espresso"),
400
-                $num_records_migrated,
401
-                $migration_stage_name
402
-            );
403
-        }
404
-        $this->_feedback_message .= implode("<br>", $feedback_message_array);
405
-    }
406
-
407
-
408
-    /**
409
-     * Calls either schema_changes_before_migration() (if $before==true) or schema_changes_after_migration
410
-     * (if $before==false). Buffers their outputs and stores them on the class.
411
-     *
412
-     * @param boolean $before
413
-     * @throws Exception
414
-     * @return void
415
-     */
416
-    private function _maybe_do_schema_changes($before = true)
417
-    {
418
-        // so this property will be either _schema_changes_after_migration_ran or _schema_changes_before_migration_ran
419
-        $property_name = '_schema_changes_' . ($before ? 'before' : 'after') . '_migration_ran';
420
-        if (! $this->{$property_name}) {
421
-            try {
422
-                ob_start();
423
-                if ($before) {
424
-                    $this->schema_changes_before_migration();
425
-                } else {
426
-                    $this->schema_changes_after_migration();
427
-                }
428
-                $output = ob_get_contents();
429
-                ob_end_clean();
430
-            } catch (Exception $e) {
431
-                $this->set_status(EE_Data_Migration_Manager::status_fatal_error);
432
-                throw $e;
433
-            }
434
-            // record that we've done these schema changes
435
-            $this->{$property_name} = true;
436
-            // if there were any warnings etc, record them as non-fatal errors
437
-            if ($output) {
438
-                // there were some warnings
439
-                $this->_errors[] = $output;
440
-            }
441
-        }
442
-    }
443
-
444
-
445
-    /**
446
-     * Wrapper for EEH_Activation::create_table. However, takes into account the request type when
447
-     * deciding what to pass for its 4th arg, $drop_pre_existing_tables. Using this function, instead
448
-     * of _table_should_exist_previously, indicates that this table should be new to the EE version being migrated to
449
-     * or
450
-     * activated currently. If this is a brand new activation or a migration, and we're indicating this table should
451
-     * not
452
-     * previously exist, then we want to set $drop_pre_existing_tables to TRUE (ie, we shouldn't discover that this
453
-     * table exists in the DB in EEH_Activation::create_table- if it DOES exist, something's wrong and the old table
454
-     * should be nuked.
455
-     *
456
-     * Just for a bit of context, the migration script's db_schema_changes_* methods
457
-     * are called basically in 3 cases: on brand new activation of EE4 (ie no previous version of EE existed and the
458
-     * plugin is being activated and we want to add all the brand new tables), upon reactivation of EE4 (it was
459
-     * deactivated and then reactivated, in which case we want to just verify the DB structure is ok) that table should
460
-     * be dropped), and during a migration when we're moving the DB to the state of the migration script
461
-     *
462
-     * @param string $table_name
463
-     * @param string $table_definition_sql
464
-     * @param string $engine_string
465
-     */
466
-    protected function _table_is_new_in_this_version(
467
-        $table_name,
468
-        $table_definition_sql,
469
-        $engine_string = 'ENGINE=InnoDB '
470
-    ) {
471
-        $this->_create_table_and_catch_errors(
472
-            $table_name,
473
-            $table_definition_sql,
474
-            $engine_string,
475
-            $this->_pre_existing_table_should_be_dropped(true)
476
-        );
477
-    }
478
-
479
-    /**
480
-     * Like _table_is_new_in_this_version and _table_should_exist_previously, this function verifies the given table
481
-     * exists. But we understand that this table has CHANGED in this version since the previous version. So it's not
482
-     * completely new, but it's different. So we need to treat it like a new table in terms of verifying it's schema is
483
-     * correct on activations, migrations, upgrades; but if it exists when it shouldn't, we need to be as lenient as
484
-     * _table_should_exist_previously.
485
-     * 8656]{Assumes only this plugin could have added this table (ie, if its a new activation of this plugin, the
486
-     * table shouldn't exist).
487
-     *
488
-     * @param string $table_name
489
-     * @param string $table_definition_sql
490
-     * @param string $engine_string
491
-     */
492
-    protected function _table_is_changed_in_this_version(
493
-        $table_name,
494
-        $table_definition_sql,
495
-        $engine_string = 'ENGINE=MyISAM'
496
-    ) {
497
-        $this->_create_table_and_catch_errors(
498
-            $table_name,
499
-            $table_definition_sql,
500
-            $engine_string,
501
-            $this->_pre_existing_table_should_be_dropped(false)
502
-        );
503
-    }
504
-
505
-
506
-    /**
507
-     * _old_table_exists
508
-     * returns TRUE if the requested table exists in the current database
509
-     *
510
-     * @param string $table_name
511
-     * @return boolean
512
-     */
513
-    protected function _old_table_exists($table_name)
514
-    {
515
-        return $this->_get_table_analysis()->tableExists($table_name);
516
-    }
517
-
518
-
519
-    /**
520
-     * _delete_table_if_empty
521
-     * returns TRUE if the requested table was empty and successfully empty
522
-     *
523
-     * @param string $table_name
524
-     * @return boolean
525
-     */
526
-    protected function _delete_table_if_empty($table_name)
527
-    {
528
-        return EEH_Activation::delete_db_table_if_empty($table_name);
529
-    }
530
-
531
-
532
-    /**
533
-     * It is preferred to use _table_has_not_changed_since_previous or _table_is_changed_in_this_version
534
-     * as these are significantly more efficient or explicit.
535
-     * Please see description of _table_is_new_in_this_version. This function will only set
536
-     * EEH_Activation::create_table's $drop_pre_existing_tables to TRUE if it's a brand
537
-     * new activation. ie, a more accurate name for this method would be "_table_added_previously_by_this_plugin"
538
-     * because the table will be cleared out if this is a new activation (ie, if its a new activation, it actually
539
-     * should exist previously). Otherwise, we'll always set $drop_pre_existing_tables to FALSE because the table
540
-     * should have existed. Note, if the table is being MODIFIED in this version being activated or migrated to, then
541
-     * you want _table_is_changed_in_this_version NOT this one. We don't check this table's structure during migrations
542
-     * because apparently it hasn't changed since the previous one, right?
543
-     *
544
-     * @param string $table_name
545
-     * @param string $table_definition_sql
546
-     * @param string $engine_string
547
-     */
548
-    protected function _table_should_exist_previously(
549
-        $table_name,
550
-        $table_definition_sql,
551
-        $engine_string = 'ENGINE=MyISAM'
552
-    ) {
553
-        $this->_create_table_and_catch_errors(
554
-            $table_name,
555
-            $table_definition_sql,
556
-            $engine_string,
557
-            $this->_pre_existing_table_should_be_dropped(false)
558
-        );
559
-    }
560
-
561
-    /**
562
-     * Exactly the same as _table_should_exist_previously(), except if this migration script is currently doing
563
-     * a migration, we skip checking this table's structure in the database and just assume it's correct.
564
-     * So this is useful only to improve efficiency when doing migrations (not a big deal for single site installs,
565
-     * but important for multisite where migrations can take a very long time otherwise).
566
-     * If the table is known to have changed since previous version, use _table_is_changed_in_this_version().
567
-     * Assumes only this plugin could have added this table (ie, if its a new activation of this plugin, the table
568
-     * shouldn't exist).
569
-     *
570
-     * @param string $table_name
571
-     * @param string $table_definition_sql
572
-     * @param string $engine_string
573
-     */
574
-    protected function _table_has_not_changed_since_previous(
575
-        $table_name,
576
-        $table_definition_sql,
577
-        $engine_string = 'ENGINE=MyISAM'
578
-    ) {
579
-        if ($this->_currently_migrating()) {
580
-            // if we're doing a migration, and this table apparently already exists, then we don't need do anything right?
581
-            return;
582
-        }
583
-        $this->_create_table_and_catch_errors(
584
-            $table_name,
585
-            $table_definition_sql,
586
-            $engine_string,
587
-            $this->_pre_existing_table_should_be_dropped(false)
588
-        );
589
-    }
590
-
591
-    /**
592
-     * Returns whether or not this migration script is being used as part of an actual migration
593
-     *
594
-     * @return boolean
595
-     */
596
-    protected function _currently_migrating()
597
-    {
598
-        // we want to know if we are currently performing a migration. We could just believe what was set on the _migrating property, but let's double-check (ie the script should apply and we should be in MM)
599
-        return $this->_migrating &&
600
-               $this->can_migrate_from_version(
601
-                   EE_Data_Migration_Manager::instance()->ensure_current_database_state_is_set()
602
-               ) &&
603
-               EE_Maintenance_Mode::instance()->real_level() == EE_Maintenance_Mode::level_2_complete_maintenance;
604
-    }
605
-
606
-    /**
607
-     * Determines if a table should be dropped, based on whether it's reported to be new in $table_is_new,
608
-     * and the plugin's request type.
609
-     * Assumes only this plugin could have added the table (ie, if its a new activation of this plugin, the table
610
-     * shouldn't exist no matter what).
611
-     *
612
-     * @param boolean $table_is_new
613
-     * @return boolean
614
-     */
615
-    protected function _pre_existing_table_should_be_dropped($table_is_new)
616
-    {
617
-        if ($table_is_new) {
618
-            if ($this->_get_req_type_for_plugin_corresponding_to_this_dms() == EE_System::req_type_new_activation
619
-                || $this->_currently_migrating()
620
-            ) {
621
-                return true;
622
-            } else {
623
-                return false;
624
-            }
625
-        } else {
626
-            if (in_array(
627
-                $this->_get_req_type_for_plugin_corresponding_to_this_dms(),
628
-                array(EE_System::req_type_new_activation)
629
-            )) {
630
-                return true;
631
-            } else {
632
-                return false;
633
-            }
634
-        }
635
-    }
636
-
637
-    /**
638
-     * Just wraps EEH_Activation::create_table, but catches any errors it may throw and adds them as errors on the DMS
639
-     *
640
-     * @param string  $table_name
641
-     * @param string  $table_definition_sql
642
-     * @param string  $engine_string
643
-     * @param boolean $drop_pre_existing_tables
644
-     */
645
-    private function _create_table_and_catch_errors(
646
-        $table_name,
647
-        $table_definition_sql,
648
-        $engine_string = 'ENGINE=MyISAM',
649
-        $drop_pre_existing_tables = false
650
-    ) {
651
-        try {
652
-            EEH_Activation::create_table($table_name, $table_definition_sql, $engine_string, $drop_pre_existing_tables);
653
-        } catch (EE_Error $e) {
654
-            $message = $e->getMessage() . '<br>Stack Trace:' . $e->getTraceAsString();
655
-            $this->add_error($message);
656
-            $this->_feedback_message .= $message;
657
-        }
658
-    }
659
-
660
-
661
-    /**
662
-     * Gets the request type for the plugin (core or addon) that corresponds to this DMS
663
-     *
664
-     * @return int one of EE_System::_req_type_* constants
665
-     * @throws EE_Error
666
-     */
667
-    private function _get_req_type_for_plugin_corresponding_to_this_dms()
668
-    {
669
-        if ($this->slug() == 'Core') {
670
-            return EE_System::instance()->detect_req_type();
671
-        } else {// it must be for an addon
672
-            $addon_name = $this->slug();
673
-            if (EE_Registry::instance()->get_addon_by_name($addon_name)) {
674
-                return EE_Registry::instance()->get_addon_by_name($addon_name)->detect_req_type();
675
-            } else {
676
-                throw new EE_Error(
677
-                    sprintf(
678
-                        __(
679
-                            "The DMS slug '%s' should correspond to the addon's name, which should also be '%s', but no such addon was registered. These are the registered addons' names: %s",
680
-                            "event_espresso"
681
-                        ),
682
-                        $this->slug(),
683
-                        $addon_name,
684
-                        implode(",", array_keys(EE_Registry::instance()->get_addons_by_name()))
685
-                    )
686
-                );
687
-            }
688
-        }
689
-    }
690
-
691
-
692
-    /**
693
-     * returns an array of strings describing errors by all the script's stages
694
-     *
695
-     * @return array
696
-     */
697
-    public function get_errors()
698
-    {
699
-        $all_errors = $this->_errors;
700
-        if (! is_array($all_errors)) {
701
-            $all_errors = array();
702
-        }
703
-        foreach ($this->stages() as $stage) {
704
-            $all_errors = array_merge($stage->get_errors(), $all_errors);
705
-        }
706
-        return $all_errors;
707
-    }
708
-
709
-
710
-    /**
711
-     * Indicates whether or not this migration script should continue
712
-     *
713
-     * @return boolean
714
-     */
715
-    public function can_continue()
716
-    {
717
-        return in_array(
718
-            $this->get_status(),
719
-            EE_Data_Migration_Manager::instance()->stati_that_indicate_to_continue_single_migration_script
720
-        );
721
-    }
722
-
723
-
724
-    /**
725
-     * Gets all the data migration stages associated with this script. Note:
726
-     * addons can filter this list to add their own stages, and because the list is
727
-     * numerically-indexed, they can insert their stage wherever they like and it will
728
-     * get ordered by the indexes
729
-     *
730
-     * @return EE_Data_Migration_Script_Stage[]
731
-     */
732
-    protected function stages()
733
-    {
734
-        $stages = apply_filters('FHEE__' . get_class($this) . '__stages', $this->_migration_stages);
735
-        ksort($stages);
736
-        return $stages;
737
-    }
738
-
739
-
740
-    /**
741
-     * Gets a string which should describe what's going on currently with this migration, which
742
-     * can be displayed to the user
743
-     *
744
-     * @return string
745
-     */
746
-    public function get_feedback_message()
747
-    {
748
-        return $this->_feedback_message;
749
-    }
750
-
751
-
752
-    /**
753
-     * A lot like "__sleep()" magic method in purpose, this is meant for persisting this class'
754
-     * properties to the DB. However, we don't want to use __sleep() because its quite
755
-     * possible that this class is defined when it goes to sleep, but NOT available when it
756
-     * awakes (eg, this class is part of an addon that is deactivated at some point).
757
-     */
758
-    public function properties_as_array()
759
-    {
760
-        $properties = parent::properties_as_array();
761
-        $properties['_migration_stages'] = array();
762
-        foreach ($this->_migration_stages as $migration_stage_priority => $migration_stage_class) {
763
-            $properties['_migration_stages'][ $migration_stage_priority ] = $migration_stage_class->properties_as_array(
764
-            );
765
-        }
766
-        unset($properties['_mappings']);
767
-        unset($properties['previous_dms']);
768
-
769
-        foreach ($this->_mappings as $old_table_name => $mapping_to_new_table) {
770
-            foreach ($mapping_to_new_table as $new_table_name => $mapping) {
771
-                $this->_set_mapping_option($old_table_name, $new_table_name, $mapping);
772
-            }
773
-        }
774
-        return $properties;
775
-    }
776
-
777
-
778
-    /**
779
-     * Sets all of the properties of this script stage to match what's in the array, which is assumed
780
-     * to have been made from the properties_as_array() function.
781
-     *
782
-     * @param array $array_of_properties like what's produced from properties_as_array() method
783
-     * @return void
784
-     */
785
-    public function instantiate_from_array_of_properties($array_of_properties)
786
-    {
787
-        $stages_properties_arrays = $array_of_properties['_migration_stages'];
788
-        unset($array_of_properties['_migration_stages']);
789
-        unset($array_of_properties['class']);
790
-        foreach ($array_of_properties as $property_name => $property_value) {
791
-            $this->{$property_name} = $property_value;
792
-        }
793
-        // _migration_stages are already instantiated, but have only default data
794
-        foreach ($this->_migration_stages as $stage) {
795
-            $stage_data = $this->_find_migration_stage_data_with_classname(
796
-                get_class($stage),
797
-                $stages_properties_arrays
798
-            );
799
-            // SO, if we found the stage data that was saved, use it. Otherwise, I guess the stage is new? (maybe added by
800
-            // an addon? Unlikely... not sure why it wouldn't exist, but if it doesn't just treat it like it was never started yet)
801
-            if ($stage_data) {
802
-                $stage->instantiate_from_array_of_properties($stage_data);
803
-            }
804
-        }
805
-    }
806
-
807
-
808
-    /**
809
-     * Gets the migration data from the array $migration_stage_data_arrays (which is an array of arrays, each of which
810
-     * is pretty well identical to EE_Data_Migration_Stage objects except all their properties are array indexes)
811
-     * for the given classname
812
-     *
813
-     * @param string $classname
814
-     * @param array  $migration_stage_data_arrays
815
-     * @return null
816
-     */
817
-    private function _find_migration_stage_data_with_classname($classname, $migration_stage_data_arrays)
818
-    {
819
-        foreach ($migration_stage_data_arrays as $migration_stage_data_array) {
820
-            if (isset($migration_stage_data_array['class']) && $migration_stage_data_array['class'] == $classname) {
821
-                return $migration_stage_data_array;
822
-            }
823
-        }
824
-        return null;
825
-    }
826
-
827
-
828
-    /**
829
-     * Returns the version that this script migrates to, based on the script's name.
830
-     * Cannot be overwritten because lots of code needs to know which version a script
831
-     * migrates to knowing only its name.
832
-     *
833
-     * @return array where the first key is the plugin's slug, the 2nd is the version of that plugin
834
-     * that will be updated to. Eg array('Core','4.1.0')
835
-     */
836
-    final public function migrates_to_version()
837
-    {
838
-        return EE_Data_Migration_Manager::instance()->script_migrates_to_version(get_class($this));
839
-    }
840
-
841
-
842
-    /**
843
-     * Gets this addon's slug as it would appear in the current_db_state wp option,
844
-     * and if this migration script is for an addon, it SHOULD match the addon's slug
845
-     * (and also the addon's classname, minus the 'EE_' prefix.). Eg, 'Calendar' for the EE_Calendar addon.
846
-     * Or 'Core' for core (non-addon).
847
-     *
848
-     * @return string
849
-     */
850
-    public function slug()
851
-    {
852
-        $migrates_to_version_info = $this->migrates_to_version();
853
-        // the slug is the first part of the array
854
-        return $migrates_to_version_info['slug'];
855
-    }
856
-
857
-
858
-    /**
859
-     * Returns the script's priority relative to DMSs from other addons. However, when
860
-     * two DMSs from the same addon/core apply, this is ignored (and instead the version that
861
-     * the script migrates to is used to determine which to run first). The default is 5, but all core DMSs
862
-     * normally have priority 10. (So if you want a DMS "A" to run before DMS "B", both of which are from addons,
863
-     * and both of which CAN run at the same time (ie, "B" doesn't depend on "A" to set
864
-     * the database up so it can run), then you can set "A" to priority 3 or something.
865
-     *
866
-     * @return int
867
-     */
868
-    public function priority()
869
-    {
870
-        return $this->_priority;
871
-    }
872
-
873
-
874
-    /**
875
-     * Sets whether or not this DMS is being ran as part of a migration, instead of
876
-     * just being used to setup (or verify) the current database structure matches
877
-     * what the latest DMS indicates it should be
878
-     *
879
-     * @param boolean $migrating
880
-     * @return void
881
-     */
882
-    public function set_migrating($migrating = true)
883
-    {
884
-        $this->_migrating = $migrating;
885
-    }
886
-
887
-    /**
888
-     * Marks that we think this migration class can continue to migrate
889
-     */
890
-    public function reattempt()
891
-    {
892
-        parent::reattempt();
893
-        // also, we want to reattempt any stages that were marked as borked
894
-        foreach ($this->stages() as $stage) {
895
-            if ($stage->is_broken()) {
896
-                $stage->reattempt();
897
-            }
898
-        }
899
-    }
18
+	/**
19
+	 * Set by client code to indicate this DMS is being ran as part of a proper migration,
20
+	 * instead of being used to merely setup (or verify) the database structure.
21
+	 * Defaults to TRUE, so client code that's NOT using this DMS as part of a proper migration
22
+	 * should call EE_Data_Migration_Script_Base::set_migrating( FALSE )
23
+	 *
24
+	 * @var boolean
25
+	 */
26
+	protected $_migrating = true;
27
+
28
+	/**
29
+	 * numerically-indexed array where each value is EE_Data_Migration_Script_Stage object
30
+	 *
31
+	 * @var EE_Data_Migration_Script_Stage[] $migration_functions
32
+	 */
33
+	protected $_migration_stages = array();
34
+
35
+	/**
36
+	 * Indicates we've already ran the schema changes that needed to happen BEFORE the data migration
37
+	 *
38
+	 * @var boolean
39
+	 */
40
+	protected $_schema_changes_before_migration_ran = null;
41
+
42
+	/**
43
+	 * Indicates we've already ran the schema changes that needed to happen AFTER the data migration
44
+	 *
45
+	 * @var boolean
46
+	 */
47
+	protected $_schema_changes_after_migration_ran = null;
48
+
49
+	/**
50
+	 * String which describes what's currently happening in this migration
51
+	 *
52
+	 * @var string
53
+	 */
54
+	protected $_feedback_message;
55
+
56
+	/**
57
+	 * Indicates the script's priority. Like wp's add_action and add_filter, lower numbers
58
+	 * correspond to earlier execution
59
+	 *
60
+	 * @var int
61
+	 */
62
+	protected $_priority = 5;
63
+
64
+	/**
65
+	 * Multi-dimensional array that defines the mapping from OLD table Primary Keys
66
+	 * to NEW table Primary Keys.
67
+	 * Top-level array keys are OLD table names (minus the "wp_" part),
68
+	 * 2nd-level array keys are NEW table names (again, minus the "wp_" part),
69
+	 * 3rd-level array keys are the OLD table primary keys
70
+	 * and 3rd-level array values are the NEW table primary keys
71
+	 *
72
+	 * @var array
73
+	 */
74
+	protected $_mappings = array();
75
+
76
+	/**
77
+	 * @var EE_Data_Migration_Script_Base
78
+	 */
79
+	protected $previous_dms;
80
+
81
+
82
+	/**
83
+	 * Returns whether or not this data migration script can operate on the given version of the database.
84
+	 * Eg, if this migration script can migrate from 3.1.26 or higher (but not anything after 4.0.0), and
85
+	 * it's passed a string like '3.1.38B', it should return true.
86
+	 * If this DMS is to migrate data from an EE3 addon, you will probably want to use
87
+	 * EventEspresso\core\services\database\TableAnalysis::tableExists() to check for old EE3 tables, and
88
+	 * EE_Data_Migration_Manager::get_migration_ran() to check that core was already
89
+	 * migrated from EE3 to EE4 (ie, this DMS probably relies on some migration data generated
90
+	 * during the Core 4.1.0 DMS. If core didn't run that DMS, you probably don't want
91
+	 * to run this DMS).
92
+	 * If this DMS migrates data from a previous version of this EE4 addon, just
93
+	 * comparing $current_database_state_of[ $this->slug() ] will probably suffice.
94
+	 * If this DMS should never migrate data, because it's only used to define the initial
95
+	 * database state, just return FALSE (and core's activation process will take care
96
+	 * of calling its schema_changes_before_migration() and
97
+	 * schema_changes_after_migration() for you. )
98
+	 *
99
+	 * @param array $current_database_state_of keys are EE plugin slugs (eg 'Core', 'Calendar', 'Mailchimp', etc)
100
+	 * @return boolean
101
+	 */
102
+	abstract public function can_migrate_from_version($current_database_state_of);
103
+
104
+
105
+	/**
106
+	 * Performs database schema changes that need to occur BEFORE the data is migrated.
107
+	 * Eg, if we were going to change user passwords from plaintext to encoded versions
108
+	 * during this migration, this would probably add a new column called something like
109
+	 * "encoded_password".
110
+	 *
111
+	 * @return boolean of success
112
+	 */
113
+	abstract public function schema_changes_before_migration();
114
+
115
+
116
+	/**
117
+	 * Performs the database schema changes that need to occur AFTER the data has been migrated.
118
+	 * Usually this will mean we'll be removing old columns. Eg, if we were changing passwords
119
+	 * from plaintext to encoded versions, and we had added a column called "encoded_password",
120
+	 * this function would probably remove the old column "password" (which still holds the plaintext password)
121
+	 * and possibly rename "encoded_password" to "password"
122
+	 *
123
+	 * @return boolean of success
124
+	 */
125
+	abstract public function schema_changes_after_migration();
126
+
127
+
128
+	/**
129
+	 * All children of this must call parent::__construct()
130
+	 * at the end of their constructor or suffer the consequences!
131
+	 *
132
+	 * @param TableManager  $table_manager
133
+	 * @param TableAnalysis $table_analysis
134
+	 */
135
+	public function __construct(TableManager $table_manager = null, TableAnalysis $table_analysis = null)
136
+	{
137
+		$this->_migration_stages = (array) apply_filters(
138
+			'FHEE__' . get_class($this) . '__construct__migration_stages',
139
+			$this->_migration_stages
140
+		);
141
+		foreach ($this->_migration_stages as $migration_stage) {
142
+			if ($migration_stage instanceof EE_Data_Migration_Script_Stage) {
143
+				$migration_stage->_construct_finalize($this);
144
+			}
145
+		}
146
+		parent::__construct($table_manager, $table_analysis);
147
+	}
148
+
149
+
150
+	/**
151
+	 * Place to add hooks and filters for tweaking the migrations page, in order
152
+	 * to customize it
153
+	 */
154
+	public function migration_page_hooks()
155
+	{
156
+		// by default none are added because we normally like the default look of the migration page
157
+	}
158
+
159
+
160
+	/**
161
+	 * Sets the mapping from old table primary keys to new table primary keys.
162
+	 * This mapping is automatically persisted as a property on the migration
163
+	 *
164
+	 * @param string     $old_table with wpdb prefix (wp_). Eg: wp_events_detail
165
+	 * @param int|string $old_pk    old primary key. Eg events_detail.id's value
166
+	 * @param string     $new_table with wpdb prefix (wp_). Eg: wp_posts
167
+	 * @param int|string $new_pk    eg posts.ID
168
+	 * @return void
169
+	 */
170
+	public function set_mapping($old_table, $old_pk, $new_table, $new_pk)
171
+	{
172
+		// make sure it has the needed keys
173
+		if (! isset($this->_mappings[ $old_table ]) || ! isset($this->_mappings[ $old_table ][ $new_table ])) {
174
+			$this->_mappings[ $old_table ][ $new_table ] = $this->_get_mapping_option($old_table, $new_table);
175
+		}
176
+		$this->_mappings[ $old_table ][ $new_table ][ $old_pk ] = $new_pk;
177
+	}
178
+
179
+
180
+	/**
181
+	 * Gets the new primary key, if provided with the OLD table and the primary key
182
+	 * of an item in the old table, and the new table
183
+	 *
184
+	 * @param string     $old_table with wpdb prefix (wp_). Eg: wp_events_detail
185
+	 * @param int|string $old_pk    old primary key. Eg events_detail.id's value
186
+	 * @param string     $new_table with wpdb prefix (wp_). Eg: wp_posts
187
+	 * @return mixed the primary key on the new table
188
+	 */
189
+	public function get_mapping_new_pk($old_table, $old_pk, $new_table)
190
+	{
191
+		if (! isset($this->_mappings[ $old_table ]) ||
192
+			! isset($this->_mappings[ $old_table ][ $new_table ])) {
193
+			// try fetching the option
194
+			$this->_mappings[ $old_table ][ $new_table ] = $this->_get_mapping_option($old_table, $new_table);
195
+		}
196
+		return isset($this->_mappings[ $old_table ][ $new_table ][ $old_pk ])
197
+			? $this->_mappings[ $old_table ][ $new_table ][ $old_pk ] : null;
198
+	}
199
+
200
+
201
+	/**
202
+	 * Gets the old primary key, if provided with the OLD table,
203
+	 * and the new table and the primary key of an item in the new table
204
+	 *
205
+	 * @param string $old_table with wpdb prefix (wp_). Eg: wp_events_detail
206
+	 * @param string $new_table with wpdb prefix (wp_). Eg: wp_posts
207
+	 * @param mixed  $new_pk
208
+	 * @return mixed
209
+	 */
210
+	public function get_mapping_old_pk($old_table, $new_table, $new_pk)
211
+	{
212
+		if (! isset($this->_mappings[ $old_table ]) ||
213
+			! isset($this->_mappings[ $old_table ][ $new_table ])) {
214
+			// try fetching the option
215
+			$this->_mappings[ $old_table ][ $new_table ] = $this->_get_mapping_option($old_table, $new_table);
216
+		}
217
+		if (isset($this->_mappings[ $old_table ][ $new_table ])) {
218
+			$new_pk_to_old_pk = array_flip($this->_mappings[ $old_table ][ $new_table ]);
219
+			if (isset($new_pk_to_old_pk[ $new_pk ])) {
220
+				return $new_pk_to_old_pk[ $new_pk ];
221
+			}
222
+		}
223
+		return null;
224
+	}
225
+
226
+
227
+	/**
228
+	 * Gets the mapping array option specified by the table names
229
+	 *
230
+	 * @param string $old_table_name
231
+	 * @param string $new_table_name
232
+	 * @return array
233
+	 */
234
+	protected function _get_mapping_option($old_table_name, $new_table_name)
235
+	{
236
+		$option = get_option($this->_get_mapping_option_name($old_table_name, $new_table_name), array());
237
+		return $option;
238
+	}
239
+
240
+
241
+	/**
242
+	 * Updates the mapping option specified by the table names with the array provided
243
+	 *
244
+	 * @param string $old_table_name
245
+	 * @param string $new_table_name
246
+	 * @param array  $mapping_array
247
+	 * @return boolean success of updating option
248
+	 */
249
+	protected function _set_mapping_option($old_table_name, $new_table_name, $mapping_array)
250
+	{
251
+		$success = update_option($this->_get_mapping_option_name($old_table_name, $new_table_name), $mapping_array, false);
252
+		return $success;
253
+	}
254
+
255
+
256
+	/**
257
+	 * Gets the option name for this script to map from $old_table_name to $new_table_name
258
+	 *
259
+	 * @param string $old_table_name
260
+	 * @param string $new_table_name
261
+	 * @return string
262
+	 */
263
+	protected function _get_mapping_option_name($old_table_name, $new_table_name)
264
+	{
265
+		global $wpdb;
266
+		$old_table_name_sans_wp = str_replace($wpdb->prefix, "", $old_table_name);
267
+		$new_table_name_sans_wp = str_replace($wpdb->prefix, "", $new_table_name);
268
+		$migrates_to = EE_Data_Migration_Manager::instance()->script_migrates_to_version(get_class($this));
269
+		return substr(
270
+			EE_Data_Migration_Manager::data_migration_script_mapping_option_prefix . $migrates_to ['slug'] . '_' . $migrates_to['version'] . '_' . $old_table_name_sans_wp . '_' . $new_table_name_sans_wp,
271
+			0,
272
+			64
273
+		);
274
+	}
275
+
276
+
277
+	/**
278
+	 * Counts all the records that will be migrated during this data migration.
279
+	 * For example, if we were changing old user passwords from plaintext to encoded versions,
280
+	 * this would be a count of all users who have passwords. If we were going to also split
281
+	 * attendee records into transactions, registrations, and attendee records, this would include
282
+	 * the count of all attendees currently in existence in the DB (ie, users + attendees).
283
+	 * If you can't determine how many records there are to migrate, just provide a guess: this
284
+	 * number will only be used in calculating the percent complete. If you estimate there to be
285
+	 * 100 records to migrate, and it turns out there's 120, we'll just show the migration as being at
286
+	 * 99% until the function "migration_step" returns EE_Data_Migration_Script_Base::status_complete.
287
+	 *
288
+	 * @return int
289
+	 */
290
+	protected function _count_records_to_migrate()
291
+	{
292
+		$count = 0;
293
+		foreach ($this->stages() as $stage) {
294
+			$count += $stage->count_records_to_migrate();
295
+		}
296
+		return $count;
297
+	}
298
+
299
+
300
+	/**
301
+	 * Returns the number of records updated so far. Usually this is easiest to do
302
+	 * by just setting a transient and updating it after each migration_step
303
+	 *
304
+	 * @return int
305
+	 */
306
+	public function count_records_migrated()
307
+	{
308
+		$count = 0;
309
+		foreach ($this->stages() as $stage) {
310
+			$count += $stage->count_records_migrated();
311
+		}
312
+		$this->_records_migrated = $count;
313
+		return $count;
314
+	}
315
+
316
+
317
+	/**
318
+	 * @param int $num_records_to_migrate_limit
319
+	 * @return int
320
+	 * @throws EE_Error
321
+	 * @throws Exception
322
+	 */
323
+	public function migration_step($num_records_to_migrate_limit)
324
+	{
325
+		// reset the feedback message
326
+		$this->_feedback_message = '';
327
+		// if we haven't yet done the 1st schema changes, do them now. buffer any output
328
+		$this->_maybe_do_schema_changes(true);
329
+
330
+		$num_records_actually_migrated = 0;
331
+		$records_migrated_per_stage = array();
332
+		// setup the 'stage' variable, which should hold the last run stage of the migration  (or none at all if nothing runs)
333
+		$stage = null;
334
+		// get the next stage that isn't complete
335
+		foreach ($this->stages() as $stage) {
336
+			if ($stage->get_status() == EE_Data_Migration_Manager::status_continue) {
337
+				try {
338
+					$records_migrated_during_stage = $stage->migration_step(
339
+						$num_records_to_migrate_limit - $num_records_actually_migrated
340
+					);
341
+					$num_records_actually_migrated += $records_migrated_during_stage;
342
+					$records_migrated_per_stage[ $stage->pretty_name() ] = $records_migrated_during_stage;
343
+				} catch (Exception $e) {
344
+					// yes if we catch an exception here, we consider that migration stage borked.
345
+					$stage->set_status(EE_Data_Migration_Manager::status_fatal_error);
346
+					$this->set_status(EE_Data_Migration_Manager::status_fatal_error);
347
+					$stage->add_error($e->getMessage() . ". Stack-trace:" . $e->getTraceAsString());
348
+					throw $e;
349
+				}
350
+				// check that the migration stage didn't mark itself as having a fatal error
351
+				if ($stage->is_broken()) {
352
+					$this->set_broken();
353
+					throw new EE_Error($stage->get_last_error());
354
+				}
355
+			}
356
+			// once we've migrated all the number we intended to (possibly from different stages), stop migrating
357
+			// or if we had a fatal error
358
+			// or if the current script stopped early- its not done, but it's done all it thinks we should do on this step
359
+			if ($num_records_actually_migrated >= $num_records_to_migrate_limit
360
+				|| $stage->is_broken()
361
+				|| $stage->has_more_to_do()
362
+			) {
363
+				break;
364
+			}
365
+		}
366
+		// check if we're all done this data migration...
367
+		// which is indicated by being done early AND the last stage claims to be done
368
+		if ($stage == null) {
369
+			// this migration script apparently has NO stages... which is super weird, but whatever
370
+			$this->set_completed();
371
+			$this->_maybe_do_schema_changes(false);
372
+		} elseif ($num_records_actually_migrated < $num_records_to_migrate_limit && ! $stage->has_more_to_do()) {
373
+			// apparently we're done, because we couldn't migrate the number we intended to
374
+			$this->set_completed();
375
+			$this->_update_feedback_message(array_reverse($records_migrated_per_stage));
376
+			// do schema changes for after the migration now
377
+			// first double-check we haven't already done this
378
+			$this->_maybe_do_schema_changes(false);
379
+		} else {
380
+			// update feedback message, keeping in mind that we show them with the most recent at the top
381
+			$this->_update_feedback_message(array_reverse($records_migrated_per_stage));
382
+		}
383
+		return $num_records_actually_migrated;
384
+	}
385
+
386
+
387
+	/**
388
+	 * Updates the feedback message according to what was done during this migration stage.
389
+	 *
390
+	 * @param array $records_migrated_per_stage KEYS are pretty names for each stage; values are the count of records
391
+	 *                                          migrated from that stage
392
+	 * @return void
393
+	 */
394
+	private function _update_feedback_message($records_migrated_per_stage)
395
+	{
396
+		$feedback_message_array = array();
397
+		foreach ($records_migrated_per_stage as $migration_stage_name => $num_records_migrated) {
398
+			$feedback_message_array[] = sprintf(
399
+				__("Migrated %d records successfully during %s", "event_espresso"),
400
+				$num_records_migrated,
401
+				$migration_stage_name
402
+			);
403
+		}
404
+		$this->_feedback_message .= implode("<br>", $feedback_message_array);
405
+	}
406
+
407
+
408
+	/**
409
+	 * Calls either schema_changes_before_migration() (if $before==true) or schema_changes_after_migration
410
+	 * (if $before==false). Buffers their outputs and stores them on the class.
411
+	 *
412
+	 * @param boolean $before
413
+	 * @throws Exception
414
+	 * @return void
415
+	 */
416
+	private function _maybe_do_schema_changes($before = true)
417
+	{
418
+		// so this property will be either _schema_changes_after_migration_ran or _schema_changes_before_migration_ran
419
+		$property_name = '_schema_changes_' . ($before ? 'before' : 'after') . '_migration_ran';
420
+		if (! $this->{$property_name}) {
421
+			try {
422
+				ob_start();
423
+				if ($before) {
424
+					$this->schema_changes_before_migration();
425
+				} else {
426
+					$this->schema_changes_after_migration();
427
+				}
428
+				$output = ob_get_contents();
429
+				ob_end_clean();
430
+			} catch (Exception $e) {
431
+				$this->set_status(EE_Data_Migration_Manager::status_fatal_error);
432
+				throw $e;
433
+			}
434
+			// record that we've done these schema changes
435
+			$this->{$property_name} = true;
436
+			// if there were any warnings etc, record them as non-fatal errors
437
+			if ($output) {
438
+				// there were some warnings
439
+				$this->_errors[] = $output;
440
+			}
441
+		}
442
+	}
443
+
444
+
445
+	/**
446
+	 * Wrapper for EEH_Activation::create_table. However, takes into account the request type when
447
+	 * deciding what to pass for its 4th arg, $drop_pre_existing_tables. Using this function, instead
448
+	 * of _table_should_exist_previously, indicates that this table should be new to the EE version being migrated to
449
+	 * or
450
+	 * activated currently. If this is a brand new activation or a migration, and we're indicating this table should
451
+	 * not
452
+	 * previously exist, then we want to set $drop_pre_existing_tables to TRUE (ie, we shouldn't discover that this
453
+	 * table exists in the DB in EEH_Activation::create_table- if it DOES exist, something's wrong and the old table
454
+	 * should be nuked.
455
+	 *
456
+	 * Just for a bit of context, the migration script's db_schema_changes_* methods
457
+	 * are called basically in 3 cases: on brand new activation of EE4 (ie no previous version of EE existed and the
458
+	 * plugin is being activated and we want to add all the brand new tables), upon reactivation of EE4 (it was
459
+	 * deactivated and then reactivated, in which case we want to just verify the DB structure is ok) that table should
460
+	 * be dropped), and during a migration when we're moving the DB to the state of the migration script
461
+	 *
462
+	 * @param string $table_name
463
+	 * @param string $table_definition_sql
464
+	 * @param string $engine_string
465
+	 */
466
+	protected function _table_is_new_in_this_version(
467
+		$table_name,
468
+		$table_definition_sql,
469
+		$engine_string = 'ENGINE=InnoDB '
470
+	) {
471
+		$this->_create_table_and_catch_errors(
472
+			$table_name,
473
+			$table_definition_sql,
474
+			$engine_string,
475
+			$this->_pre_existing_table_should_be_dropped(true)
476
+		);
477
+	}
478
+
479
+	/**
480
+	 * Like _table_is_new_in_this_version and _table_should_exist_previously, this function verifies the given table
481
+	 * exists. But we understand that this table has CHANGED in this version since the previous version. So it's not
482
+	 * completely new, but it's different. So we need to treat it like a new table in terms of verifying it's schema is
483
+	 * correct on activations, migrations, upgrades; but if it exists when it shouldn't, we need to be as lenient as
484
+	 * _table_should_exist_previously.
485
+	 * 8656]{Assumes only this plugin could have added this table (ie, if its a new activation of this plugin, the
486
+	 * table shouldn't exist).
487
+	 *
488
+	 * @param string $table_name
489
+	 * @param string $table_definition_sql
490
+	 * @param string $engine_string
491
+	 */
492
+	protected function _table_is_changed_in_this_version(
493
+		$table_name,
494
+		$table_definition_sql,
495
+		$engine_string = 'ENGINE=MyISAM'
496
+	) {
497
+		$this->_create_table_and_catch_errors(
498
+			$table_name,
499
+			$table_definition_sql,
500
+			$engine_string,
501
+			$this->_pre_existing_table_should_be_dropped(false)
502
+		);
503
+	}
504
+
505
+
506
+	/**
507
+	 * _old_table_exists
508
+	 * returns TRUE if the requested table exists in the current database
509
+	 *
510
+	 * @param string $table_name
511
+	 * @return boolean
512
+	 */
513
+	protected function _old_table_exists($table_name)
514
+	{
515
+		return $this->_get_table_analysis()->tableExists($table_name);
516
+	}
517
+
518
+
519
+	/**
520
+	 * _delete_table_if_empty
521
+	 * returns TRUE if the requested table was empty and successfully empty
522
+	 *
523
+	 * @param string $table_name
524
+	 * @return boolean
525
+	 */
526
+	protected function _delete_table_if_empty($table_name)
527
+	{
528
+		return EEH_Activation::delete_db_table_if_empty($table_name);
529
+	}
530
+
531
+
532
+	/**
533
+	 * It is preferred to use _table_has_not_changed_since_previous or _table_is_changed_in_this_version
534
+	 * as these are significantly more efficient or explicit.
535
+	 * Please see description of _table_is_new_in_this_version. This function will only set
536
+	 * EEH_Activation::create_table's $drop_pre_existing_tables to TRUE if it's a brand
537
+	 * new activation. ie, a more accurate name for this method would be "_table_added_previously_by_this_plugin"
538
+	 * because the table will be cleared out if this is a new activation (ie, if its a new activation, it actually
539
+	 * should exist previously). Otherwise, we'll always set $drop_pre_existing_tables to FALSE because the table
540
+	 * should have existed. Note, if the table is being MODIFIED in this version being activated or migrated to, then
541
+	 * you want _table_is_changed_in_this_version NOT this one. We don't check this table's structure during migrations
542
+	 * because apparently it hasn't changed since the previous one, right?
543
+	 *
544
+	 * @param string $table_name
545
+	 * @param string $table_definition_sql
546
+	 * @param string $engine_string
547
+	 */
548
+	protected function _table_should_exist_previously(
549
+		$table_name,
550
+		$table_definition_sql,
551
+		$engine_string = 'ENGINE=MyISAM'
552
+	) {
553
+		$this->_create_table_and_catch_errors(
554
+			$table_name,
555
+			$table_definition_sql,
556
+			$engine_string,
557
+			$this->_pre_existing_table_should_be_dropped(false)
558
+		);
559
+	}
560
+
561
+	/**
562
+	 * Exactly the same as _table_should_exist_previously(), except if this migration script is currently doing
563
+	 * a migration, we skip checking this table's structure in the database and just assume it's correct.
564
+	 * So this is useful only to improve efficiency when doing migrations (not a big deal for single site installs,
565
+	 * but important for multisite where migrations can take a very long time otherwise).
566
+	 * If the table is known to have changed since previous version, use _table_is_changed_in_this_version().
567
+	 * Assumes only this plugin could have added this table (ie, if its a new activation of this plugin, the table
568
+	 * shouldn't exist).
569
+	 *
570
+	 * @param string $table_name
571
+	 * @param string $table_definition_sql
572
+	 * @param string $engine_string
573
+	 */
574
+	protected function _table_has_not_changed_since_previous(
575
+		$table_name,
576
+		$table_definition_sql,
577
+		$engine_string = 'ENGINE=MyISAM'
578
+	) {
579
+		if ($this->_currently_migrating()) {
580
+			// if we're doing a migration, and this table apparently already exists, then we don't need do anything right?
581
+			return;
582
+		}
583
+		$this->_create_table_and_catch_errors(
584
+			$table_name,
585
+			$table_definition_sql,
586
+			$engine_string,
587
+			$this->_pre_existing_table_should_be_dropped(false)
588
+		);
589
+	}
590
+
591
+	/**
592
+	 * Returns whether or not this migration script is being used as part of an actual migration
593
+	 *
594
+	 * @return boolean
595
+	 */
596
+	protected function _currently_migrating()
597
+	{
598
+		// we want to know if we are currently performing a migration. We could just believe what was set on the _migrating property, but let's double-check (ie the script should apply and we should be in MM)
599
+		return $this->_migrating &&
600
+			   $this->can_migrate_from_version(
601
+				   EE_Data_Migration_Manager::instance()->ensure_current_database_state_is_set()
602
+			   ) &&
603
+			   EE_Maintenance_Mode::instance()->real_level() == EE_Maintenance_Mode::level_2_complete_maintenance;
604
+	}
605
+
606
+	/**
607
+	 * Determines if a table should be dropped, based on whether it's reported to be new in $table_is_new,
608
+	 * and the plugin's request type.
609
+	 * Assumes only this plugin could have added the table (ie, if its a new activation of this plugin, the table
610
+	 * shouldn't exist no matter what).
611
+	 *
612
+	 * @param boolean $table_is_new
613
+	 * @return boolean
614
+	 */
615
+	protected function _pre_existing_table_should_be_dropped($table_is_new)
616
+	{
617
+		if ($table_is_new) {
618
+			if ($this->_get_req_type_for_plugin_corresponding_to_this_dms() == EE_System::req_type_new_activation
619
+				|| $this->_currently_migrating()
620
+			) {
621
+				return true;
622
+			} else {
623
+				return false;
624
+			}
625
+		} else {
626
+			if (in_array(
627
+				$this->_get_req_type_for_plugin_corresponding_to_this_dms(),
628
+				array(EE_System::req_type_new_activation)
629
+			)) {
630
+				return true;
631
+			} else {
632
+				return false;
633
+			}
634
+		}
635
+	}
636
+
637
+	/**
638
+	 * Just wraps EEH_Activation::create_table, but catches any errors it may throw and adds them as errors on the DMS
639
+	 *
640
+	 * @param string  $table_name
641
+	 * @param string  $table_definition_sql
642
+	 * @param string  $engine_string
643
+	 * @param boolean $drop_pre_existing_tables
644
+	 */
645
+	private function _create_table_and_catch_errors(
646
+		$table_name,
647
+		$table_definition_sql,
648
+		$engine_string = 'ENGINE=MyISAM',
649
+		$drop_pre_existing_tables = false
650
+	) {
651
+		try {
652
+			EEH_Activation::create_table($table_name, $table_definition_sql, $engine_string, $drop_pre_existing_tables);
653
+		} catch (EE_Error $e) {
654
+			$message = $e->getMessage() . '<br>Stack Trace:' . $e->getTraceAsString();
655
+			$this->add_error($message);
656
+			$this->_feedback_message .= $message;
657
+		}
658
+	}
659
+
660
+
661
+	/**
662
+	 * Gets the request type for the plugin (core or addon) that corresponds to this DMS
663
+	 *
664
+	 * @return int one of EE_System::_req_type_* constants
665
+	 * @throws EE_Error
666
+	 */
667
+	private function _get_req_type_for_plugin_corresponding_to_this_dms()
668
+	{
669
+		if ($this->slug() == 'Core') {
670
+			return EE_System::instance()->detect_req_type();
671
+		} else {// it must be for an addon
672
+			$addon_name = $this->slug();
673
+			if (EE_Registry::instance()->get_addon_by_name($addon_name)) {
674
+				return EE_Registry::instance()->get_addon_by_name($addon_name)->detect_req_type();
675
+			} else {
676
+				throw new EE_Error(
677
+					sprintf(
678
+						__(
679
+							"The DMS slug '%s' should correspond to the addon's name, which should also be '%s', but no such addon was registered. These are the registered addons' names: %s",
680
+							"event_espresso"
681
+						),
682
+						$this->slug(),
683
+						$addon_name,
684
+						implode(",", array_keys(EE_Registry::instance()->get_addons_by_name()))
685
+					)
686
+				);
687
+			}
688
+		}
689
+	}
690
+
691
+
692
+	/**
693
+	 * returns an array of strings describing errors by all the script's stages
694
+	 *
695
+	 * @return array
696
+	 */
697
+	public function get_errors()
698
+	{
699
+		$all_errors = $this->_errors;
700
+		if (! is_array($all_errors)) {
701
+			$all_errors = array();
702
+		}
703
+		foreach ($this->stages() as $stage) {
704
+			$all_errors = array_merge($stage->get_errors(), $all_errors);
705
+		}
706
+		return $all_errors;
707
+	}
708
+
709
+
710
+	/**
711
+	 * Indicates whether or not this migration script should continue
712
+	 *
713
+	 * @return boolean
714
+	 */
715
+	public function can_continue()
716
+	{
717
+		return in_array(
718
+			$this->get_status(),
719
+			EE_Data_Migration_Manager::instance()->stati_that_indicate_to_continue_single_migration_script
720
+		);
721
+	}
722
+
723
+
724
+	/**
725
+	 * Gets all the data migration stages associated with this script. Note:
726
+	 * addons can filter this list to add their own stages, and because the list is
727
+	 * numerically-indexed, they can insert their stage wherever they like and it will
728
+	 * get ordered by the indexes
729
+	 *
730
+	 * @return EE_Data_Migration_Script_Stage[]
731
+	 */
732
+	protected function stages()
733
+	{
734
+		$stages = apply_filters('FHEE__' . get_class($this) . '__stages', $this->_migration_stages);
735
+		ksort($stages);
736
+		return $stages;
737
+	}
738
+
739
+
740
+	/**
741
+	 * Gets a string which should describe what's going on currently with this migration, which
742
+	 * can be displayed to the user
743
+	 *
744
+	 * @return string
745
+	 */
746
+	public function get_feedback_message()
747
+	{
748
+		return $this->_feedback_message;
749
+	}
750
+
751
+
752
+	/**
753
+	 * A lot like "__sleep()" magic method in purpose, this is meant for persisting this class'
754
+	 * properties to the DB. However, we don't want to use __sleep() because its quite
755
+	 * possible that this class is defined when it goes to sleep, but NOT available when it
756
+	 * awakes (eg, this class is part of an addon that is deactivated at some point).
757
+	 */
758
+	public function properties_as_array()
759
+	{
760
+		$properties = parent::properties_as_array();
761
+		$properties['_migration_stages'] = array();
762
+		foreach ($this->_migration_stages as $migration_stage_priority => $migration_stage_class) {
763
+			$properties['_migration_stages'][ $migration_stage_priority ] = $migration_stage_class->properties_as_array(
764
+			);
765
+		}
766
+		unset($properties['_mappings']);
767
+		unset($properties['previous_dms']);
768
+
769
+		foreach ($this->_mappings as $old_table_name => $mapping_to_new_table) {
770
+			foreach ($mapping_to_new_table as $new_table_name => $mapping) {
771
+				$this->_set_mapping_option($old_table_name, $new_table_name, $mapping);
772
+			}
773
+		}
774
+		return $properties;
775
+	}
776
+
777
+
778
+	/**
779
+	 * Sets all of the properties of this script stage to match what's in the array, which is assumed
780
+	 * to have been made from the properties_as_array() function.
781
+	 *
782
+	 * @param array $array_of_properties like what's produced from properties_as_array() method
783
+	 * @return void
784
+	 */
785
+	public function instantiate_from_array_of_properties($array_of_properties)
786
+	{
787
+		$stages_properties_arrays = $array_of_properties['_migration_stages'];
788
+		unset($array_of_properties['_migration_stages']);
789
+		unset($array_of_properties['class']);
790
+		foreach ($array_of_properties as $property_name => $property_value) {
791
+			$this->{$property_name} = $property_value;
792
+		}
793
+		// _migration_stages are already instantiated, but have only default data
794
+		foreach ($this->_migration_stages as $stage) {
795
+			$stage_data = $this->_find_migration_stage_data_with_classname(
796
+				get_class($stage),
797
+				$stages_properties_arrays
798
+			);
799
+			// SO, if we found the stage data that was saved, use it. Otherwise, I guess the stage is new? (maybe added by
800
+			// an addon? Unlikely... not sure why it wouldn't exist, but if it doesn't just treat it like it was never started yet)
801
+			if ($stage_data) {
802
+				$stage->instantiate_from_array_of_properties($stage_data);
803
+			}
804
+		}
805
+	}
806
+
807
+
808
+	/**
809
+	 * Gets the migration data from the array $migration_stage_data_arrays (which is an array of arrays, each of which
810
+	 * is pretty well identical to EE_Data_Migration_Stage objects except all their properties are array indexes)
811
+	 * for the given classname
812
+	 *
813
+	 * @param string $classname
814
+	 * @param array  $migration_stage_data_arrays
815
+	 * @return null
816
+	 */
817
+	private function _find_migration_stage_data_with_classname($classname, $migration_stage_data_arrays)
818
+	{
819
+		foreach ($migration_stage_data_arrays as $migration_stage_data_array) {
820
+			if (isset($migration_stage_data_array['class']) && $migration_stage_data_array['class'] == $classname) {
821
+				return $migration_stage_data_array;
822
+			}
823
+		}
824
+		return null;
825
+	}
826
+
827
+
828
+	/**
829
+	 * Returns the version that this script migrates to, based on the script's name.
830
+	 * Cannot be overwritten because lots of code needs to know which version a script
831
+	 * migrates to knowing only its name.
832
+	 *
833
+	 * @return array where the first key is the plugin's slug, the 2nd is the version of that plugin
834
+	 * that will be updated to. Eg array('Core','4.1.0')
835
+	 */
836
+	final public function migrates_to_version()
837
+	{
838
+		return EE_Data_Migration_Manager::instance()->script_migrates_to_version(get_class($this));
839
+	}
840
+
841
+
842
+	/**
843
+	 * Gets this addon's slug as it would appear in the current_db_state wp option,
844
+	 * and if this migration script is for an addon, it SHOULD match the addon's slug
845
+	 * (and also the addon's classname, minus the 'EE_' prefix.). Eg, 'Calendar' for the EE_Calendar addon.
846
+	 * Or 'Core' for core (non-addon).
847
+	 *
848
+	 * @return string
849
+	 */
850
+	public function slug()
851
+	{
852
+		$migrates_to_version_info = $this->migrates_to_version();
853
+		// the slug is the first part of the array
854
+		return $migrates_to_version_info['slug'];
855
+	}
856
+
857
+
858
+	/**
859
+	 * Returns the script's priority relative to DMSs from other addons. However, when
860
+	 * two DMSs from the same addon/core apply, this is ignored (and instead the version that
861
+	 * the script migrates to is used to determine which to run first). The default is 5, but all core DMSs
862
+	 * normally have priority 10. (So if you want a DMS "A" to run before DMS "B", both of which are from addons,
863
+	 * and both of which CAN run at the same time (ie, "B" doesn't depend on "A" to set
864
+	 * the database up so it can run), then you can set "A" to priority 3 or something.
865
+	 *
866
+	 * @return int
867
+	 */
868
+	public function priority()
869
+	{
870
+		return $this->_priority;
871
+	}
872
+
873
+
874
+	/**
875
+	 * Sets whether or not this DMS is being ran as part of a migration, instead of
876
+	 * just being used to setup (or verify) the current database structure matches
877
+	 * what the latest DMS indicates it should be
878
+	 *
879
+	 * @param boolean $migrating
880
+	 * @return void
881
+	 */
882
+	public function set_migrating($migrating = true)
883
+	{
884
+		$this->_migrating = $migrating;
885
+	}
886
+
887
+	/**
888
+	 * Marks that we think this migration class can continue to migrate
889
+	 */
890
+	public function reattempt()
891
+	{
892
+		parent::reattempt();
893
+		// also, we want to reattempt any stages that were marked as borked
894
+		foreach ($this->stages() as $stage) {
895
+			if ($stage->is_broken()) {
896
+				$stage->reattempt();
897
+			}
898
+		}
899
+	}
900 900
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Registration.class.php 1 patch
Indentation   +2065 added lines, -2065 removed lines patch added patch discarded remove patch
@@ -17,2069 +17,2069 @@
 block discarded – undo
17 17
 {
18 18
 
19 19
 
20
-    /**
21
-     * Used to reference when a registration has never been checked in.
22
-     *
23
-     * @deprecated use \EE_Checkin::status_checked_never instead
24
-     * @type int
25
-     */
26
-    const checkin_status_never = 2;
27
-
28
-    /**
29
-     * Used to reference when a registration has been checked in.
30
-     *
31
-     * @deprecated use \EE_Checkin::status_checked_in instead
32
-     * @type int
33
-     */
34
-    const checkin_status_in = 1;
35
-
36
-
37
-    /**
38
-     * Used to reference when a registration has been checked out.
39
-     *
40
-     * @deprecated use \EE_Checkin::status_checked_out instead
41
-     * @type int
42
-     */
43
-    const checkin_status_out = 0;
44
-
45
-
46
-    /**
47
-     * extra meta key for tracking reg status os trashed registrations
48
-     *
49
-     * @type string
50
-     */
51
-    const PRE_TRASH_REG_STATUS_KEY = 'pre_trash_registration_status';
52
-
53
-
54
-    /**
55
-     * extra meta key for tracking if registration has reserved ticket
56
-     *
57
-     * @type string
58
-     */
59
-    const HAS_RESERVED_TICKET_KEY = 'has_reserved_ticket';
60
-
61
-
62
-    /**
63
-     * @param array  $props_n_values          incoming values
64
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
65
-     *                                        used.)
66
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
67
-     *                                        date_format and the second value is the time format
68
-     * @return EE_Registration
69
-     * @throws EE_Error
70
-     */
71
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
72
-    {
73
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
74
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
75
-    }
76
-
77
-
78
-    /**
79
-     * @param array  $props_n_values  incoming values from the database
80
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
81
-     *                                the website will be used.
82
-     * @return EE_Registration
83
-     */
84
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
85
-    {
86
-        return new self($props_n_values, true, $timezone);
87
-    }
88
-
89
-
90
-    /**
91
-     *        Set Event ID
92
-     *
93
-     * @param        int $EVT_ID Event ID
94
-     * @throws EE_Error
95
-     * @throws RuntimeException
96
-     */
97
-    public function set_event($EVT_ID = 0)
98
-    {
99
-        $this->set('EVT_ID', $EVT_ID);
100
-    }
101
-
102
-
103
-    /**
104
-     * Overrides parent set() method so that all calls to set( 'REG_code', $REG_code ) OR set( 'STS_ID', $STS_ID ) can
105
-     * be routed to internal methods
106
-     *
107
-     * @param string $field_name
108
-     * @param mixed  $field_value
109
-     * @param bool   $use_default
110
-     * @throws EE_Error
111
-     * @throws EntityNotFoundException
112
-     * @throws InvalidArgumentException
113
-     * @throws InvalidDataTypeException
114
-     * @throws InvalidInterfaceException
115
-     * @throws ReflectionException
116
-     * @throws RuntimeException
117
-     */
118
-    public function set($field_name, $field_value, $use_default = false)
119
-    {
120
-        switch ($field_name) {
121
-            case 'REG_code':
122
-                if (! empty($field_value) && $this->reg_code() === null) {
123
-                    $this->set_reg_code($field_value, $use_default);
124
-                }
125
-                break;
126
-            case 'STS_ID':
127
-                $this->set_status($field_value, $use_default);
128
-                break;
129
-            default:
130
-                parent::set($field_name, $field_value, $use_default);
131
-        }
132
-    }
133
-
134
-
135
-    /**
136
-     * Set Status ID
137
-     * updates the registration status and ALSO...
138
-     * calls reserve_registration_space() if the reg status changes TO approved from any other reg status
139
-     * calls release_registration_space() if the reg status changes FROM approved to any other reg status
140
-     *
141
-     * @param string                $new_STS_ID
142
-     * @param boolean               $use_default
143
-     * @param ContextInterface|null $context
144
-     * @return bool
145
-     * @throws DomainException
146
-     * @throws EE_Error
147
-     * @throws EntityNotFoundException
148
-     * @throws InvalidArgumentException
149
-     * @throws InvalidDataTypeException
150
-     * @throws InvalidInterfaceException
151
-     * @throws ReflectionException
152
-     * @throws RuntimeException
153
-     * @throws UnexpectedEntityException
154
-     */
155
-    public function set_status($new_STS_ID = null, $use_default = false, ContextInterface $context = null)
156
-    {
157
-        // get current REG_Status
158
-        $old_STS_ID = $this->status_ID();
159
-        // if status has changed
160
-        if ($old_STS_ID !== $new_STS_ID // and that status has actually changed
161
-            && ! empty($old_STS_ID) // and that old status is actually set
162
-            && ! empty($new_STS_ID) // as well as the new status
163
-            && $this->ID() // ensure registration is in the db
164
-        ) {
165
-            // update internal status first
166
-            parent::set('STS_ID', $new_STS_ID, $use_default);
167
-            // THEN handle other changes that occur when reg status changes
168
-            // TO approved
169
-            if ($new_STS_ID === EEM_Registration::status_id_approved) {
170
-                // reserve a space by incrementing ticket and datetime sold values
171
-                $this->reserveRegistrationSpace();
172
-                do_action('AHEE__EE_Registration__set_status__to_approved', $this, $old_STS_ID, $new_STS_ID, $context);
173
-                // OR FROM  approved
174
-            } elseif ($old_STS_ID === EEM_Registration::status_id_approved) {
175
-                // release a space by decrementing ticket and datetime sold values
176
-                $this->releaseRegistrationSpace();
177
-                do_action(
178
-                    'AHEE__EE_Registration__set_status__from_approved',
179
-                    $this,
180
-                    $old_STS_ID,
181
-                    $new_STS_ID,
182
-                    $context
183
-                );
184
-            }
185
-            // update status
186
-            parent::set('STS_ID', $new_STS_ID, $use_default);
187
-            $this->updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, $context);
188
-            if ($this->statusChangeUpdatesTransaction($context)) {
189
-                $this->updateTransactionAfterStatusChange();
190
-            }
191
-            do_action('AHEE__EE_Registration__set_status__after_update', $this, $old_STS_ID, $new_STS_ID, $context);
192
-            return true;
193
-        }
194
-        // even though the old value matches the new value, it's still good to
195
-        // allow the parent set method to have a say
196
-        parent::set('STS_ID', $new_STS_ID, $use_default);
197
-        return true;
198
-    }
199
-
200
-
201
-    /**
202
-     * update REGs and TXN when cancelled or declined registrations involved
203
-     *
204
-     * @param string                $new_STS_ID
205
-     * @param string                $old_STS_ID
206
-     * @param ContextInterface|null $context
207
-     * @throws EE_Error
208
-     * @throws InvalidArgumentException
209
-     * @throws InvalidDataTypeException
210
-     * @throws InvalidInterfaceException
211
-     * @throws ReflectionException
212
-     * @throws RuntimeException
213
-     */
214
-    private function updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, ContextInterface $context = null)
215
-    {
216
-        // these reg statuses should not be considered in any calculations involving monies owing
217
-        $closed_reg_statuses = EEM_Registration::closed_reg_statuses();
218
-        // true if registration has been cancelled or declined
219
-        $this->updateIfCanceled(
220
-            $closed_reg_statuses,
221
-            $new_STS_ID,
222
-            $old_STS_ID,
223
-            $context
224
-        );
225
-        $this->updateIfReinstated(
226
-            $closed_reg_statuses,
227
-            $new_STS_ID,
228
-            $old_STS_ID,
229
-            $context
230
-        );
231
-    }
232
-
233
-
234
-    /**
235
-     * update REGs and TXN when cancelled or declined registrations involved
236
-     *
237
-     * @param array                 $closed_reg_statuses
238
-     * @param string                $new_STS_ID
239
-     * @param string                $old_STS_ID
240
-     * @param ContextInterface|null $context
241
-     * @throws EE_Error
242
-     * @throws InvalidArgumentException
243
-     * @throws InvalidDataTypeException
244
-     * @throws InvalidInterfaceException
245
-     * @throws ReflectionException
246
-     * @throws RuntimeException
247
-     */
248
-    private function updateIfCanceled(
249
-        array $closed_reg_statuses,
250
-        $new_STS_ID,
251
-        $old_STS_ID,
252
-        ContextInterface $context = null
253
-    ) {
254
-        // true if registration has been cancelled or declined
255
-        if (in_array($new_STS_ID, $closed_reg_statuses, true)
256
-            && ! in_array($old_STS_ID, $closed_reg_statuses, true)
257
-        ) {
258
-            /** @type EE_Registration_Processor $registration_processor */
259
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
260
-            /** @type EE_Transaction_Processor $transaction_processor */
261
-            $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
262
-            // cancelled or declined registration
263
-            $registration_processor->update_registration_after_being_canceled_or_declined(
264
-                $this,
265
-                $closed_reg_statuses
266
-            );
267
-            $transaction_processor->update_transaction_after_canceled_or_declined_registration(
268
-                $this,
269
-                $closed_reg_statuses,
270
-                false
271
-            );
272
-            do_action(
273
-                'AHEE__EE_Registration__set_status__canceled_or_declined',
274
-                $this,
275
-                $old_STS_ID,
276
-                $new_STS_ID,
277
-                $context
278
-            );
279
-            return;
280
-        }
281
-    }
282
-
283
-
284
-    /**
285
-     * update REGs and TXN when cancelled or declined registrations involved
286
-     *
287
-     * @param array                 $closed_reg_statuses
288
-     * @param string                $new_STS_ID
289
-     * @param string                $old_STS_ID
290
-     * @param ContextInterface|null $context
291
-     * @throws EE_Error
292
-     * @throws InvalidArgumentException
293
-     * @throws InvalidDataTypeException
294
-     * @throws InvalidInterfaceException
295
-     * @throws ReflectionException
296
-     */
297
-    private function updateIfReinstated(
298
-        array $closed_reg_statuses,
299
-        $new_STS_ID,
300
-        $old_STS_ID,
301
-        ContextInterface $context = null
302
-    ) {
303
-        // true if reinstating cancelled or declined registration
304
-        if (in_array($old_STS_ID, $closed_reg_statuses, true)
305
-            && ! in_array($new_STS_ID, $closed_reg_statuses, true)
306
-        ) {
307
-            /** @type EE_Registration_Processor $registration_processor */
308
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
309
-            /** @type EE_Transaction_Processor $transaction_processor */
310
-            $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
311
-            // reinstating cancelled or declined registration
312
-            $registration_processor->update_canceled_or_declined_registration_after_being_reinstated(
313
-                $this,
314
-                $closed_reg_statuses
315
-            );
316
-            $transaction_processor->update_transaction_after_reinstating_canceled_registration(
317
-                $this,
318
-                $closed_reg_statuses,
319
-                false
320
-            );
321
-            do_action(
322
-                'AHEE__EE_Registration__set_status__after_reinstated',
323
-                $this,
324
-                $old_STS_ID,
325
-                $new_STS_ID,
326
-                $context
327
-            );
328
-        }
329
-    }
330
-
331
-
332
-    /**
333
-     * @param ContextInterface|null $context
334
-     * @return bool
335
-     */
336
-    private function statusChangeUpdatesTransaction(ContextInterface $context = null)
337
-    {
338
-        $contexts_that_do_not_update_transaction = (array) apply_filters(
339
-            'AHEE__EE_Registration__statusChangeUpdatesTransaction__contexts_that_do_not_update_transaction',
340
-            array('spco_reg_step_attendee_information_process_registrations'),
341
-            $context,
342
-            $this
343
-        );
344
-        return ! (
345
-            $context instanceof ContextInterface
346
-            && in_array($context->slug(), $contexts_that_do_not_update_transaction, true)
347
-        );
348
-    }
349
-
350
-
351
-    /**
352
-     * @throws EE_Error
353
-     * @throws EntityNotFoundException
354
-     * @throws InvalidArgumentException
355
-     * @throws InvalidDataTypeException
356
-     * @throws InvalidInterfaceException
357
-     * @throws ReflectionException
358
-     * @throws RuntimeException
359
-     */
360
-    private function updateTransactionAfterStatusChange()
361
-    {
362
-        /** @type EE_Transaction_Payments $transaction_payments */
363
-        $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
364
-        $transaction_payments->recalculate_transaction_total($this->transaction(), false);
365
-        $this->transaction()->update_status_based_on_total_paid(true);
366
-    }
367
-
368
-
369
-    /**
370
-     *        get Status ID
371
-     */
372
-    public function status_ID()
373
-    {
374
-        return $this->get('STS_ID');
375
-    }
376
-
377
-
378
-    /**
379
-     * Gets the ticket this registration is for
380
-     *
381
-     * @param boolean $include_archived whether to include archived tickets or not.
382
-     *
383
-     * @return EE_Ticket|EE_Base_Class
384
-     * @throws EE_Error
385
-     */
386
-    public function ticket($include_archived = true)
387
-    {
388
-        $query_params = array();
389
-        if ($include_archived) {
390
-            $query_params['default_where_conditions'] = 'none';
391
-        }
392
-        return $this->get_first_related('Ticket', $query_params);
393
-    }
394
-
395
-
396
-    /**
397
-     * Gets the event this registration is for
398
-     *
399
-     * @return EE_Event
400
-     * @throws EE_Error
401
-     * @throws EntityNotFoundException
402
-     */
403
-    public function event()
404
-    {
405
-        $event = $this->get_first_related('Event');
406
-        if (! $event instanceof \EE_Event) {
407
-            throw new EntityNotFoundException('Event ID', $this->event_ID());
408
-        }
409
-        return $event;
410
-    }
411
-
412
-
413
-    /**
414
-     * Gets the "author" of the registration.  Note that for the purposes of registrations, the author will correspond
415
-     * with the author of the event this registration is for.
416
-     *
417
-     * @since 4.5.0
418
-     * @return int
419
-     * @throws EE_Error
420
-     * @throws EntityNotFoundException
421
-     */
422
-    public function wp_user()
423
-    {
424
-        $event = $this->event();
425
-        if ($event instanceof EE_Event) {
426
-            return $event->wp_user();
427
-        }
428
-        return 0;
429
-    }
430
-
431
-
432
-    /**
433
-     * increments this registration's related ticket sold and corresponding datetime sold values
434
-     *
435
-     * @return void
436
-     * @throws DomainException
437
-     * @throws EE_Error
438
-     * @throws EntityNotFoundException
439
-     * @throws InvalidArgumentException
440
-     * @throws InvalidDataTypeException
441
-     * @throws InvalidInterfaceException
442
-     * @throws ReflectionException
443
-     * @throws UnexpectedEntityException
444
-     */
445
-    private function reserveRegistrationSpace()
446
-    {
447
-        // reserved ticket and datetime counts will be decremented as sold counts are incremented
448
-        // so stop tracking that this reg has a ticket reserved
449
-        $this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
450
-        $ticket = $this->ticket();
451
-        $ticket->increaseSold();
452
-        // possibly set event status to sold out
453
-        $this->event()->perform_sold_out_status_check();
454
-    }
455
-
456
-
457
-    /**
458
-     * decrements (subtracts) this registration's related ticket sold and corresponding datetime sold values
459
-     *
460
-     * @return void
461
-     * @throws DomainException
462
-     * @throws EE_Error
463
-     * @throws EntityNotFoundException
464
-     * @throws InvalidArgumentException
465
-     * @throws InvalidDataTypeException
466
-     * @throws InvalidInterfaceException
467
-     * @throws ReflectionException
468
-     * @throws UnexpectedEntityException
469
-     */
470
-    private function releaseRegistrationSpace()
471
-    {
472
-        $ticket = $this->ticket();
473
-        $ticket->decreaseSold();
474
-        // possibly change event status from sold out back to previous status
475
-        $this->event()->perform_sold_out_status_check();
476
-    }
477
-
478
-
479
-    /**
480
-     * tracks this registration's ticket reservation in extra meta
481
-     * and can increment related ticket reserved and corresponding datetime reserved values
482
-     *
483
-     * @param bool $update_ticket if true, will increment ticket and datetime reserved count
484
-     * @return void
485
-     * @throws EE_Error
486
-     * @throws InvalidArgumentException
487
-     * @throws InvalidDataTypeException
488
-     * @throws InvalidInterfaceException
489
-     * @throws ReflectionException
490
-     */
491
-    public function reserve_ticket($update_ticket = false, $source = 'unknown')
492
-    {
493
-        // only reserve ticket if space is not currently reserved
494
-        if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) !== true) {
495
-            $this->update_extra_meta('reserve_ticket', "{$this->ticket_ID()} from {$source}");
496
-            // IMPORTANT !!!
497
-            // although checking $update_ticket first would be more efficient,
498
-            // we NEED to ALWAYS call update_extra_meta(), which is why that is done first
499
-            if ($this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true)
500
-                && $update_ticket
501
-            ) {
502
-                $ticket = $this->ticket();
503
-                $ticket->increaseReserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
504
-                $ticket->save();
505
-            }
506
-        }
507
-    }
508
-
509
-
510
-    /**
511
-     * stops tracking this registration's ticket reservation in extra meta
512
-     * decrements (subtracts) related ticket reserved and corresponding datetime reserved values
513
-     *
514
-     * @param bool $update_ticket if true, will decrement ticket and datetime reserved count
515
-     * @return void
516
-     * @throws EE_Error
517
-     * @throws InvalidArgumentException
518
-     * @throws InvalidDataTypeException
519
-     * @throws InvalidInterfaceException
520
-     * @throws ReflectionException
521
-     */
522
-    public function release_reserved_ticket($update_ticket = false, $source = 'unknown')
523
-    {
524
-        // only release ticket if space is currently reserved
525
-        if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) === true) {
526
-            $this->update_extra_meta('release_reserved_ticket', "{$this->ticket_ID()} from {$source}");
527
-            // IMPORTANT !!!
528
-            // although checking $update_ticket first would be more efficient,
529
-            // we NEED to ALWAYS call update_extra_meta(), which is why that is done first
530
-            if ($this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, false)
531
-                && $update_ticket
532
-            ) {
533
-                $ticket = $this->ticket();
534
-                $ticket->decreaseReserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
535
-            }
536
-        }
537
-    }
538
-
539
-
540
-    /**
541
-     * Set Attendee ID
542
-     *
543
-     * @param        int $ATT_ID Attendee ID
544
-     * @throws EE_Error
545
-     * @throws RuntimeException
546
-     */
547
-    public function set_attendee_id($ATT_ID = 0)
548
-    {
549
-        $this->set('ATT_ID', $ATT_ID);
550
-    }
551
-
552
-
553
-    /**
554
-     *        Set Transaction ID
555
-     *
556
-     * @param        int $TXN_ID Transaction ID
557
-     * @throws EE_Error
558
-     * @throws RuntimeException
559
-     */
560
-    public function set_transaction_id($TXN_ID = 0)
561
-    {
562
-        $this->set('TXN_ID', $TXN_ID);
563
-    }
564
-
565
-
566
-    /**
567
-     *        Set Session
568
-     *
569
-     * @param    string $REG_session PHP Session ID
570
-     * @throws EE_Error
571
-     * @throws RuntimeException
572
-     */
573
-    public function set_session($REG_session = '')
574
-    {
575
-        $this->set('REG_session', $REG_session);
576
-    }
577
-
578
-
579
-    /**
580
-     *        Set Registration URL Link
581
-     *
582
-     * @param    string $REG_url_link Registration URL Link
583
-     * @throws EE_Error
584
-     * @throws RuntimeException
585
-     */
586
-    public function set_reg_url_link($REG_url_link = '')
587
-    {
588
-        $this->set('REG_url_link', $REG_url_link);
589
-    }
590
-
591
-
592
-    /**
593
-     *        Set Attendee Counter
594
-     *
595
-     * @param        int $REG_count Primary Attendee
596
-     * @throws EE_Error
597
-     * @throws RuntimeException
598
-     */
599
-    public function set_count($REG_count = 1)
600
-    {
601
-        $this->set('REG_count', $REG_count);
602
-    }
603
-
604
-
605
-    /**
606
-     *        Set Group Size
607
-     *
608
-     * @param        boolean $REG_group_size Group Registration
609
-     * @throws EE_Error
610
-     * @throws RuntimeException
611
-     */
612
-    public function set_group_size($REG_group_size = false)
613
-    {
614
-        $this->set('REG_group_size', $REG_group_size);
615
-    }
616
-
617
-
618
-    /**
619
-     *    is_not_approved -  convenience method that returns TRUE if REG status ID ==
620
-     *    EEM_Registration::status_id_not_approved
621
-     *
622
-     * @return        boolean
623
-     */
624
-    public function is_not_approved()
625
-    {
626
-        return $this->status_ID() == EEM_Registration::status_id_not_approved ? true : false;
627
-    }
628
-
629
-
630
-    /**
631
-     *    is_pending_payment -  convenience method that returns TRUE if REG status ID ==
632
-     *    EEM_Registration::status_id_pending_payment
633
-     *
634
-     * @return        boolean
635
-     */
636
-    public function is_pending_payment()
637
-    {
638
-        return $this->status_ID() == EEM_Registration::status_id_pending_payment ? true : false;
639
-    }
640
-
641
-
642
-    /**
643
-     *    is_approved -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_approved
644
-     *
645
-     * @return        boolean
646
-     */
647
-    public function is_approved()
648
-    {
649
-        return $this->status_ID() == EEM_Registration::status_id_approved ? true : false;
650
-    }
651
-
652
-
653
-    /**
654
-     *    is_cancelled -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_cancelled
655
-     *
656
-     * @return        boolean
657
-     */
658
-    public function is_cancelled()
659
-    {
660
-        return $this->status_ID() == EEM_Registration::status_id_cancelled ? true : false;
661
-    }
662
-
663
-
664
-    /**
665
-     *    is_declined -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_declined
666
-     *
667
-     * @return        boolean
668
-     */
669
-    public function is_declined()
670
-    {
671
-        return $this->status_ID() == EEM_Registration::status_id_declined ? true : false;
672
-    }
673
-
674
-
675
-    /**
676
-     *    is_incomplete -  convenience method that returns TRUE if REG status ID ==
677
-     *    EEM_Registration::status_id_incomplete
678
-     *
679
-     * @return        boolean
680
-     */
681
-    public function is_incomplete()
682
-    {
683
-        return $this->status_ID() == EEM_Registration::status_id_incomplete ? true : false;
684
-    }
685
-
686
-
687
-    /**
688
-     *        Set Registration Date
689
-     *
690
-     * @param        mixed ( int or string ) $REG_date Registration Date - Unix timestamp or string representation of
691
-     *                                                 Date
692
-     * @throws EE_Error
693
-     * @throws RuntimeException
694
-     */
695
-    public function set_reg_date($REG_date = false)
696
-    {
697
-        $this->set('REG_date', $REG_date);
698
-    }
699
-
700
-
701
-    /**
702
-     *    Set final price owing for this registration after all ticket/price modifications
703
-     *
704
-     * @access    public
705
-     * @param    float $REG_final_price
706
-     * @throws EE_Error
707
-     * @throws RuntimeException
708
-     */
709
-    public function set_final_price($REG_final_price = 0.00)
710
-    {
711
-        $this->set('REG_final_price', $REG_final_price);
712
-    }
713
-
714
-
715
-    /**
716
-     *    Set amount paid towards this registration's final price
717
-     *
718
-     * @access    public
719
-     * @param    float $REG_paid
720
-     * @throws EE_Error
721
-     * @throws RuntimeException
722
-     */
723
-    public function set_paid($REG_paid = 0.00)
724
-    {
725
-        $this->set('REG_paid', $REG_paid);
726
-    }
727
-
728
-
729
-    /**
730
-     *        Attendee Is Going
731
-     *
732
-     * @param        boolean $REG_att_is_going Attendee Is Going
733
-     * @throws EE_Error
734
-     * @throws RuntimeException
735
-     */
736
-    public function set_att_is_going($REG_att_is_going = false)
737
-    {
738
-        $this->set('REG_att_is_going', $REG_att_is_going);
739
-    }
740
-
741
-
742
-    /**
743
-     * Gets the related attendee
744
-     *
745
-     * @return EE_Attendee
746
-     * @throws EE_Error
747
-     */
748
-    public function attendee()
749
-    {
750
-        return $this->get_first_related('Attendee');
751
-    }
752
-
753
-
754
-    /**
755
-     *        get Event ID
756
-     */
757
-    public function event_ID()
758
-    {
759
-        return $this->get('EVT_ID');
760
-    }
761
-
762
-
763
-    /**
764
-     *        get Event ID
765
-     */
766
-    public function event_name()
767
-    {
768
-        $event = $this->event_obj();
769
-        if ($event) {
770
-            return $event->name();
771
-        } else {
772
-            return null;
773
-        }
774
-    }
775
-
776
-
777
-    /**
778
-     * Fetches the event this registration is for
779
-     *
780
-     * @return EE_Event
781
-     * @throws EE_Error
782
-     */
783
-    public function event_obj()
784
-    {
785
-        return $this->get_first_related('Event');
786
-    }
787
-
788
-
789
-    /**
790
-     *        get Attendee ID
791
-     */
792
-    public function attendee_ID()
793
-    {
794
-        return $this->get('ATT_ID');
795
-    }
796
-
797
-
798
-    /**
799
-     *        get PHP Session ID
800
-     */
801
-    public function session_ID()
802
-    {
803
-        return $this->get('REG_session');
804
-    }
805
-
806
-
807
-    /**
808
-     * Gets the string which represents the URL trigger for the receipt template in the message template system.
809
-     *
810
-     * @param string $messenger 'pdf' or 'html'.  Default 'html'.
811
-     * @return string
812
-     */
813
-    public function receipt_url($messenger = 'html')
814
-    {
815
-
816
-        /**
817
-         * The below will be deprecated one version after this.  We check first if there is a custom receipt template
818
-         * already in use on old system.  If there is then we just return the standard url for it.
819
-         *
820
-         * @since 4.5.0
821
-         */
822
-        $template_relative_path = 'modules/gateways/Invoice/lib/templates/receipt_body.template.php';
823
-        $has_custom = EEH_Template::locate_template(
824
-            $template_relative_path,
825
-            array(),
826
-            true,
827
-            true,
828
-            true
829
-        );
830
-
831
-        if ($has_custom) {
832
-            return add_query_arg(array('receipt' => 'true'), $this->invoice_url('launch'));
833
-        }
834
-        return apply_filters('FHEE__EE_Registration__receipt_url__receipt_url', '', $this, $messenger, 'receipt');
835
-    }
836
-
837
-
838
-    /**
839
-     * Gets the string which represents the URL trigger for the invoice template in the message template system.
840
-     *
841
-     * @param string $messenger 'pdf' or 'html'.  Default 'html'.
842
-     * @return string
843
-     * @throws EE_Error
844
-     */
845
-    public function invoice_url($messenger = 'html')
846
-    {
847
-        /**
848
-         * The below will be deprecated one version after this.  We check first if there is a custom invoice template
849
-         * already in use on old system.  If there is then we just return the standard url for it.
850
-         *
851
-         * @since 4.5.0
852
-         */
853
-        $template_relative_path = 'modules/gateways/Invoice/lib/templates/invoice_body.template.php';
854
-        $has_custom = EEH_Template::locate_template(
855
-            $template_relative_path,
856
-            array(),
857
-            true,
858
-            true,
859
-            true
860
-        );
861
-
862
-        if ($has_custom) {
863
-            if ($messenger == 'html') {
864
-                return $this->invoice_url('launch');
865
-            }
866
-            $route = $messenger == 'download' || $messenger == 'pdf' ? 'download_invoice' : 'launch_invoice';
867
-
868
-            $query_args = array('ee' => $route, 'id' => $this->reg_url_link());
869
-            if ($messenger == 'html') {
870
-                $query_args['html'] = true;
871
-            }
872
-            return add_query_arg($query_args, get_permalink(EE_Registry::instance()->CFG->core->thank_you_page_id));
873
-        }
874
-        return apply_filters('FHEE__EE_Registration__invoice_url__invoice_url', '', $this, $messenger, 'invoice');
875
-    }
876
-
877
-
878
-    /**
879
-     * get Registration URL Link
880
-     *
881
-     * @access public
882
-     * @return string
883
-     * @throws EE_Error
884
-     */
885
-    public function reg_url_link()
886
-    {
887
-        return (string) $this->get('REG_url_link');
888
-    }
889
-
890
-
891
-    /**
892
-     * Echoes out invoice_url()
893
-     *
894
-     * @param string $type 'download','launch', or 'html' (default is 'launch')
895
-     * @return void
896
-     * @throws EE_Error
897
-     */
898
-    public function e_invoice_url($type = 'launch')
899
-    {
900
-        echo $this->invoice_url($type);
901
-    }
902
-
903
-
904
-    /**
905
-     * Echoes out payment_overview_url
906
-     */
907
-    public function e_payment_overview_url()
908
-    {
909
-        echo $this->payment_overview_url();
910
-    }
911
-
912
-
913
-    /**
914
-     * Gets the URL for the checkout payment options reg step
915
-     * with this registration's REG_url_link added as a query parameter
916
-     *
917
-     * @param bool $clear_session Set to true when you want to clear the session on revisiting the
918
-     *                            payment overview url.
919
-     * @return string
920
-     * @throws InvalidInterfaceException
921
-     * @throws InvalidDataTypeException
922
-     * @throws EE_Error
923
-     * @throws InvalidArgumentException
924
-     */
925
-    public function payment_overview_url($clear_session = false)
926
-    {
927
-        return add_query_arg(
928
-            (array) apply_filters(
929
-                'FHEE__EE_Registration__payment_overview_url__query_args',
930
-                array(
931
-                    'e_reg_url_link' => $this->reg_url_link(),
932
-                    'step'           => 'payment_options',
933
-                    'revisit'        => true,
934
-                    'clear_session'  => (bool) $clear_session,
935
-                ),
936
-                $this
937
-            ),
938
-            EE_Registry::instance()->CFG->core->reg_page_url()
939
-        );
940
-    }
941
-
942
-
943
-    /**
944
-     * Gets the URL for the checkout attendee information reg step
945
-     * with this registration's REG_url_link added as a query parameter
946
-     *
947
-     * @return string
948
-     * @throws InvalidInterfaceException
949
-     * @throws InvalidDataTypeException
950
-     * @throws EE_Error
951
-     * @throws InvalidArgumentException
952
-     */
953
-    public function edit_attendee_information_url()
954
-    {
955
-        return add_query_arg(
956
-            (array) apply_filters(
957
-                'FHEE__EE_Registration__edit_attendee_information_url__query_args',
958
-                array(
959
-                    'e_reg_url_link' => $this->reg_url_link(),
960
-                    'step'           => 'attendee_information',
961
-                    'revisit'        => true,
962
-                ),
963
-                $this
964
-            ),
965
-            EE_Registry::instance()->CFG->core->reg_page_url()
966
-        );
967
-    }
968
-
969
-
970
-    /**
971
-     * Simply generates and returns the appropriate admin_url link to edit this registration
972
-     *
973
-     * @return string
974
-     * @throws EE_Error
975
-     */
976
-    public function get_admin_edit_url()
977
-    {
978
-        return EEH_URL::add_query_args_and_nonce(
979
-            array(
980
-                'page'    => 'espresso_registrations',
981
-                'action'  => 'view_registration',
982
-                '_REG_ID' => $this->ID(),
983
-            ),
984
-            admin_url('admin.php')
985
-        );
986
-    }
987
-
988
-
989
-    /**
990
-     *    is_primary_registrant?
991
-     */
992
-    public function is_primary_registrant()
993
-    {
994
-        return $this->get('REG_count') === 1 ? true : false;
995
-    }
996
-
997
-
998
-    /**
999
-     * This returns the primary registration object for this registration group (which may be this object).
1000
-     *
1001
-     * @return EE_Registration
1002
-     * @throws EE_Error
1003
-     */
1004
-    public function get_primary_registration()
1005
-    {
1006
-        if ($this->is_primary_registrant()) {
1007
-            return $this;
1008
-        }
1009
-
1010
-        // k reg_count !== 1 so let's get the EE_Registration object matching this txn_id and reg_count == 1
1011
-        /** @var EE_Registration $primary_registrant */
1012
-        $primary_registrant = EEM_Registration::instance()->get_one(
1013
-            array(
1014
-                array(
1015
-                    'TXN_ID'    => $this->transaction_ID(),
1016
-                    'REG_count' => 1,
1017
-                ),
1018
-            )
1019
-        );
1020
-        return $primary_registrant;
1021
-    }
1022
-
1023
-
1024
-    /**
1025
-     *        get  Attendee Number
1026
-     *
1027
-     * @access        public
1028
-     */
1029
-    public function count()
1030
-    {
1031
-        return $this->get('REG_count');
1032
-    }
1033
-
1034
-
1035
-    /**
1036
-     *        get Group Size
1037
-     */
1038
-    public function group_size()
1039
-    {
1040
-        return $this->get('REG_group_size');
1041
-    }
1042
-
1043
-
1044
-    /**
1045
-     *        get Registration Date
1046
-     */
1047
-    public function date()
1048
-    {
1049
-        return $this->get('REG_date');
1050
-    }
1051
-
1052
-
1053
-    /**
1054
-     * gets a pretty date
1055
-     *
1056
-     * @param string $date_format
1057
-     * @param string $time_format
1058
-     * @return string
1059
-     * @throws EE_Error
1060
-     */
1061
-    public function pretty_date($date_format = null, $time_format = null)
1062
-    {
1063
-        return $this->get_datetime('REG_date', $date_format, $time_format);
1064
-    }
1065
-
1066
-
1067
-    /**
1068
-     * final_price
1069
-     * the registration's share of the transaction total, so that the
1070
-     * sum of all the transaction's REG_final_prices equal the transaction's total
1071
-     *
1072
-     * @return float
1073
-     * @throws EE_Error
1074
-     */
1075
-    public function final_price()
1076
-    {
1077
-        return $this->get('REG_final_price');
1078
-    }
1079
-
1080
-
1081
-    /**
1082
-     * pretty_final_price
1083
-     *  final price as formatted string, with correct decimal places and currency symbol
1084
-     *
1085
-     * @return string
1086
-     * @throws EE_Error
1087
-     */
1088
-    public function pretty_final_price()
1089
-    {
1090
-        return $this->get_pretty('REG_final_price');
1091
-    }
1092
-
1093
-
1094
-    /**
1095
-     * get paid (yeah)
1096
-     *
1097
-     * @return float
1098
-     * @throws EE_Error
1099
-     */
1100
-    public function paid()
1101
-    {
1102
-        return $this->get('REG_paid');
1103
-    }
1104
-
1105
-
1106
-    /**
1107
-     * pretty_paid
1108
-     *
1109
-     * @return float
1110
-     * @throws EE_Error
1111
-     */
1112
-    public function pretty_paid()
1113
-    {
1114
-        return $this->get_pretty('REG_paid');
1115
-    }
1116
-
1117
-
1118
-    /**
1119
-     * owes_monies_and_can_pay
1120
-     * whether or not this registration has monies owing and it's' status allows payment
1121
-     *
1122
-     * @param array $requires_payment
1123
-     * @return bool
1124
-     * @throws EE_Error
1125
-     */
1126
-    public function owes_monies_and_can_pay($requires_payment = array())
1127
-    {
1128
-        // these reg statuses require payment (if event is not free)
1129
-        $requires_payment = ! empty($requires_payment)
1130
-            ? $requires_payment
1131
-            : EEM_Registration::reg_statuses_that_allow_payment();
1132
-        if (in_array($this->status_ID(), $requires_payment) &&
1133
-            $this->final_price() != 0 &&
1134
-            $this->final_price() != $this->paid()
1135
-        ) {
1136
-            return true;
1137
-        } else {
1138
-            return false;
1139
-        }
1140
-    }
1141
-
1142
-
1143
-    /**
1144
-     * Prints out the return value of $this->pretty_status()
1145
-     *
1146
-     * @param bool $show_icons
1147
-     * @return void
1148
-     * @throws EE_Error
1149
-     */
1150
-    public function e_pretty_status($show_icons = false)
1151
-    {
1152
-        echo $this->pretty_status($show_icons);
1153
-    }
1154
-
1155
-
1156
-    /**
1157
-     * Returns a nice version of the status for displaying to customers
1158
-     *
1159
-     * @param bool $show_icons
1160
-     * @return string
1161
-     * @throws EE_Error
1162
-     */
1163
-    public function pretty_status($show_icons = false)
1164
-    {
1165
-        $status = EEM_Status::instance()->localized_status(
1166
-            array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
1167
-            false,
1168
-            'sentence'
1169
-        );
1170
-        $icon = '';
1171
-        switch ($this->status_ID()) {
1172
-            case EEM_Registration::status_id_approved:
1173
-                $icon = $show_icons
1174
-                    ? '<span class="dashicons dashicons-star-filled ee-icon-size-16 green-text"></span>'
1175
-                    : '';
1176
-                break;
1177
-            case EEM_Registration::status_id_pending_payment:
1178
-                $icon = $show_icons
1179
-                    ? '<span class="dashicons dashicons-star-half ee-icon-size-16 orange-text"></span>'
1180
-                    : '';
1181
-                break;
1182
-            case EEM_Registration::status_id_not_approved:
1183
-                $icon = $show_icons
1184
-                    ? '<span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>'
1185
-                    : '';
1186
-                break;
1187
-            case EEM_Registration::status_id_cancelled:
1188
-                $icon = $show_icons
1189
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
1190
-                    : '';
1191
-                break;
1192
-            case EEM_Registration::status_id_incomplete:
1193
-                $icon = $show_icons
1194
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-orange-text"></span>'
1195
-                    : '';
1196
-                break;
1197
-            case EEM_Registration::status_id_declined:
1198
-                $icon = $show_icons
1199
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
1200
-                    : '';
1201
-                break;
1202
-            case EEM_Registration::status_id_wait_list:
1203
-                $icon = $show_icons
1204
-                    ? '<span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>'
1205
-                    : '';
1206
-                break;
1207
-        }
1208
-        return $icon . $status[ $this->status_ID() ];
1209
-    }
1210
-
1211
-
1212
-    /**
1213
-     *        get Attendee Is Going
1214
-     */
1215
-    public function att_is_going()
1216
-    {
1217
-        return $this->get('REG_att_is_going');
1218
-    }
1219
-
1220
-
1221
-    /**
1222
-     * Gets related answers
1223
-     *
1224
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1225
-     * @return EE_Answer[]
1226
-     * @throws EE_Error
1227
-     */
1228
-    public function answers($query_params = null)
1229
-    {
1230
-        return $this->get_many_related('Answer', $query_params);
1231
-    }
1232
-
1233
-
1234
-    /**
1235
-     * Gets the registration's answer value to the specified question
1236
-     * (either the question's ID or a question object)
1237
-     *
1238
-     * @param EE_Question|int $question
1239
-     * @param bool            $pretty_value
1240
-     * @return array|string if pretty_value= true, the result will always be a string
1241
-     * (because the answer might be an array of answer values, so passing pretty_value=true
1242
-     * will convert it into some kind of string)
1243
-     * @throws EE_Error
1244
-     */
1245
-    public function answer_value_to_question($question, $pretty_value = true)
1246
-    {
1247
-        $question_id = EEM_Question::instance()->ensure_is_ID($question);
1248
-        return EEM_Answer::instance()->get_answer_value_to_question($this, $question_id, $pretty_value);
1249
-    }
1250
-
1251
-
1252
-    /**
1253
-     * question_groups
1254
-     * returns an array of EE_Question_Group objects for this registration
1255
-     *
1256
-     * @return EE_Question_Group[]
1257
-     * @throws EE_Error
1258
-     * @throws InvalidArgumentException
1259
-     * @throws InvalidDataTypeException
1260
-     * @throws InvalidInterfaceException
1261
-     * @throws ReflectionException
1262
-     */
1263
-    public function question_groups()
1264
-    {
1265
-        return EEM_Event::instance()->get_question_groups_for_event($this->event_ID(), $this);
1266
-    }
1267
-
1268
-
1269
-    /**
1270
-     * count_question_groups
1271
-     * returns a count of the number of EE_Question_Group objects for this registration
1272
-     *
1273
-     * @return int
1274
-     * @throws EE_Error
1275
-     * @throws EntityNotFoundException
1276
-     * @throws InvalidArgumentException
1277
-     * @throws InvalidDataTypeException
1278
-     * @throws InvalidInterfaceException
1279
-     * @throws ReflectionException
1280
-     */
1281
-    public function count_question_groups()
1282
-    {
1283
-        return EEM_Event::instance()->count_related(
1284
-            $this->event_ID(),
1285
-            'Question_Group',
1286
-            [
1287
-                [
1288
-                    'Event_Question_Group.'
1289
-                    . EEM_Event_Question_Group::instance()->fieldNameForContext($this->is_primary_registrant()) => true,
1290
-                ]
1291
-            ]
1292
-        );
1293
-    }
1294
-
1295
-
1296
-    /**
1297
-     * Returns the registration date in the 'standard' string format
1298
-     * (function may be improved in the future to allow for different formats and timezones)
1299
-     *
1300
-     * @return string
1301
-     * @throws EE_Error
1302
-     */
1303
-    public function reg_date()
1304
-    {
1305
-        return $this->get_datetime('REG_date');
1306
-    }
1307
-
1308
-
1309
-    /**
1310
-     * Gets the datetime-ticket for this registration (ie, it can be used to isolate
1311
-     * the ticket this registration purchased, or the datetime they have registered
1312
-     * to attend)
1313
-     *
1314
-     * @return EE_Datetime_Ticket
1315
-     * @throws EE_Error
1316
-     */
1317
-    public function datetime_ticket()
1318
-    {
1319
-        return $this->get_first_related('Datetime_Ticket');
1320
-    }
1321
-
1322
-
1323
-    /**
1324
-     * Sets the registration's datetime_ticket.
1325
-     *
1326
-     * @param EE_Datetime_Ticket $datetime_ticket
1327
-     * @return EE_Datetime_Ticket
1328
-     * @throws EE_Error
1329
-     */
1330
-    public function set_datetime_ticket($datetime_ticket)
1331
-    {
1332
-        return $this->_add_relation_to($datetime_ticket, 'Datetime_Ticket');
1333
-    }
1334
-
1335
-    /**
1336
-     * Gets deleted
1337
-     *
1338
-     * @return bool
1339
-     * @throws EE_Error
1340
-     */
1341
-    public function deleted()
1342
-    {
1343
-        return $this->get('REG_deleted');
1344
-    }
1345
-
1346
-    /**
1347
-     * Sets deleted
1348
-     *
1349
-     * @param boolean $deleted
1350
-     * @return bool
1351
-     * @throws EE_Error
1352
-     * @throws RuntimeException
1353
-     */
1354
-    public function set_deleted($deleted)
1355
-    {
1356
-        if ($deleted) {
1357
-            $this->delete();
1358
-        } else {
1359
-            $this->restore();
1360
-        }
1361
-    }
1362
-
1363
-
1364
-    /**
1365
-     * Get the status object of this object
1366
-     *
1367
-     * @return EE_Status
1368
-     * @throws EE_Error
1369
-     */
1370
-    public function status_obj()
1371
-    {
1372
-        return $this->get_first_related('Status');
1373
-    }
1374
-
1375
-
1376
-    /**
1377
-     * Returns the number of times this registration has checked into any of the datetimes
1378
-     * its available for
1379
-     *
1380
-     * @return int
1381
-     * @throws EE_Error
1382
-     */
1383
-    public function count_checkins()
1384
-    {
1385
-        return $this->get_model()->count_related($this, 'Checkin');
1386
-    }
1387
-
1388
-
1389
-    /**
1390
-     * Returns the number of current Check-ins this registration is checked into for any of the datetimes the
1391
-     * registration is for.  Note, this is ONLY checked in (does not include checkedout)
1392
-     *
1393
-     * @return int
1394
-     * @throws EE_Error
1395
-     */
1396
-    public function count_checkins_not_checkedout()
1397
-    {
1398
-        return $this->get_model()->count_related($this, 'Checkin', array(array('CHK_in' => 1)));
1399
-    }
1400
-
1401
-
1402
-    /**
1403
-     * The purpose of this method is simply to check whether this registration can checkin to the given datetime.
1404
-     *
1405
-     * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1406
-     * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1407
-     *                                          consider registration status as well as datetime access.
1408
-     * @return bool
1409
-     * @throws EE_Error
1410
-     */
1411
-    public function can_checkin($DTT_OR_ID, $check_approved = true)
1412
-    {
1413
-        $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1414
-
1415
-        // first check registration status
1416
-        if (($check_approved && ! $this->is_approved()) || ! $DTT_ID) {
1417
-            return false;
1418
-        }
1419
-        // is there a datetime ticket that matches this dtt_ID?
1420
-        if (! (EEM_Datetime_Ticket::instance()->exists(
1421
-            array(
1422
-                array(
1423
-                    'TKT_ID' => $this->get('TKT_ID'),
1424
-                    'DTT_ID' => $DTT_ID,
1425
-                ),
1426
-            )
1427
-        ))
1428
-        ) {
1429
-            return false;
1430
-        }
1431
-
1432
-        // final check is against TKT_uses
1433
-        return $this->verify_can_checkin_against_TKT_uses($DTT_ID);
1434
-    }
1435
-
1436
-
1437
-    /**
1438
-     * This method verifies whether the user can checkin for the given datetime considering the max uses value set on
1439
-     * the ticket. To do this,  a query is done to get the count of the datetime records already checked into.  If the
1440
-     * datetime given does not have a check-in record and checking in for that datetime will exceed the allowed uses,
1441
-     * then return false.  Otherwise return true.
1442
-     *
1443
-     * @param int | EE_Datetime $DTT_OR_ID The datetime the registration is being checked against
1444
-     * @return bool true means can checkin.  false means cannot checkin.
1445
-     * @throws EE_Error
1446
-     */
1447
-    public function verify_can_checkin_against_TKT_uses($DTT_OR_ID)
1448
-    {
1449
-        $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1450
-
1451
-        if (! $DTT_ID) {
1452
-            return false;
1453
-        }
1454
-
1455
-        $max_uses = $this->ticket() instanceof EE_Ticket ? $this->ticket()->uses() : EE_INF;
1456
-
1457
-        // if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1458
-        // check-in or not.
1459
-        if (! $max_uses || $max_uses === EE_INF) {
1460
-            return true;
1461
-        }
1462
-
1463
-        // does this datetime have a checkin record?  If so, then the dtt count has already been verified so we can just
1464
-        // go ahead and toggle.
1465
-        if (EEM_Checkin::instance()->exists(array(array('REG_ID' => $this->ID(), 'DTT_ID' => $DTT_ID)))) {
1466
-            return true;
1467
-        }
1468
-
1469
-        // made it here so the last check is whether the number of checkins per unique datetime on this registration
1470
-        // disallows further check-ins.
1471
-        $count_unique_dtt_checkins = EEM_Checkin::instance()->count(
1472
-            array(
1473
-                array(
1474
-                    'REG_ID' => $this->ID(),
1475
-                    'CHK_in' => true,
1476
-                ),
1477
-            ),
1478
-            'DTT_ID',
1479
-            true
1480
-        );
1481
-        // checkins have already reached their max number of uses
1482
-        // so registrant can NOT checkin
1483
-        if ($count_unique_dtt_checkins >= $max_uses) {
1484
-            EE_Error::add_error(
1485
-                esc_html__(
1486
-                    'Check-in denied because number of datetime uses for the ticket has been reached or exceeded.',
1487
-                    'event_espresso'
1488
-                ),
1489
-                __FILE__,
1490
-                __FUNCTION__,
1491
-                __LINE__
1492
-            );
1493
-            return false;
1494
-        }
1495
-        return true;
1496
-    }
1497
-
1498
-
1499
-    /**
1500
-     * toggle Check-in status for this registration
1501
-     * Check-ins are toggled in the following order:
1502
-     * never checked in -> checked in
1503
-     * checked in -> checked out
1504
-     * checked out -> checked in
1505
-     *
1506
-     * @param  int $DTT_ID  include specific datetime to toggle Check-in for.
1507
-     *                      If not included or null, then it is assumed latest datetime is being toggled.
1508
-     * @param bool $verify  If true then can_checkin() is used to verify whether the person
1509
-     *                      can be checked in or not.  Otherwise this forces change in checkin status.
1510
-     * @return bool|int     the chk_in status toggled to OR false if nothing got changed.
1511
-     * @throws EE_Error
1512
-     */
1513
-    public function toggle_checkin_status($DTT_ID = null, $verify = false)
1514
-    {
1515
-        if (empty($DTT_ID)) {
1516
-            $datetime = $this->get_latest_related_datetime();
1517
-            $DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1518
-            // verify the registration can checkin for the given DTT_ID
1519
-        } elseif (! $this->can_checkin($DTT_ID, $verify)) {
1520
-            EE_Error::add_error(
1521
-                sprintf(
1522
-                    esc_html__(
1523
-                        'The given registration (ID:%1$d) can not be checked in to the given DTT_ID (%2$d), because the registration does not have access',
1524
-                        'event_espresso'
1525
-                    ),
1526
-                    $this->ID(),
1527
-                    $DTT_ID
1528
-                ),
1529
-                __FILE__,
1530
-                __FUNCTION__,
1531
-                __LINE__
1532
-            );
1533
-            return false;
1534
-        }
1535
-        $status_paths = array(
1536
-            EE_Checkin::status_checked_never => EE_Checkin::status_checked_in,
1537
-            EE_Checkin::status_checked_in    => EE_Checkin::status_checked_out,
1538
-            EE_Checkin::status_checked_out   => EE_Checkin::status_checked_in,
1539
-        );
1540
-        // start by getting the current status so we know what status we'll be changing to.
1541
-        $cur_status = $this->check_in_status_for_datetime($DTT_ID, null);
1542
-        $status_to = $status_paths[ $cur_status ];
1543
-        // database only records true for checked IN or false for checked OUT
1544
-        // no record ( null ) means checked in NEVER, but we obviously don't save that
1545
-        $new_status = $status_to === EE_Checkin::status_checked_in ? true : false;
1546
-        // add relation - note Check-ins are always creating new rows
1547
-        // because we are keeping track of Check-ins over time.
1548
-        // Eventually we'll probably want to show a list table
1549
-        // for the individual Check-ins so that they can be managed.
1550
-        $checkin = EE_Checkin::new_instance(
1551
-            array(
1552
-                'REG_ID' => $this->ID(),
1553
-                'DTT_ID' => $DTT_ID,
1554
-                'CHK_in' => $new_status,
1555
-            )
1556
-        );
1557
-        // if the record could not be saved then return false
1558
-        if ($checkin->save() === 0) {
1559
-            if (WP_DEBUG) {
1560
-                global $wpdb;
1561
-                $error = sprintf(
1562
-                    esc_html__(
1563
-                        'Registration check in update failed because of the following database error: %1$s%2$s',
1564
-                        'event_espresso'
1565
-                    ),
1566
-                    '<br />',
1567
-                    $wpdb->last_error
1568
-                );
1569
-            } else {
1570
-                $error = esc_html__(
1571
-                    'Registration check in update failed because of an unknown database error',
1572
-                    'event_espresso'
1573
-                );
1574
-            }
1575
-            EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
1576
-            return false;
1577
-        }
1578
-        return $status_to;
1579
-    }
1580
-
1581
-
1582
-    /**
1583
-     * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1584
-     * "Latest" is defined by the `DTT_EVT_start` column.
1585
-     *
1586
-     * @return EE_Datetime|null
1587
-     * @throws EE_Error
1588
-     */
1589
-    public function get_latest_related_datetime()
1590
-    {
1591
-        return EEM_Datetime::instance()->get_one(
1592
-            array(
1593
-                array(
1594
-                    'Ticket.Registration.REG_ID' => $this->ID(),
1595
-                ),
1596
-                'order_by' => array('DTT_EVT_start' => 'DESC'),
1597
-            )
1598
-        );
1599
-    }
1600
-
1601
-
1602
-    /**
1603
-     * Returns the earliest datetime related to this registration (via the ticket attached to the registration).
1604
-     * "Earliest" is defined by the `DTT_EVT_start` column.
1605
-     *
1606
-     * @throws EE_Error
1607
-     */
1608
-    public function get_earliest_related_datetime()
1609
-    {
1610
-        return EEM_Datetime::instance()->get_one(
1611
-            array(
1612
-                array(
1613
-                    'Ticket.Registration.REG_ID' => $this->ID(),
1614
-                ),
1615
-                'order_by' => array('DTT_EVT_start' => 'ASC'),
1616
-            )
1617
-        );
1618
-    }
1619
-
1620
-
1621
-    /**
1622
-     * This method simply returns the check-in status for this registration and the given datetime.
1623
-     * If neither the datetime nor the checkin values are provided as arguments,
1624
-     * then this will return the LATEST check-in status for the registration across all datetimes it belongs to.
1625
-     *
1626
-     * @param  int       $DTT_ID  The ID of the datetime we're checking against
1627
-     *                            (if empty we'll get the primary datetime for
1628
-     *                            this registration (via event) and use it's ID);
1629
-     * @param EE_Checkin $checkin If present, we use the given checkin object rather than the dtt_id.
1630
-     *
1631
-     * @return int                Integer representing Check-in status.
1632
-     * @throws EE_Error
1633
-     */
1634
-    public function check_in_status_for_datetime($DTT_ID = 0, $checkin = null)
1635
-    {
1636
-        $checkin_query_params = array(
1637
-            'order_by' => array('CHK_timestamp' => 'DESC'),
1638
-        );
1639
-
1640
-        if ($DTT_ID > 0) {
1641
-            $checkin_query_params[0] = array('DTT_ID' => $DTT_ID);
1642
-        }
1643
-
1644
-        // get checkin object (if exists)
1645
-        $checkin = $checkin instanceof EE_Checkin
1646
-            ? $checkin
1647
-            : $this->get_first_related('Checkin', $checkin_query_params);
1648
-        if ($checkin instanceof EE_Checkin) {
1649
-            if ($checkin->get('CHK_in')) {
1650
-                return EE_Checkin::status_checked_in; // checked in
1651
-            }
1652
-            return EE_Checkin::status_checked_out; // had checked in but is now checked out.
1653
-        }
1654
-        return EE_Checkin::status_checked_never; // never been checked in
1655
-    }
1656
-
1657
-
1658
-    /**
1659
-     * This method returns a localized message for the toggled Check-in message.
1660
-     *
1661
-     * @param  int $DTT_ID include specific datetime to get the correct Check-in message.  If not included or null,
1662
-     *                     then it is assumed Check-in for primary datetime was toggled.
1663
-     * @param bool $error  This just flags that you want an error message returned. This is put in so that the error
1664
-     *                     message can be customized with the attendee name.
1665
-     * @return string internationalized message
1666
-     * @throws EE_Error
1667
-     */
1668
-    public function get_checkin_msg($DTT_ID, $error = false)
1669
-    {
1670
-        // let's get the attendee first so we can include the name of the attendee
1671
-        $attendee = $this->get_first_related('Attendee');
1672
-        if ($attendee instanceof EE_Attendee) {
1673
-            if ($error) {
1674
-                return sprintf(__("%s's check-in status was not changed.", "event_espresso"), $attendee->full_name());
1675
-            }
1676
-            $cur_status = $this->check_in_status_for_datetime($DTT_ID);
1677
-            // what is the status message going to be?
1678
-            switch ($cur_status) {
1679
-                case EE_Checkin::status_checked_never:
1680
-                    return sprintf(
1681
-                        __("%s has been removed from Check-in records", "event_espresso"),
1682
-                        $attendee->full_name()
1683
-                    );
1684
-                    break;
1685
-                case EE_Checkin::status_checked_in:
1686
-                    return sprintf(__('%s has been checked in', 'event_espresso'), $attendee->full_name());
1687
-                    break;
1688
-                case EE_Checkin::status_checked_out:
1689
-                    return sprintf(__('%s has been checked out', 'event_espresso'), $attendee->full_name());
1690
-                    break;
1691
-            }
1692
-        }
1693
-        return esc_html__("The check-in status could not be determined.", "event_espresso");
1694
-    }
1695
-
1696
-
1697
-    /**
1698
-     * Returns the related EE_Transaction to this registration
1699
-     *
1700
-     * @return EE_Transaction
1701
-     * @throws EE_Error
1702
-     * @throws EntityNotFoundException
1703
-     */
1704
-    public function transaction()
1705
-    {
1706
-        $transaction = $this->get_first_related('Transaction');
1707
-        if (! $transaction instanceof \EE_Transaction) {
1708
-            throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
1709
-        }
1710
-        return $transaction;
1711
-    }
1712
-
1713
-
1714
-    /**
1715
-     *        get Registration Code
1716
-     */
1717
-    public function reg_code()
1718
-    {
1719
-        return $this->get('REG_code');
1720
-    }
1721
-
1722
-
1723
-    /**
1724
-     *        get Transaction ID
1725
-     */
1726
-    public function transaction_ID()
1727
-    {
1728
-        return $this->get('TXN_ID');
1729
-    }
1730
-
1731
-
1732
-    /**
1733
-     * @return int
1734
-     * @throws EE_Error
1735
-     */
1736
-    public function ticket_ID()
1737
-    {
1738
-        return $this->get('TKT_ID');
1739
-    }
1740
-
1741
-
1742
-    /**
1743
-     *        Set Registration Code
1744
-     *
1745
-     * @access    public
1746
-     * @param    string  $REG_code Registration Code
1747
-     * @param    boolean $use_default
1748
-     * @throws EE_Error
1749
-     */
1750
-    public function set_reg_code($REG_code, $use_default = false)
1751
-    {
1752
-        if (empty($REG_code)) {
1753
-            EE_Error::add_error(
1754
-                esc_html__('REG_code can not be empty.', 'event_espresso'),
1755
-                __FILE__,
1756
-                __FUNCTION__,
1757
-                __LINE__
1758
-            );
1759
-            return;
1760
-        }
1761
-        if (! $this->reg_code()) {
1762
-            parent::set('REG_code', $REG_code, $use_default);
1763
-        } else {
1764
-            EE_Error::doing_it_wrong(
1765
-                __CLASS__ . '::' . __FUNCTION__,
1766
-                esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
1767
-                '4.6.0'
1768
-            );
1769
-        }
1770
-    }
1771
-
1772
-
1773
-    /**
1774
-     * Returns all other registrations in the same group as this registrant who have the same ticket option.
1775
-     * Note, if you want to just get all registrations in the same transaction (group), use:
1776
-     *    $registration->transaction()->registrations();
1777
-     *
1778
-     * @since 4.5.0
1779
-     * @return EE_Registration[] or empty array if this isn't a group registration.
1780
-     * @throws EE_Error
1781
-     */
1782
-    public function get_all_other_registrations_in_group()
1783
-    {
1784
-        if ($this->group_size() < 2) {
1785
-            return array();
1786
-        }
1787
-
1788
-        $query[0] = array(
1789
-            'TXN_ID' => $this->transaction_ID(),
1790
-            'REG_ID' => array('!=', $this->ID()),
1791
-            'TKT_ID' => $this->ticket_ID(),
1792
-        );
1793
-        /** @var EE_Registration[] $registrations */
1794
-        $registrations = $this->get_model()->get_all($query);
1795
-        return $registrations;
1796
-    }
1797
-
1798
-    /**
1799
-     * Return the link to the admin details for the object.
1800
-     *
1801
-     * @return string
1802
-     * @throws EE_Error
1803
-     */
1804
-    public function get_admin_details_link()
1805
-    {
1806
-        EE_Registry::instance()->load_helper('URL');
1807
-        return EEH_URL::add_query_args_and_nonce(
1808
-            array(
1809
-                'page'    => 'espresso_registrations',
1810
-                'action'  => 'view_registration',
1811
-                '_REG_ID' => $this->ID(),
1812
-            ),
1813
-            admin_url('admin.php')
1814
-        );
1815
-    }
1816
-
1817
-    /**
1818
-     * Returns the link to the editor for the object.  Sometimes this is the same as the details.
1819
-     *
1820
-     * @return string
1821
-     * @throws EE_Error
1822
-     */
1823
-    public function get_admin_edit_link()
1824
-    {
1825
-        return $this->get_admin_details_link();
1826
-    }
1827
-
1828
-    /**
1829
-     * Returns the link to a settings page for the object.
1830
-     *
1831
-     * @return string
1832
-     * @throws EE_Error
1833
-     */
1834
-    public function get_admin_settings_link()
1835
-    {
1836
-        return $this->get_admin_details_link();
1837
-    }
1838
-
1839
-    /**
1840
-     * Returns the link to the "overview" for the object (typically the "list table" view).
1841
-     *
1842
-     * @return string
1843
-     */
1844
-    public function get_admin_overview_link()
1845
-    {
1846
-        EE_Registry::instance()->load_helper('URL');
1847
-        return EEH_URL::add_query_args_and_nonce(
1848
-            array(
1849
-                'page' => 'espresso_registrations',
1850
-            ),
1851
-            admin_url('admin.php')
1852
-        );
1853
-    }
1854
-
1855
-
1856
-    /**
1857
-     * @param array $query_params
1858
-     *
1859
-     * @return \EE_Registration[]
1860
-     * @throws EE_Error
1861
-     */
1862
-    public function payments($query_params = array())
1863
-    {
1864
-        return $this->get_many_related('Payment', $query_params);
1865
-    }
1866
-
1867
-
1868
-    /**
1869
-     * @param array $query_params
1870
-     *
1871
-     * @return \EE_Registration_Payment[]
1872
-     * @throws EE_Error
1873
-     */
1874
-    public function registration_payments($query_params = array())
1875
-    {
1876
-        return $this->get_many_related('Registration_Payment', $query_params);
1877
-    }
1878
-
1879
-
1880
-    /**
1881
-     * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
1882
-     * Note: if there are no payments on the registration there will be no payment method returned.
1883
-     *
1884
-     * @return EE_Payment_Method|null
1885
-     */
1886
-    public function payment_method()
1887
-    {
1888
-        return EEM_Payment_Method::instance()->get_last_used_for_registration($this);
1889
-    }
1890
-
1891
-
1892
-    /**
1893
-     * @return \EE_Line_Item
1894
-     * @throws EntityNotFoundException
1895
-     * @throws EE_Error
1896
-     */
1897
-    public function ticket_line_item()
1898
-    {
1899
-        $ticket = $this->ticket();
1900
-        $transaction = $this->transaction();
1901
-        $line_item = null;
1902
-        $ticket_line_items = \EEH_Line_Item::get_line_items_by_object_type_and_IDs(
1903
-            $transaction->total_line_item(),
1904
-            'Ticket',
1905
-            array($ticket->ID())
1906
-        );
1907
-        foreach ($ticket_line_items as $ticket_line_item) {
1908
-            if ($ticket_line_item instanceof \EE_Line_Item
1909
-                && $ticket_line_item->OBJ_type() === 'Ticket'
1910
-                && $ticket_line_item->OBJ_ID() === $ticket->ID()
1911
-            ) {
1912
-                $line_item = $ticket_line_item;
1913
-                break;
1914
-            }
1915
-        }
1916
-        if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
1917
-            throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
1918
-        }
1919
-        return $line_item;
1920
-    }
1921
-
1922
-
1923
-    /**
1924
-     * Soft Deletes this model object.
1925
-     *
1926
-     * @return boolean | int
1927
-     * @throws RuntimeException
1928
-     * @throws EE_Error
1929
-     */
1930
-    public function delete()
1931
-    {
1932
-        if ($this->update_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY, $this->status_ID()) === true) {
1933
-            $this->set_status(EEM_Registration::status_id_cancelled);
1934
-        }
1935
-        return parent::delete();
1936
-    }
1937
-
1938
-
1939
-    /**
1940
-     * Restores whatever the previous status was on a registration before it was trashed (if possible)
1941
-     *
1942
-     * @throws EE_Error
1943
-     * @throws RuntimeException
1944
-     */
1945
-    public function restore()
1946
-    {
1947
-        $previous_status = $this->get_extra_meta(
1948
-            EE_Registration::PRE_TRASH_REG_STATUS_KEY,
1949
-            true,
1950
-            EEM_Registration::status_id_cancelled
1951
-        );
1952
-        if ($previous_status) {
1953
-            $this->delete_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY);
1954
-            $this->set_status($previous_status);
1955
-        }
1956
-        return parent::restore();
1957
-    }
1958
-
1959
-
1960
-    /**
1961
-     * possibly toggle Registration status based on comparison of REG_paid vs REG_final_price
1962
-     *
1963
-     * @param  boolean $trigger_set_status_logic EE_Registration::set_status() can trigger additional logic
1964
-     *                                           depending on whether the reg status changes to or from "Approved"
1965
-     * @return boolean whether the Registration status was updated
1966
-     * @throws EE_Error
1967
-     * @throws RuntimeException
1968
-     */
1969
-    public function updateStatusBasedOnTotalPaid($trigger_set_status_logic = true)
1970
-    {
1971
-        $paid = $this->paid();
1972
-        $price = $this->final_price();
1973
-        switch (true) {
1974
-            // overpaid or paid
1975
-            case EEH_Money::compare_floats($paid, $price, '>'):
1976
-            case EEH_Money::compare_floats($paid, $price):
1977
-                $new_status = EEM_Registration::status_id_approved;
1978
-                break;
1979
-            //  underpaid
1980
-            case EEH_Money::compare_floats($paid, $price, '<'):
1981
-                $new_status = EEM_Registration::status_id_pending_payment;
1982
-                break;
1983
-            // uhhh Houston...
1984
-            default:
1985
-                throw new RuntimeException(
1986
-                    esc_html__('The total paid calculation for this registration is inaccurate.', 'event_espresso')
1987
-                );
1988
-        }
1989
-        if ($new_status !== $this->status_ID()) {
1990
-            if ($trigger_set_status_logic) {
1991
-                return $this->set_status($new_status);
1992
-            }
1993
-            parent::set('STS_ID', $new_status);
1994
-            return true;
1995
-        }
1996
-        return false;
1997
-    }
1998
-
1999
-
2000
-    /*************************** DEPRECATED ***************************/
2001
-
2002
-
2003
-    /**
2004
-     * @deprecated
2005
-     * @since     4.7.0
2006
-     * @access    public
2007
-     */
2008
-    public function price_paid()
2009
-    {
2010
-        EE_Error::doing_it_wrong(
2011
-            'EE_Registration::price_paid()',
2012
-            esc_html__(
2013
-                'This method is deprecated, please use EE_Registration::final_price() instead.',
2014
-                'event_espresso'
2015
-            ),
2016
-            '4.7.0'
2017
-        );
2018
-        return $this->final_price();
2019
-    }
2020
-
2021
-
2022
-    /**
2023
-     * @deprecated
2024
-     * @since     4.7.0
2025
-     * @access    public
2026
-     * @param    float $REG_final_price
2027
-     * @throws EE_Error
2028
-     * @throws RuntimeException
2029
-     */
2030
-    public function set_price_paid($REG_final_price = 0.00)
2031
-    {
2032
-        EE_Error::doing_it_wrong(
2033
-            'EE_Registration::set_price_paid()',
2034
-            esc_html__(
2035
-                'This method is deprecated, please use EE_Registration::set_final_price() instead.',
2036
-                'event_espresso'
2037
-            ),
2038
-            '4.7.0'
2039
-        );
2040
-        $this->set_final_price($REG_final_price);
2041
-    }
2042
-
2043
-
2044
-    /**
2045
-     * @deprecated
2046
-     * @since 4.7.0
2047
-     * @return string
2048
-     * @throws EE_Error
2049
-     */
2050
-    public function pretty_price_paid()
2051
-    {
2052
-        EE_Error::doing_it_wrong(
2053
-            'EE_Registration::pretty_price_paid()',
2054
-            esc_html__(
2055
-                'This method is deprecated, please use EE_Registration::pretty_final_price() instead.',
2056
-                'event_espresso'
2057
-            ),
2058
-            '4.7.0'
2059
-        );
2060
-        return $this->pretty_final_price();
2061
-    }
2062
-
2063
-
2064
-    /**
2065
-     * Gets the primary datetime related to this registration via the related Event to this registration
2066
-     *
2067
-     * @deprecated 4.9.17
2068
-     * @return EE_Datetime
2069
-     * @throws EE_Error
2070
-     * @throws EntityNotFoundException
2071
-     */
2072
-    public function get_related_primary_datetime()
2073
-    {
2074
-        EE_Error::doing_it_wrong(
2075
-            __METHOD__,
2076
-            esc_html__(
2077
-                'Use EE_Registration::get_latest_related_datetime() or EE_Registration::get_earliest_related_datetime()',
2078
-                'event_espresso'
2079
-            ),
2080
-            '4.9.17',
2081
-            '5.0.0'
2082
-        );
2083
-        return $this->event()->primary_datetime();
2084
-    }
20
+	/**
21
+	 * Used to reference when a registration has never been checked in.
22
+	 *
23
+	 * @deprecated use \EE_Checkin::status_checked_never instead
24
+	 * @type int
25
+	 */
26
+	const checkin_status_never = 2;
27
+
28
+	/**
29
+	 * Used to reference when a registration has been checked in.
30
+	 *
31
+	 * @deprecated use \EE_Checkin::status_checked_in instead
32
+	 * @type int
33
+	 */
34
+	const checkin_status_in = 1;
35
+
36
+
37
+	/**
38
+	 * Used to reference when a registration has been checked out.
39
+	 *
40
+	 * @deprecated use \EE_Checkin::status_checked_out instead
41
+	 * @type int
42
+	 */
43
+	const checkin_status_out = 0;
44
+
45
+
46
+	/**
47
+	 * extra meta key for tracking reg status os trashed registrations
48
+	 *
49
+	 * @type string
50
+	 */
51
+	const PRE_TRASH_REG_STATUS_KEY = 'pre_trash_registration_status';
52
+
53
+
54
+	/**
55
+	 * extra meta key for tracking if registration has reserved ticket
56
+	 *
57
+	 * @type string
58
+	 */
59
+	const HAS_RESERVED_TICKET_KEY = 'has_reserved_ticket';
60
+
61
+
62
+	/**
63
+	 * @param array  $props_n_values          incoming values
64
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
65
+	 *                                        used.)
66
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
67
+	 *                                        date_format and the second value is the time format
68
+	 * @return EE_Registration
69
+	 * @throws EE_Error
70
+	 */
71
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
72
+	{
73
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
74
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
75
+	}
76
+
77
+
78
+	/**
79
+	 * @param array  $props_n_values  incoming values from the database
80
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
81
+	 *                                the website will be used.
82
+	 * @return EE_Registration
83
+	 */
84
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
85
+	{
86
+		return new self($props_n_values, true, $timezone);
87
+	}
88
+
89
+
90
+	/**
91
+	 *        Set Event ID
92
+	 *
93
+	 * @param        int $EVT_ID Event ID
94
+	 * @throws EE_Error
95
+	 * @throws RuntimeException
96
+	 */
97
+	public function set_event($EVT_ID = 0)
98
+	{
99
+		$this->set('EVT_ID', $EVT_ID);
100
+	}
101
+
102
+
103
+	/**
104
+	 * Overrides parent set() method so that all calls to set( 'REG_code', $REG_code ) OR set( 'STS_ID', $STS_ID ) can
105
+	 * be routed to internal methods
106
+	 *
107
+	 * @param string $field_name
108
+	 * @param mixed  $field_value
109
+	 * @param bool   $use_default
110
+	 * @throws EE_Error
111
+	 * @throws EntityNotFoundException
112
+	 * @throws InvalidArgumentException
113
+	 * @throws InvalidDataTypeException
114
+	 * @throws InvalidInterfaceException
115
+	 * @throws ReflectionException
116
+	 * @throws RuntimeException
117
+	 */
118
+	public function set($field_name, $field_value, $use_default = false)
119
+	{
120
+		switch ($field_name) {
121
+			case 'REG_code':
122
+				if (! empty($field_value) && $this->reg_code() === null) {
123
+					$this->set_reg_code($field_value, $use_default);
124
+				}
125
+				break;
126
+			case 'STS_ID':
127
+				$this->set_status($field_value, $use_default);
128
+				break;
129
+			default:
130
+				parent::set($field_name, $field_value, $use_default);
131
+		}
132
+	}
133
+
134
+
135
+	/**
136
+	 * Set Status ID
137
+	 * updates the registration status and ALSO...
138
+	 * calls reserve_registration_space() if the reg status changes TO approved from any other reg status
139
+	 * calls release_registration_space() if the reg status changes FROM approved to any other reg status
140
+	 *
141
+	 * @param string                $new_STS_ID
142
+	 * @param boolean               $use_default
143
+	 * @param ContextInterface|null $context
144
+	 * @return bool
145
+	 * @throws DomainException
146
+	 * @throws EE_Error
147
+	 * @throws EntityNotFoundException
148
+	 * @throws InvalidArgumentException
149
+	 * @throws InvalidDataTypeException
150
+	 * @throws InvalidInterfaceException
151
+	 * @throws ReflectionException
152
+	 * @throws RuntimeException
153
+	 * @throws UnexpectedEntityException
154
+	 */
155
+	public function set_status($new_STS_ID = null, $use_default = false, ContextInterface $context = null)
156
+	{
157
+		// get current REG_Status
158
+		$old_STS_ID = $this->status_ID();
159
+		// if status has changed
160
+		if ($old_STS_ID !== $new_STS_ID // and that status has actually changed
161
+			&& ! empty($old_STS_ID) // and that old status is actually set
162
+			&& ! empty($new_STS_ID) // as well as the new status
163
+			&& $this->ID() // ensure registration is in the db
164
+		) {
165
+			// update internal status first
166
+			parent::set('STS_ID', $new_STS_ID, $use_default);
167
+			// THEN handle other changes that occur when reg status changes
168
+			// TO approved
169
+			if ($new_STS_ID === EEM_Registration::status_id_approved) {
170
+				// reserve a space by incrementing ticket and datetime sold values
171
+				$this->reserveRegistrationSpace();
172
+				do_action('AHEE__EE_Registration__set_status__to_approved', $this, $old_STS_ID, $new_STS_ID, $context);
173
+				// OR FROM  approved
174
+			} elseif ($old_STS_ID === EEM_Registration::status_id_approved) {
175
+				// release a space by decrementing ticket and datetime sold values
176
+				$this->releaseRegistrationSpace();
177
+				do_action(
178
+					'AHEE__EE_Registration__set_status__from_approved',
179
+					$this,
180
+					$old_STS_ID,
181
+					$new_STS_ID,
182
+					$context
183
+				);
184
+			}
185
+			// update status
186
+			parent::set('STS_ID', $new_STS_ID, $use_default);
187
+			$this->updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, $context);
188
+			if ($this->statusChangeUpdatesTransaction($context)) {
189
+				$this->updateTransactionAfterStatusChange();
190
+			}
191
+			do_action('AHEE__EE_Registration__set_status__after_update', $this, $old_STS_ID, $new_STS_ID, $context);
192
+			return true;
193
+		}
194
+		// even though the old value matches the new value, it's still good to
195
+		// allow the parent set method to have a say
196
+		parent::set('STS_ID', $new_STS_ID, $use_default);
197
+		return true;
198
+	}
199
+
200
+
201
+	/**
202
+	 * update REGs and TXN when cancelled or declined registrations involved
203
+	 *
204
+	 * @param string                $new_STS_ID
205
+	 * @param string                $old_STS_ID
206
+	 * @param ContextInterface|null $context
207
+	 * @throws EE_Error
208
+	 * @throws InvalidArgumentException
209
+	 * @throws InvalidDataTypeException
210
+	 * @throws InvalidInterfaceException
211
+	 * @throws ReflectionException
212
+	 * @throws RuntimeException
213
+	 */
214
+	private function updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, ContextInterface $context = null)
215
+	{
216
+		// these reg statuses should not be considered in any calculations involving monies owing
217
+		$closed_reg_statuses = EEM_Registration::closed_reg_statuses();
218
+		// true if registration has been cancelled or declined
219
+		$this->updateIfCanceled(
220
+			$closed_reg_statuses,
221
+			$new_STS_ID,
222
+			$old_STS_ID,
223
+			$context
224
+		);
225
+		$this->updateIfReinstated(
226
+			$closed_reg_statuses,
227
+			$new_STS_ID,
228
+			$old_STS_ID,
229
+			$context
230
+		);
231
+	}
232
+
233
+
234
+	/**
235
+	 * update REGs and TXN when cancelled or declined registrations involved
236
+	 *
237
+	 * @param array                 $closed_reg_statuses
238
+	 * @param string                $new_STS_ID
239
+	 * @param string                $old_STS_ID
240
+	 * @param ContextInterface|null $context
241
+	 * @throws EE_Error
242
+	 * @throws InvalidArgumentException
243
+	 * @throws InvalidDataTypeException
244
+	 * @throws InvalidInterfaceException
245
+	 * @throws ReflectionException
246
+	 * @throws RuntimeException
247
+	 */
248
+	private function updateIfCanceled(
249
+		array $closed_reg_statuses,
250
+		$new_STS_ID,
251
+		$old_STS_ID,
252
+		ContextInterface $context = null
253
+	) {
254
+		// true if registration has been cancelled or declined
255
+		if (in_array($new_STS_ID, $closed_reg_statuses, true)
256
+			&& ! in_array($old_STS_ID, $closed_reg_statuses, true)
257
+		) {
258
+			/** @type EE_Registration_Processor $registration_processor */
259
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
260
+			/** @type EE_Transaction_Processor $transaction_processor */
261
+			$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
262
+			// cancelled or declined registration
263
+			$registration_processor->update_registration_after_being_canceled_or_declined(
264
+				$this,
265
+				$closed_reg_statuses
266
+			);
267
+			$transaction_processor->update_transaction_after_canceled_or_declined_registration(
268
+				$this,
269
+				$closed_reg_statuses,
270
+				false
271
+			);
272
+			do_action(
273
+				'AHEE__EE_Registration__set_status__canceled_or_declined',
274
+				$this,
275
+				$old_STS_ID,
276
+				$new_STS_ID,
277
+				$context
278
+			);
279
+			return;
280
+		}
281
+	}
282
+
283
+
284
+	/**
285
+	 * update REGs and TXN when cancelled or declined registrations involved
286
+	 *
287
+	 * @param array                 $closed_reg_statuses
288
+	 * @param string                $new_STS_ID
289
+	 * @param string                $old_STS_ID
290
+	 * @param ContextInterface|null $context
291
+	 * @throws EE_Error
292
+	 * @throws InvalidArgumentException
293
+	 * @throws InvalidDataTypeException
294
+	 * @throws InvalidInterfaceException
295
+	 * @throws ReflectionException
296
+	 */
297
+	private function updateIfReinstated(
298
+		array $closed_reg_statuses,
299
+		$new_STS_ID,
300
+		$old_STS_ID,
301
+		ContextInterface $context = null
302
+	) {
303
+		// true if reinstating cancelled or declined registration
304
+		if (in_array($old_STS_ID, $closed_reg_statuses, true)
305
+			&& ! in_array($new_STS_ID, $closed_reg_statuses, true)
306
+		) {
307
+			/** @type EE_Registration_Processor $registration_processor */
308
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
309
+			/** @type EE_Transaction_Processor $transaction_processor */
310
+			$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
311
+			// reinstating cancelled or declined registration
312
+			$registration_processor->update_canceled_or_declined_registration_after_being_reinstated(
313
+				$this,
314
+				$closed_reg_statuses
315
+			);
316
+			$transaction_processor->update_transaction_after_reinstating_canceled_registration(
317
+				$this,
318
+				$closed_reg_statuses,
319
+				false
320
+			);
321
+			do_action(
322
+				'AHEE__EE_Registration__set_status__after_reinstated',
323
+				$this,
324
+				$old_STS_ID,
325
+				$new_STS_ID,
326
+				$context
327
+			);
328
+		}
329
+	}
330
+
331
+
332
+	/**
333
+	 * @param ContextInterface|null $context
334
+	 * @return bool
335
+	 */
336
+	private function statusChangeUpdatesTransaction(ContextInterface $context = null)
337
+	{
338
+		$contexts_that_do_not_update_transaction = (array) apply_filters(
339
+			'AHEE__EE_Registration__statusChangeUpdatesTransaction__contexts_that_do_not_update_transaction',
340
+			array('spco_reg_step_attendee_information_process_registrations'),
341
+			$context,
342
+			$this
343
+		);
344
+		return ! (
345
+			$context instanceof ContextInterface
346
+			&& in_array($context->slug(), $contexts_that_do_not_update_transaction, true)
347
+		);
348
+	}
349
+
350
+
351
+	/**
352
+	 * @throws EE_Error
353
+	 * @throws EntityNotFoundException
354
+	 * @throws InvalidArgumentException
355
+	 * @throws InvalidDataTypeException
356
+	 * @throws InvalidInterfaceException
357
+	 * @throws ReflectionException
358
+	 * @throws RuntimeException
359
+	 */
360
+	private function updateTransactionAfterStatusChange()
361
+	{
362
+		/** @type EE_Transaction_Payments $transaction_payments */
363
+		$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
364
+		$transaction_payments->recalculate_transaction_total($this->transaction(), false);
365
+		$this->transaction()->update_status_based_on_total_paid(true);
366
+	}
367
+
368
+
369
+	/**
370
+	 *        get Status ID
371
+	 */
372
+	public function status_ID()
373
+	{
374
+		return $this->get('STS_ID');
375
+	}
376
+
377
+
378
+	/**
379
+	 * Gets the ticket this registration is for
380
+	 *
381
+	 * @param boolean $include_archived whether to include archived tickets or not.
382
+	 *
383
+	 * @return EE_Ticket|EE_Base_Class
384
+	 * @throws EE_Error
385
+	 */
386
+	public function ticket($include_archived = true)
387
+	{
388
+		$query_params = array();
389
+		if ($include_archived) {
390
+			$query_params['default_where_conditions'] = 'none';
391
+		}
392
+		return $this->get_first_related('Ticket', $query_params);
393
+	}
394
+
395
+
396
+	/**
397
+	 * Gets the event this registration is for
398
+	 *
399
+	 * @return EE_Event
400
+	 * @throws EE_Error
401
+	 * @throws EntityNotFoundException
402
+	 */
403
+	public function event()
404
+	{
405
+		$event = $this->get_first_related('Event');
406
+		if (! $event instanceof \EE_Event) {
407
+			throw new EntityNotFoundException('Event ID', $this->event_ID());
408
+		}
409
+		return $event;
410
+	}
411
+
412
+
413
+	/**
414
+	 * Gets the "author" of the registration.  Note that for the purposes of registrations, the author will correspond
415
+	 * with the author of the event this registration is for.
416
+	 *
417
+	 * @since 4.5.0
418
+	 * @return int
419
+	 * @throws EE_Error
420
+	 * @throws EntityNotFoundException
421
+	 */
422
+	public function wp_user()
423
+	{
424
+		$event = $this->event();
425
+		if ($event instanceof EE_Event) {
426
+			return $event->wp_user();
427
+		}
428
+		return 0;
429
+	}
430
+
431
+
432
+	/**
433
+	 * increments this registration's related ticket sold and corresponding datetime sold values
434
+	 *
435
+	 * @return void
436
+	 * @throws DomainException
437
+	 * @throws EE_Error
438
+	 * @throws EntityNotFoundException
439
+	 * @throws InvalidArgumentException
440
+	 * @throws InvalidDataTypeException
441
+	 * @throws InvalidInterfaceException
442
+	 * @throws ReflectionException
443
+	 * @throws UnexpectedEntityException
444
+	 */
445
+	private function reserveRegistrationSpace()
446
+	{
447
+		// reserved ticket and datetime counts will be decremented as sold counts are incremented
448
+		// so stop tracking that this reg has a ticket reserved
449
+		$this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
450
+		$ticket = $this->ticket();
451
+		$ticket->increaseSold();
452
+		// possibly set event status to sold out
453
+		$this->event()->perform_sold_out_status_check();
454
+	}
455
+
456
+
457
+	/**
458
+	 * decrements (subtracts) this registration's related ticket sold and corresponding datetime sold values
459
+	 *
460
+	 * @return void
461
+	 * @throws DomainException
462
+	 * @throws EE_Error
463
+	 * @throws EntityNotFoundException
464
+	 * @throws InvalidArgumentException
465
+	 * @throws InvalidDataTypeException
466
+	 * @throws InvalidInterfaceException
467
+	 * @throws ReflectionException
468
+	 * @throws UnexpectedEntityException
469
+	 */
470
+	private function releaseRegistrationSpace()
471
+	{
472
+		$ticket = $this->ticket();
473
+		$ticket->decreaseSold();
474
+		// possibly change event status from sold out back to previous status
475
+		$this->event()->perform_sold_out_status_check();
476
+	}
477
+
478
+
479
+	/**
480
+	 * tracks this registration's ticket reservation in extra meta
481
+	 * and can increment related ticket reserved and corresponding datetime reserved values
482
+	 *
483
+	 * @param bool $update_ticket if true, will increment ticket and datetime reserved count
484
+	 * @return void
485
+	 * @throws EE_Error
486
+	 * @throws InvalidArgumentException
487
+	 * @throws InvalidDataTypeException
488
+	 * @throws InvalidInterfaceException
489
+	 * @throws ReflectionException
490
+	 */
491
+	public function reserve_ticket($update_ticket = false, $source = 'unknown')
492
+	{
493
+		// only reserve ticket if space is not currently reserved
494
+		if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) !== true) {
495
+			$this->update_extra_meta('reserve_ticket', "{$this->ticket_ID()} from {$source}");
496
+			// IMPORTANT !!!
497
+			// although checking $update_ticket first would be more efficient,
498
+			// we NEED to ALWAYS call update_extra_meta(), which is why that is done first
499
+			if ($this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true)
500
+				&& $update_ticket
501
+			) {
502
+				$ticket = $this->ticket();
503
+				$ticket->increaseReserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
504
+				$ticket->save();
505
+			}
506
+		}
507
+	}
508
+
509
+
510
+	/**
511
+	 * stops tracking this registration's ticket reservation in extra meta
512
+	 * decrements (subtracts) related ticket reserved and corresponding datetime reserved values
513
+	 *
514
+	 * @param bool $update_ticket if true, will decrement ticket and datetime reserved count
515
+	 * @return void
516
+	 * @throws EE_Error
517
+	 * @throws InvalidArgumentException
518
+	 * @throws InvalidDataTypeException
519
+	 * @throws InvalidInterfaceException
520
+	 * @throws ReflectionException
521
+	 */
522
+	public function release_reserved_ticket($update_ticket = false, $source = 'unknown')
523
+	{
524
+		// only release ticket if space is currently reserved
525
+		if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) === true) {
526
+			$this->update_extra_meta('release_reserved_ticket', "{$this->ticket_ID()} from {$source}");
527
+			// IMPORTANT !!!
528
+			// although checking $update_ticket first would be more efficient,
529
+			// we NEED to ALWAYS call update_extra_meta(), which is why that is done first
530
+			if ($this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, false)
531
+				&& $update_ticket
532
+			) {
533
+				$ticket = $this->ticket();
534
+				$ticket->decreaseReserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
535
+			}
536
+		}
537
+	}
538
+
539
+
540
+	/**
541
+	 * Set Attendee ID
542
+	 *
543
+	 * @param        int $ATT_ID Attendee ID
544
+	 * @throws EE_Error
545
+	 * @throws RuntimeException
546
+	 */
547
+	public function set_attendee_id($ATT_ID = 0)
548
+	{
549
+		$this->set('ATT_ID', $ATT_ID);
550
+	}
551
+
552
+
553
+	/**
554
+	 *        Set Transaction ID
555
+	 *
556
+	 * @param        int $TXN_ID Transaction ID
557
+	 * @throws EE_Error
558
+	 * @throws RuntimeException
559
+	 */
560
+	public function set_transaction_id($TXN_ID = 0)
561
+	{
562
+		$this->set('TXN_ID', $TXN_ID);
563
+	}
564
+
565
+
566
+	/**
567
+	 *        Set Session
568
+	 *
569
+	 * @param    string $REG_session PHP Session ID
570
+	 * @throws EE_Error
571
+	 * @throws RuntimeException
572
+	 */
573
+	public function set_session($REG_session = '')
574
+	{
575
+		$this->set('REG_session', $REG_session);
576
+	}
577
+
578
+
579
+	/**
580
+	 *        Set Registration URL Link
581
+	 *
582
+	 * @param    string $REG_url_link Registration URL Link
583
+	 * @throws EE_Error
584
+	 * @throws RuntimeException
585
+	 */
586
+	public function set_reg_url_link($REG_url_link = '')
587
+	{
588
+		$this->set('REG_url_link', $REG_url_link);
589
+	}
590
+
591
+
592
+	/**
593
+	 *        Set Attendee Counter
594
+	 *
595
+	 * @param        int $REG_count Primary Attendee
596
+	 * @throws EE_Error
597
+	 * @throws RuntimeException
598
+	 */
599
+	public function set_count($REG_count = 1)
600
+	{
601
+		$this->set('REG_count', $REG_count);
602
+	}
603
+
604
+
605
+	/**
606
+	 *        Set Group Size
607
+	 *
608
+	 * @param        boolean $REG_group_size Group Registration
609
+	 * @throws EE_Error
610
+	 * @throws RuntimeException
611
+	 */
612
+	public function set_group_size($REG_group_size = false)
613
+	{
614
+		$this->set('REG_group_size', $REG_group_size);
615
+	}
616
+
617
+
618
+	/**
619
+	 *    is_not_approved -  convenience method that returns TRUE if REG status ID ==
620
+	 *    EEM_Registration::status_id_not_approved
621
+	 *
622
+	 * @return        boolean
623
+	 */
624
+	public function is_not_approved()
625
+	{
626
+		return $this->status_ID() == EEM_Registration::status_id_not_approved ? true : false;
627
+	}
628
+
629
+
630
+	/**
631
+	 *    is_pending_payment -  convenience method that returns TRUE if REG status ID ==
632
+	 *    EEM_Registration::status_id_pending_payment
633
+	 *
634
+	 * @return        boolean
635
+	 */
636
+	public function is_pending_payment()
637
+	{
638
+		return $this->status_ID() == EEM_Registration::status_id_pending_payment ? true : false;
639
+	}
640
+
641
+
642
+	/**
643
+	 *    is_approved -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_approved
644
+	 *
645
+	 * @return        boolean
646
+	 */
647
+	public function is_approved()
648
+	{
649
+		return $this->status_ID() == EEM_Registration::status_id_approved ? true : false;
650
+	}
651
+
652
+
653
+	/**
654
+	 *    is_cancelled -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_cancelled
655
+	 *
656
+	 * @return        boolean
657
+	 */
658
+	public function is_cancelled()
659
+	{
660
+		return $this->status_ID() == EEM_Registration::status_id_cancelled ? true : false;
661
+	}
662
+
663
+
664
+	/**
665
+	 *    is_declined -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_declined
666
+	 *
667
+	 * @return        boolean
668
+	 */
669
+	public function is_declined()
670
+	{
671
+		return $this->status_ID() == EEM_Registration::status_id_declined ? true : false;
672
+	}
673
+
674
+
675
+	/**
676
+	 *    is_incomplete -  convenience method that returns TRUE if REG status ID ==
677
+	 *    EEM_Registration::status_id_incomplete
678
+	 *
679
+	 * @return        boolean
680
+	 */
681
+	public function is_incomplete()
682
+	{
683
+		return $this->status_ID() == EEM_Registration::status_id_incomplete ? true : false;
684
+	}
685
+
686
+
687
+	/**
688
+	 *        Set Registration Date
689
+	 *
690
+	 * @param        mixed ( int or string ) $REG_date Registration Date - Unix timestamp or string representation of
691
+	 *                                                 Date
692
+	 * @throws EE_Error
693
+	 * @throws RuntimeException
694
+	 */
695
+	public function set_reg_date($REG_date = false)
696
+	{
697
+		$this->set('REG_date', $REG_date);
698
+	}
699
+
700
+
701
+	/**
702
+	 *    Set final price owing for this registration after all ticket/price modifications
703
+	 *
704
+	 * @access    public
705
+	 * @param    float $REG_final_price
706
+	 * @throws EE_Error
707
+	 * @throws RuntimeException
708
+	 */
709
+	public function set_final_price($REG_final_price = 0.00)
710
+	{
711
+		$this->set('REG_final_price', $REG_final_price);
712
+	}
713
+
714
+
715
+	/**
716
+	 *    Set amount paid towards this registration's final price
717
+	 *
718
+	 * @access    public
719
+	 * @param    float $REG_paid
720
+	 * @throws EE_Error
721
+	 * @throws RuntimeException
722
+	 */
723
+	public function set_paid($REG_paid = 0.00)
724
+	{
725
+		$this->set('REG_paid', $REG_paid);
726
+	}
727
+
728
+
729
+	/**
730
+	 *        Attendee Is Going
731
+	 *
732
+	 * @param        boolean $REG_att_is_going Attendee Is Going
733
+	 * @throws EE_Error
734
+	 * @throws RuntimeException
735
+	 */
736
+	public function set_att_is_going($REG_att_is_going = false)
737
+	{
738
+		$this->set('REG_att_is_going', $REG_att_is_going);
739
+	}
740
+
741
+
742
+	/**
743
+	 * Gets the related attendee
744
+	 *
745
+	 * @return EE_Attendee
746
+	 * @throws EE_Error
747
+	 */
748
+	public function attendee()
749
+	{
750
+		return $this->get_first_related('Attendee');
751
+	}
752
+
753
+
754
+	/**
755
+	 *        get Event ID
756
+	 */
757
+	public function event_ID()
758
+	{
759
+		return $this->get('EVT_ID');
760
+	}
761
+
762
+
763
+	/**
764
+	 *        get Event ID
765
+	 */
766
+	public function event_name()
767
+	{
768
+		$event = $this->event_obj();
769
+		if ($event) {
770
+			return $event->name();
771
+		} else {
772
+			return null;
773
+		}
774
+	}
775
+
776
+
777
+	/**
778
+	 * Fetches the event this registration is for
779
+	 *
780
+	 * @return EE_Event
781
+	 * @throws EE_Error
782
+	 */
783
+	public function event_obj()
784
+	{
785
+		return $this->get_first_related('Event');
786
+	}
787
+
788
+
789
+	/**
790
+	 *        get Attendee ID
791
+	 */
792
+	public function attendee_ID()
793
+	{
794
+		return $this->get('ATT_ID');
795
+	}
796
+
797
+
798
+	/**
799
+	 *        get PHP Session ID
800
+	 */
801
+	public function session_ID()
802
+	{
803
+		return $this->get('REG_session');
804
+	}
805
+
806
+
807
+	/**
808
+	 * Gets the string which represents the URL trigger for the receipt template in the message template system.
809
+	 *
810
+	 * @param string $messenger 'pdf' or 'html'.  Default 'html'.
811
+	 * @return string
812
+	 */
813
+	public function receipt_url($messenger = 'html')
814
+	{
815
+
816
+		/**
817
+		 * The below will be deprecated one version after this.  We check first if there is a custom receipt template
818
+		 * already in use on old system.  If there is then we just return the standard url for it.
819
+		 *
820
+		 * @since 4.5.0
821
+		 */
822
+		$template_relative_path = 'modules/gateways/Invoice/lib/templates/receipt_body.template.php';
823
+		$has_custom = EEH_Template::locate_template(
824
+			$template_relative_path,
825
+			array(),
826
+			true,
827
+			true,
828
+			true
829
+		);
830
+
831
+		if ($has_custom) {
832
+			return add_query_arg(array('receipt' => 'true'), $this->invoice_url('launch'));
833
+		}
834
+		return apply_filters('FHEE__EE_Registration__receipt_url__receipt_url', '', $this, $messenger, 'receipt');
835
+	}
836
+
837
+
838
+	/**
839
+	 * Gets the string which represents the URL trigger for the invoice template in the message template system.
840
+	 *
841
+	 * @param string $messenger 'pdf' or 'html'.  Default 'html'.
842
+	 * @return string
843
+	 * @throws EE_Error
844
+	 */
845
+	public function invoice_url($messenger = 'html')
846
+	{
847
+		/**
848
+		 * The below will be deprecated one version after this.  We check first if there is a custom invoice template
849
+		 * already in use on old system.  If there is then we just return the standard url for it.
850
+		 *
851
+		 * @since 4.5.0
852
+		 */
853
+		$template_relative_path = 'modules/gateways/Invoice/lib/templates/invoice_body.template.php';
854
+		$has_custom = EEH_Template::locate_template(
855
+			$template_relative_path,
856
+			array(),
857
+			true,
858
+			true,
859
+			true
860
+		);
861
+
862
+		if ($has_custom) {
863
+			if ($messenger == 'html') {
864
+				return $this->invoice_url('launch');
865
+			}
866
+			$route = $messenger == 'download' || $messenger == 'pdf' ? 'download_invoice' : 'launch_invoice';
867
+
868
+			$query_args = array('ee' => $route, 'id' => $this->reg_url_link());
869
+			if ($messenger == 'html') {
870
+				$query_args['html'] = true;
871
+			}
872
+			return add_query_arg($query_args, get_permalink(EE_Registry::instance()->CFG->core->thank_you_page_id));
873
+		}
874
+		return apply_filters('FHEE__EE_Registration__invoice_url__invoice_url', '', $this, $messenger, 'invoice');
875
+	}
876
+
877
+
878
+	/**
879
+	 * get Registration URL Link
880
+	 *
881
+	 * @access public
882
+	 * @return string
883
+	 * @throws EE_Error
884
+	 */
885
+	public function reg_url_link()
886
+	{
887
+		return (string) $this->get('REG_url_link');
888
+	}
889
+
890
+
891
+	/**
892
+	 * Echoes out invoice_url()
893
+	 *
894
+	 * @param string $type 'download','launch', or 'html' (default is 'launch')
895
+	 * @return void
896
+	 * @throws EE_Error
897
+	 */
898
+	public function e_invoice_url($type = 'launch')
899
+	{
900
+		echo $this->invoice_url($type);
901
+	}
902
+
903
+
904
+	/**
905
+	 * Echoes out payment_overview_url
906
+	 */
907
+	public function e_payment_overview_url()
908
+	{
909
+		echo $this->payment_overview_url();
910
+	}
911
+
912
+
913
+	/**
914
+	 * Gets the URL for the checkout payment options reg step
915
+	 * with this registration's REG_url_link added as a query parameter
916
+	 *
917
+	 * @param bool $clear_session Set to true when you want to clear the session on revisiting the
918
+	 *                            payment overview url.
919
+	 * @return string
920
+	 * @throws InvalidInterfaceException
921
+	 * @throws InvalidDataTypeException
922
+	 * @throws EE_Error
923
+	 * @throws InvalidArgumentException
924
+	 */
925
+	public function payment_overview_url($clear_session = false)
926
+	{
927
+		return add_query_arg(
928
+			(array) apply_filters(
929
+				'FHEE__EE_Registration__payment_overview_url__query_args',
930
+				array(
931
+					'e_reg_url_link' => $this->reg_url_link(),
932
+					'step'           => 'payment_options',
933
+					'revisit'        => true,
934
+					'clear_session'  => (bool) $clear_session,
935
+				),
936
+				$this
937
+			),
938
+			EE_Registry::instance()->CFG->core->reg_page_url()
939
+		);
940
+	}
941
+
942
+
943
+	/**
944
+	 * Gets the URL for the checkout attendee information reg step
945
+	 * with this registration's REG_url_link added as a query parameter
946
+	 *
947
+	 * @return string
948
+	 * @throws InvalidInterfaceException
949
+	 * @throws InvalidDataTypeException
950
+	 * @throws EE_Error
951
+	 * @throws InvalidArgumentException
952
+	 */
953
+	public function edit_attendee_information_url()
954
+	{
955
+		return add_query_arg(
956
+			(array) apply_filters(
957
+				'FHEE__EE_Registration__edit_attendee_information_url__query_args',
958
+				array(
959
+					'e_reg_url_link' => $this->reg_url_link(),
960
+					'step'           => 'attendee_information',
961
+					'revisit'        => true,
962
+				),
963
+				$this
964
+			),
965
+			EE_Registry::instance()->CFG->core->reg_page_url()
966
+		);
967
+	}
968
+
969
+
970
+	/**
971
+	 * Simply generates and returns the appropriate admin_url link to edit this registration
972
+	 *
973
+	 * @return string
974
+	 * @throws EE_Error
975
+	 */
976
+	public function get_admin_edit_url()
977
+	{
978
+		return EEH_URL::add_query_args_and_nonce(
979
+			array(
980
+				'page'    => 'espresso_registrations',
981
+				'action'  => 'view_registration',
982
+				'_REG_ID' => $this->ID(),
983
+			),
984
+			admin_url('admin.php')
985
+		);
986
+	}
987
+
988
+
989
+	/**
990
+	 *    is_primary_registrant?
991
+	 */
992
+	public function is_primary_registrant()
993
+	{
994
+		return $this->get('REG_count') === 1 ? true : false;
995
+	}
996
+
997
+
998
+	/**
999
+	 * This returns the primary registration object for this registration group (which may be this object).
1000
+	 *
1001
+	 * @return EE_Registration
1002
+	 * @throws EE_Error
1003
+	 */
1004
+	public function get_primary_registration()
1005
+	{
1006
+		if ($this->is_primary_registrant()) {
1007
+			return $this;
1008
+		}
1009
+
1010
+		// k reg_count !== 1 so let's get the EE_Registration object matching this txn_id and reg_count == 1
1011
+		/** @var EE_Registration $primary_registrant */
1012
+		$primary_registrant = EEM_Registration::instance()->get_one(
1013
+			array(
1014
+				array(
1015
+					'TXN_ID'    => $this->transaction_ID(),
1016
+					'REG_count' => 1,
1017
+				),
1018
+			)
1019
+		);
1020
+		return $primary_registrant;
1021
+	}
1022
+
1023
+
1024
+	/**
1025
+	 *        get  Attendee Number
1026
+	 *
1027
+	 * @access        public
1028
+	 */
1029
+	public function count()
1030
+	{
1031
+		return $this->get('REG_count');
1032
+	}
1033
+
1034
+
1035
+	/**
1036
+	 *        get Group Size
1037
+	 */
1038
+	public function group_size()
1039
+	{
1040
+		return $this->get('REG_group_size');
1041
+	}
1042
+
1043
+
1044
+	/**
1045
+	 *        get Registration Date
1046
+	 */
1047
+	public function date()
1048
+	{
1049
+		return $this->get('REG_date');
1050
+	}
1051
+
1052
+
1053
+	/**
1054
+	 * gets a pretty date
1055
+	 *
1056
+	 * @param string $date_format
1057
+	 * @param string $time_format
1058
+	 * @return string
1059
+	 * @throws EE_Error
1060
+	 */
1061
+	public function pretty_date($date_format = null, $time_format = null)
1062
+	{
1063
+		return $this->get_datetime('REG_date', $date_format, $time_format);
1064
+	}
1065
+
1066
+
1067
+	/**
1068
+	 * final_price
1069
+	 * the registration's share of the transaction total, so that the
1070
+	 * sum of all the transaction's REG_final_prices equal the transaction's total
1071
+	 *
1072
+	 * @return float
1073
+	 * @throws EE_Error
1074
+	 */
1075
+	public function final_price()
1076
+	{
1077
+		return $this->get('REG_final_price');
1078
+	}
1079
+
1080
+
1081
+	/**
1082
+	 * pretty_final_price
1083
+	 *  final price as formatted string, with correct decimal places and currency symbol
1084
+	 *
1085
+	 * @return string
1086
+	 * @throws EE_Error
1087
+	 */
1088
+	public function pretty_final_price()
1089
+	{
1090
+		return $this->get_pretty('REG_final_price');
1091
+	}
1092
+
1093
+
1094
+	/**
1095
+	 * get paid (yeah)
1096
+	 *
1097
+	 * @return float
1098
+	 * @throws EE_Error
1099
+	 */
1100
+	public function paid()
1101
+	{
1102
+		return $this->get('REG_paid');
1103
+	}
1104
+
1105
+
1106
+	/**
1107
+	 * pretty_paid
1108
+	 *
1109
+	 * @return float
1110
+	 * @throws EE_Error
1111
+	 */
1112
+	public function pretty_paid()
1113
+	{
1114
+		return $this->get_pretty('REG_paid');
1115
+	}
1116
+
1117
+
1118
+	/**
1119
+	 * owes_monies_and_can_pay
1120
+	 * whether or not this registration has monies owing and it's' status allows payment
1121
+	 *
1122
+	 * @param array $requires_payment
1123
+	 * @return bool
1124
+	 * @throws EE_Error
1125
+	 */
1126
+	public function owes_monies_and_can_pay($requires_payment = array())
1127
+	{
1128
+		// these reg statuses require payment (if event is not free)
1129
+		$requires_payment = ! empty($requires_payment)
1130
+			? $requires_payment
1131
+			: EEM_Registration::reg_statuses_that_allow_payment();
1132
+		if (in_array($this->status_ID(), $requires_payment) &&
1133
+			$this->final_price() != 0 &&
1134
+			$this->final_price() != $this->paid()
1135
+		) {
1136
+			return true;
1137
+		} else {
1138
+			return false;
1139
+		}
1140
+	}
1141
+
1142
+
1143
+	/**
1144
+	 * Prints out the return value of $this->pretty_status()
1145
+	 *
1146
+	 * @param bool $show_icons
1147
+	 * @return void
1148
+	 * @throws EE_Error
1149
+	 */
1150
+	public function e_pretty_status($show_icons = false)
1151
+	{
1152
+		echo $this->pretty_status($show_icons);
1153
+	}
1154
+
1155
+
1156
+	/**
1157
+	 * Returns a nice version of the status for displaying to customers
1158
+	 *
1159
+	 * @param bool $show_icons
1160
+	 * @return string
1161
+	 * @throws EE_Error
1162
+	 */
1163
+	public function pretty_status($show_icons = false)
1164
+	{
1165
+		$status = EEM_Status::instance()->localized_status(
1166
+			array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
1167
+			false,
1168
+			'sentence'
1169
+		);
1170
+		$icon = '';
1171
+		switch ($this->status_ID()) {
1172
+			case EEM_Registration::status_id_approved:
1173
+				$icon = $show_icons
1174
+					? '<span class="dashicons dashicons-star-filled ee-icon-size-16 green-text"></span>'
1175
+					: '';
1176
+				break;
1177
+			case EEM_Registration::status_id_pending_payment:
1178
+				$icon = $show_icons
1179
+					? '<span class="dashicons dashicons-star-half ee-icon-size-16 orange-text"></span>'
1180
+					: '';
1181
+				break;
1182
+			case EEM_Registration::status_id_not_approved:
1183
+				$icon = $show_icons
1184
+					? '<span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>'
1185
+					: '';
1186
+				break;
1187
+			case EEM_Registration::status_id_cancelled:
1188
+				$icon = $show_icons
1189
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
1190
+					: '';
1191
+				break;
1192
+			case EEM_Registration::status_id_incomplete:
1193
+				$icon = $show_icons
1194
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-orange-text"></span>'
1195
+					: '';
1196
+				break;
1197
+			case EEM_Registration::status_id_declined:
1198
+				$icon = $show_icons
1199
+					? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
1200
+					: '';
1201
+				break;
1202
+			case EEM_Registration::status_id_wait_list:
1203
+				$icon = $show_icons
1204
+					? '<span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>'
1205
+					: '';
1206
+				break;
1207
+		}
1208
+		return $icon . $status[ $this->status_ID() ];
1209
+	}
1210
+
1211
+
1212
+	/**
1213
+	 *        get Attendee Is Going
1214
+	 */
1215
+	public function att_is_going()
1216
+	{
1217
+		return $this->get('REG_att_is_going');
1218
+	}
1219
+
1220
+
1221
+	/**
1222
+	 * Gets related answers
1223
+	 *
1224
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1225
+	 * @return EE_Answer[]
1226
+	 * @throws EE_Error
1227
+	 */
1228
+	public function answers($query_params = null)
1229
+	{
1230
+		return $this->get_many_related('Answer', $query_params);
1231
+	}
1232
+
1233
+
1234
+	/**
1235
+	 * Gets the registration's answer value to the specified question
1236
+	 * (either the question's ID or a question object)
1237
+	 *
1238
+	 * @param EE_Question|int $question
1239
+	 * @param bool            $pretty_value
1240
+	 * @return array|string if pretty_value= true, the result will always be a string
1241
+	 * (because the answer might be an array of answer values, so passing pretty_value=true
1242
+	 * will convert it into some kind of string)
1243
+	 * @throws EE_Error
1244
+	 */
1245
+	public function answer_value_to_question($question, $pretty_value = true)
1246
+	{
1247
+		$question_id = EEM_Question::instance()->ensure_is_ID($question);
1248
+		return EEM_Answer::instance()->get_answer_value_to_question($this, $question_id, $pretty_value);
1249
+	}
1250
+
1251
+
1252
+	/**
1253
+	 * question_groups
1254
+	 * returns an array of EE_Question_Group objects for this registration
1255
+	 *
1256
+	 * @return EE_Question_Group[]
1257
+	 * @throws EE_Error
1258
+	 * @throws InvalidArgumentException
1259
+	 * @throws InvalidDataTypeException
1260
+	 * @throws InvalidInterfaceException
1261
+	 * @throws ReflectionException
1262
+	 */
1263
+	public function question_groups()
1264
+	{
1265
+		return EEM_Event::instance()->get_question_groups_for_event($this->event_ID(), $this);
1266
+	}
1267
+
1268
+
1269
+	/**
1270
+	 * count_question_groups
1271
+	 * returns a count of the number of EE_Question_Group objects for this registration
1272
+	 *
1273
+	 * @return int
1274
+	 * @throws EE_Error
1275
+	 * @throws EntityNotFoundException
1276
+	 * @throws InvalidArgumentException
1277
+	 * @throws InvalidDataTypeException
1278
+	 * @throws InvalidInterfaceException
1279
+	 * @throws ReflectionException
1280
+	 */
1281
+	public function count_question_groups()
1282
+	{
1283
+		return EEM_Event::instance()->count_related(
1284
+			$this->event_ID(),
1285
+			'Question_Group',
1286
+			[
1287
+				[
1288
+					'Event_Question_Group.'
1289
+					. EEM_Event_Question_Group::instance()->fieldNameForContext($this->is_primary_registrant()) => true,
1290
+				]
1291
+			]
1292
+		);
1293
+	}
1294
+
1295
+
1296
+	/**
1297
+	 * Returns the registration date in the 'standard' string format
1298
+	 * (function may be improved in the future to allow for different formats and timezones)
1299
+	 *
1300
+	 * @return string
1301
+	 * @throws EE_Error
1302
+	 */
1303
+	public function reg_date()
1304
+	{
1305
+		return $this->get_datetime('REG_date');
1306
+	}
1307
+
1308
+
1309
+	/**
1310
+	 * Gets the datetime-ticket for this registration (ie, it can be used to isolate
1311
+	 * the ticket this registration purchased, or the datetime they have registered
1312
+	 * to attend)
1313
+	 *
1314
+	 * @return EE_Datetime_Ticket
1315
+	 * @throws EE_Error
1316
+	 */
1317
+	public function datetime_ticket()
1318
+	{
1319
+		return $this->get_first_related('Datetime_Ticket');
1320
+	}
1321
+
1322
+
1323
+	/**
1324
+	 * Sets the registration's datetime_ticket.
1325
+	 *
1326
+	 * @param EE_Datetime_Ticket $datetime_ticket
1327
+	 * @return EE_Datetime_Ticket
1328
+	 * @throws EE_Error
1329
+	 */
1330
+	public function set_datetime_ticket($datetime_ticket)
1331
+	{
1332
+		return $this->_add_relation_to($datetime_ticket, 'Datetime_Ticket');
1333
+	}
1334
+
1335
+	/**
1336
+	 * Gets deleted
1337
+	 *
1338
+	 * @return bool
1339
+	 * @throws EE_Error
1340
+	 */
1341
+	public function deleted()
1342
+	{
1343
+		return $this->get('REG_deleted');
1344
+	}
1345
+
1346
+	/**
1347
+	 * Sets deleted
1348
+	 *
1349
+	 * @param boolean $deleted
1350
+	 * @return bool
1351
+	 * @throws EE_Error
1352
+	 * @throws RuntimeException
1353
+	 */
1354
+	public function set_deleted($deleted)
1355
+	{
1356
+		if ($deleted) {
1357
+			$this->delete();
1358
+		} else {
1359
+			$this->restore();
1360
+		}
1361
+	}
1362
+
1363
+
1364
+	/**
1365
+	 * Get the status object of this object
1366
+	 *
1367
+	 * @return EE_Status
1368
+	 * @throws EE_Error
1369
+	 */
1370
+	public function status_obj()
1371
+	{
1372
+		return $this->get_first_related('Status');
1373
+	}
1374
+
1375
+
1376
+	/**
1377
+	 * Returns the number of times this registration has checked into any of the datetimes
1378
+	 * its available for
1379
+	 *
1380
+	 * @return int
1381
+	 * @throws EE_Error
1382
+	 */
1383
+	public function count_checkins()
1384
+	{
1385
+		return $this->get_model()->count_related($this, 'Checkin');
1386
+	}
1387
+
1388
+
1389
+	/**
1390
+	 * Returns the number of current Check-ins this registration is checked into for any of the datetimes the
1391
+	 * registration is for.  Note, this is ONLY checked in (does not include checkedout)
1392
+	 *
1393
+	 * @return int
1394
+	 * @throws EE_Error
1395
+	 */
1396
+	public function count_checkins_not_checkedout()
1397
+	{
1398
+		return $this->get_model()->count_related($this, 'Checkin', array(array('CHK_in' => 1)));
1399
+	}
1400
+
1401
+
1402
+	/**
1403
+	 * The purpose of this method is simply to check whether this registration can checkin to the given datetime.
1404
+	 *
1405
+	 * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1406
+	 * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1407
+	 *                                          consider registration status as well as datetime access.
1408
+	 * @return bool
1409
+	 * @throws EE_Error
1410
+	 */
1411
+	public function can_checkin($DTT_OR_ID, $check_approved = true)
1412
+	{
1413
+		$DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1414
+
1415
+		// first check registration status
1416
+		if (($check_approved && ! $this->is_approved()) || ! $DTT_ID) {
1417
+			return false;
1418
+		}
1419
+		// is there a datetime ticket that matches this dtt_ID?
1420
+		if (! (EEM_Datetime_Ticket::instance()->exists(
1421
+			array(
1422
+				array(
1423
+					'TKT_ID' => $this->get('TKT_ID'),
1424
+					'DTT_ID' => $DTT_ID,
1425
+				),
1426
+			)
1427
+		))
1428
+		) {
1429
+			return false;
1430
+		}
1431
+
1432
+		// final check is against TKT_uses
1433
+		return $this->verify_can_checkin_against_TKT_uses($DTT_ID);
1434
+	}
1435
+
1436
+
1437
+	/**
1438
+	 * This method verifies whether the user can checkin for the given datetime considering the max uses value set on
1439
+	 * the ticket. To do this,  a query is done to get the count of the datetime records already checked into.  If the
1440
+	 * datetime given does not have a check-in record and checking in for that datetime will exceed the allowed uses,
1441
+	 * then return false.  Otherwise return true.
1442
+	 *
1443
+	 * @param int | EE_Datetime $DTT_OR_ID The datetime the registration is being checked against
1444
+	 * @return bool true means can checkin.  false means cannot checkin.
1445
+	 * @throws EE_Error
1446
+	 */
1447
+	public function verify_can_checkin_against_TKT_uses($DTT_OR_ID)
1448
+	{
1449
+		$DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1450
+
1451
+		if (! $DTT_ID) {
1452
+			return false;
1453
+		}
1454
+
1455
+		$max_uses = $this->ticket() instanceof EE_Ticket ? $this->ticket()->uses() : EE_INF;
1456
+
1457
+		// if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1458
+		// check-in or not.
1459
+		if (! $max_uses || $max_uses === EE_INF) {
1460
+			return true;
1461
+		}
1462
+
1463
+		// does this datetime have a checkin record?  If so, then the dtt count has already been verified so we can just
1464
+		// go ahead and toggle.
1465
+		if (EEM_Checkin::instance()->exists(array(array('REG_ID' => $this->ID(), 'DTT_ID' => $DTT_ID)))) {
1466
+			return true;
1467
+		}
1468
+
1469
+		// made it here so the last check is whether the number of checkins per unique datetime on this registration
1470
+		// disallows further check-ins.
1471
+		$count_unique_dtt_checkins = EEM_Checkin::instance()->count(
1472
+			array(
1473
+				array(
1474
+					'REG_ID' => $this->ID(),
1475
+					'CHK_in' => true,
1476
+				),
1477
+			),
1478
+			'DTT_ID',
1479
+			true
1480
+		);
1481
+		// checkins have already reached their max number of uses
1482
+		// so registrant can NOT checkin
1483
+		if ($count_unique_dtt_checkins >= $max_uses) {
1484
+			EE_Error::add_error(
1485
+				esc_html__(
1486
+					'Check-in denied because number of datetime uses for the ticket has been reached or exceeded.',
1487
+					'event_espresso'
1488
+				),
1489
+				__FILE__,
1490
+				__FUNCTION__,
1491
+				__LINE__
1492
+			);
1493
+			return false;
1494
+		}
1495
+		return true;
1496
+	}
1497
+
1498
+
1499
+	/**
1500
+	 * toggle Check-in status for this registration
1501
+	 * Check-ins are toggled in the following order:
1502
+	 * never checked in -> checked in
1503
+	 * checked in -> checked out
1504
+	 * checked out -> checked in
1505
+	 *
1506
+	 * @param  int $DTT_ID  include specific datetime to toggle Check-in for.
1507
+	 *                      If not included or null, then it is assumed latest datetime is being toggled.
1508
+	 * @param bool $verify  If true then can_checkin() is used to verify whether the person
1509
+	 *                      can be checked in or not.  Otherwise this forces change in checkin status.
1510
+	 * @return bool|int     the chk_in status toggled to OR false if nothing got changed.
1511
+	 * @throws EE_Error
1512
+	 */
1513
+	public function toggle_checkin_status($DTT_ID = null, $verify = false)
1514
+	{
1515
+		if (empty($DTT_ID)) {
1516
+			$datetime = $this->get_latest_related_datetime();
1517
+			$DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1518
+			// verify the registration can checkin for the given DTT_ID
1519
+		} elseif (! $this->can_checkin($DTT_ID, $verify)) {
1520
+			EE_Error::add_error(
1521
+				sprintf(
1522
+					esc_html__(
1523
+						'The given registration (ID:%1$d) can not be checked in to the given DTT_ID (%2$d), because the registration does not have access',
1524
+						'event_espresso'
1525
+					),
1526
+					$this->ID(),
1527
+					$DTT_ID
1528
+				),
1529
+				__FILE__,
1530
+				__FUNCTION__,
1531
+				__LINE__
1532
+			);
1533
+			return false;
1534
+		}
1535
+		$status_paths = array(
1536
+			EE_Checkin::status_checked_never => EE_Checkin::status_checked_in,
1537
+			EE_Checkin::status_checked_in    => EE_Checkin::status_checked_out,
1538
+			EE_Checkin::status_checked_out   => EE_Checkin::status_checked_in,
1539
+		);
1540
+		// start by getting the current status so we know what status we'll be changing to.
1541
+		$cur_status = $this->check_in_status_for_datetime($DTT_ID, null);
1542
+		$status_to = $status_paths[ $cur_status ];
1543
+		// database only records true for checked IN or false for checked OUT
1544
+		// no record ( null ) means checked in NEVER, but we obviously don't save that
1545
+		$new_status = $status_to === EE_Checkin::status_checked_in ? true : false;
1546
+		// add relation - note Check-ins are always creating new rows
1547
+		// because we are keeping track of Check-ins over time.
1548
+		// Eventually we'll probably want to show a list table
1549
+		// for the individual Check-ins so that they can be managed.
1550
+		$checkin = EE_Checkin::new_instance(
1551
+			array(
1552
+				'REG_ID' => $this->ID(),
1553
+				'DTT_ID' => $DTT_ID,
1554
+				'CHK_in' => $new_status,
1555
+			)
1556
+		);
1557
+		// if the record could not be saved then return false
1558
+		if ($checkin->save() === 0) {
1559
+			if (WP_DEBUG) {
1560
+				global $wpdb;
1561
+				$error = sprintf(
1562
+					esc_html__(
1563
+						'Registration check in update failed because of the following database error: %1$s%2$s',
1564
+						'event_espresso'
1565
+					),
1566
+					'<br />',
1567
+					$wpdb->last_error
1568
+				);
1569
+			} else {
1570
+				$error = esc_html__(
1571
+					'Registration check in update failed because of an unknown database error',
1572
+					'event_espresso'
1573
+				);
1574
+			}
1575
+			EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
1576
+			return false;
1577
+		}
1578
+		return $status_to;
1579
+	}
1580
+
1581
+
1582
+	/**
1583
+	 * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1584
+	 * "Latest" is defined by the `DTT_EVT_start` column.
1585
+	 *
1586
+	 * @return EE_Datetime|null
1587
+	 * @throws EE_Error
1588
+	 */
1589
+	public function get_latest_related_datetime()
1590
+	{
1591
+		return EEM_Datetime::instance()->get_one(
1592
+			array(
1593
+				array(
1594
+					'Ticket.Registration.REG_ID' => $this->ID(),
1595
+				),
1596
+				'order_by' => array('DTT_EVT_start' => 'DESC'),
1597
+			)
1598
+		);
1599
+	}
1600
+
1601
+
1602
+	/**
1603
+	 * Returns the earliest datetime related to this registration (via the ticket attached to the registration).
1604
+	 * "Earliest" is defined by the `DTT_EVT_start` column.
1605
+	 *
1606
+	 * @throws EE_Error
1607
+	 */
1608
+	public function get_earliest_related_datetime()
1609
+	{
1610
+		return EEM_Datetime::instance()->get_one(
1611
+			array(
1612
+				array(
1613
+					'Ticket.Registration.REG_ID' => $this->ID(),
1614
+				),
1615
+				'order_by' => array('DTT_EVT_start' => 'ASC'),
1616
+			)
1617
+		);
1618
+	}
1619
+
1620
+
1621
+	/**
1622
+	 * This method simply returns the check-in status for this registration and the given datetime.
1623
+	 * If neither the datetime nor the checkin values are provided as arguments,
1624
+	 * then this will return the LATEST check-in status for the registration across all datetimes it belongs to.
1625
+	 *
1626
+	 * @param  int       $DTT_ID  The ID of the datetime we're checking against
1627
+	 *                            (if empty we'll get the primary datetime for
1628
+	 *                            this registration (via event) and use it's ID);
1629
+	 * @param EE_Checkin $checkin If present, we use the given checkin object rather than the dtt_id.
1630
+	 *
1631
+	 * @return int                Integer representing Check-in status.
1632
+	 * @throws EE_Error
1633
+	 */
1634
+	public function check_in_status_for_datetime($DTT_ID = 0, $checkin = null)
1635
+	{
1636
+		$checkin_query_params = array(
1637
+			'order_by' => array('CHK_timestamp' => 'DESC'),
1638
+		);
1639
+
1640
+		if ($DTT_ID > 0) {
1641
+			$checkin_query_params[0] = array('DTT_ID' => $DTT_ID);
1642
+		}
1643
+
1644
+		// get checkin object (if exists)
1645
+		$checkin = $checkin instanceof EE_Checkin
1646
+			? $checkin
1647
+			: $this->get_first_related('Checkin', $checkin_query_params);
1648
+		if ($checkin instanceof EE_Checkin) {
1649
+			if ($checkin->get('CHK_in')) {
1650
+				return EE_Checkin::status_checked_in; // checked in
1651
+			}
1652
+			return EE_Checkin::status_checked_out; // had checked in but is now checked out.
1653
+		}
1654
+		return EE_Checkin::status_checked_never; // never been checked in
1655
+	}
1656
+
1657
+
1658
+	/**
1659
+	 * This method returns a localized message for the toggled Check-in message.
1660
+	 *
1661
+	 * @param  int $DTT_ID include specific datetime to get the correct Check-in message.  If not included or null,
1662
+	 *                     then it is assumed Check-in for primary datetime was toggled.
1663
+	 * @param bool $error  This just flags that you want an error message returned. This is put in so that the error
1664
+	 *                     message can be customized with the attendee name.
1665
+	 * @return string internationalized message
1666
+	 * @throws EE_Error
1667
+	 */
1668
+	public function get_checkin_msg($DTT_ID, $error = false)
1669
+	{
1670
+		// let's get the attendee first so we can include the name of the attendee
1671
+		$attendee = $this->get_first_related('Attendee');
1672
+		if ($attendee instanceof EE_Attendee) {
1673
+			if ($error) {
1674
+				return sprintf(__("%s's check-in status was not changed.", "event_espresso"), $attendee->full_name());
1675
+			}
1676
+			$cur_status = $this->check_in_status_for_datetime($DTT_ID);
1677
+			// what is the status message going to be?
1678
+			switch ($cur_status) {
1679
+				case EE_Checkin::status_checked_never:
1680
+					return sprintf(
1681
+						__("%s has been removed from Check-in records", "event_espresso"),
1682
+						$attendee->full_name()
1683
+					);
1684
+					break;
1685
+				case EE_Checkin::status_checked_in:
1686
+					return sprintf(__('%s has been checked in', 'event_espresso'), $attendee->full_name());
1687
+					break;
1688
+				case EE_Checkin::status_checked_out:
1689
+					return sprintf(__('%s has been checked out', 'event_espresso'), $attendee->full_name());
1690
+					break;
1691
+			}
1692
+		}
1693
+		return esc_html__("The check-in status could not be determined.", "event_espresso");
1694
+	}
1695
+
1696
+
1697
+	/**
1698
+	 * Returns the related EE_Transaction to this registration
1699
+	 *
1700
+	 * @return EE_Transaction
1701
+	 * @throws EE_Error
1702
+	 * @throws EntityNotFoundException
1703
+	 */
1704
+	public function transaction()
1705
+	{
1706
+		$transaction = $this->get_first_related('Transaction');
1707
+		if (! $transaction instanceof \EE_Transaction) {
1708
+			throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
1709
+		}
1710
+		return $transaction;
1711
+	}
1712
+
1713
+
1714
+	/**
1715
+	 *        get Registration Code
1716
+	 */
1717
+	public function reg_code()
1718
+	{
1719
+		return $this->get('REG_code');
1720
+	}
1721
+
1722
+
1723
+	/**
1724
+	 *        get Transaction ID
1725
+	 */
1726
+	public function transaction_ID()
1727
+	{
1728
+		return $this->get('TXN_ID');
1729
+	}
1730
+
1731
+
1732
+	/**
1733
+	 * @return int
1734
+	 * @throws EE_Error
1735
+	 */
1736
+	public function ticket_ID()
1737
+	{
1738
+		return $this->get('TKT_ID');
1739
+	}
1740
+
1741
+
1742
+	/**
1743
+	 *        Set Registration Code
1744
+	 *
1745
+	 * @access    public
1746
+	 * @param    string  $REG_code Registration Code
1747
+	 * @param    boolean $use_default
1748
+	 * @throws EE_Error
1749
+	 */
1750
+	public function set_reg_code($REG_code, $use_default = false)
1751
+	{
1752
+		if (empty($REG_code)) {
1753
+			EE_Error::add_error(
1754
+				esc_html__('REG_code can not be empty.', 'event_espresso'),
1755
+				__FILE__,
1756
+				__FUNCTION__,
1757
+				__LINE__
1758
+			);
1759
+			return;
1760
+		}
1761
+		if (! $this->reg_code()) {
1762
+			parent::set('REG_code', $REG_code, $use_default);
1763
+		} else {
1764
+			EE_Error::doing_it_wrong(
1765
+				__CLASS__ . '::' . __FUNCTION__,
1766
+				esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
1767
+				'4.6.0'
1768
+			);
1769
+		}
1770
+	}
1771
+
1772
+
1773
+	/**
1774
+	 * Returns all other registrations in the same group as this registrant who have the same ticket option.
1775
+	 * Note, if you want to just get all registrations in the same transaction (group), use:
1776
+	 *    $registration->transaction()->registrations();
1777
+	 *
1778
+	 * @since 4.5.0
1779
+	 * @return EE_Registration[] or empty array if this isn't a group registration.
1780
+	 * @throws EE_Error
1781
+	 */
1782
+	public function get_all_other_registrations_in_group()
1783
+	{
1784
+		if ($this->group_size() < 2) {
1785
+			return array();
1786
+		}
1787
+
1788
+		$query[0] = array(
1789
+			'TXN_ID' => $this->transaction_ID(),
1790
+			'REG_ID' => array('!=', $this->ID()),
1791
+			'TKT_ID' => $this->ticket_ID(),
1792
+		);
1793
+		/** @var EE_Registration[] $registrations */
1794
+		$registrations = $this->get_model()->get_all($query);
1795
+		return $registrations;
1796
+	}
1797
+
1798
+	/**
1799
+	 * Return the link to the admin details for the object.
1800
+	 *
1801
+	 * @return string
1802
+	 * @throws EE_Error
1803
+	 */
1804
+	public function get_admin_details_link()
1805
+	{
1806
+		EE_Registry::instance()->load_helper('URL');
1807
+		return EEH_URL::add_query_args_and_nonce(
1808
+			array(
1809
+				'page'    => 'espresso_registrations',
1810
+				'action'  => 'view_registration',
1811
+				'_REG_ID' => $this->ID(),
1812
+			),
1813
+			admin_url('admin.php')
1814
+		);
1815
+	}
1816
+
1817
+	/**
1818
+	 * Returns the link to the editor for the object.  Sometimes this is the same as the details.
1819
+	 *
1820
+	 * @return string
1821
+	 * @throws EE_Error
1822
+	 */
1823
+	public function get_admin_edit_link()
1824
+	{
1825
+		return $this->get_admin_details_link();
1826
+	}
1827
+
1828
+	/**
1829
+	 * Returns the link to a settings page for the object.
1830
+	 *
1831
+	 * @return string
1832
+	 * @throws EE_Error
1833
+	 */
1834
+	public function get_admin_settings_link()
1835
+	{
1836
+		return $this->get_admin_details_link();
1837
+	}
1838
+
1839
+	/**
1840
+	 * Returns the link to the "overview" for the object (typically the "list table" view).
1841
+	 *
1842
+	 * @return string
1843
+	 */
1844
+	public function get_admin_overview_link()
1845
+	{
1846
+		EE_Registry::instance()->load_helper('URL');
1847
+		return EEH_URL::add_query_args_and_nonce(
1848
+			array(
1849
+				'page' => 'espresso_registrations',
1850
+			),
1851
+			admin_url('admin.php')
1852
+		);
1853
+	}
1854
+
1855
+
1856
+	/**
1857
+	 * @param array $query_params
1858
+	 *
1859
+	 * @return \EE_Registration[]
1860
+	 * @throws EE_Error
1861
+	 */
1862
+	public function payments($query_params = array())
1863
+	{
1864
+		return $this->get_many_related('Payment', $query_params);
1865
+	}
1866
+
1867
+
1868
+	/**
1869
+	 * @param array $query_params
1870
+	 *
1871
+	 * @return \EE_Registration_Payment[]
1872
+	 * @throws EE_Error
1873
+	 */
1874
+	public function registration_payments($query_params = array())
1875
+	{
1876
+		return $this->get_many_related('Registration_Payment', $query_params);
1877
+	}
1878
+
1879
+
1880
+	/**
1881
+	 * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
1882
+	 * Note: if there are no payments on the registration there will be no payment method returned.
1883
+	 *
1884
+	 * @return EE_Payment_Method|null
1885
+	 */
1886
+	public function payment_method()
1887
+	{
1888
+		return EEM_Payment_Method::instance()->get_last_used_for_registration($this);
1889
+	}
1890
+
1891
+
1892
+	/**
1893
+	 * @return \EE_Line_Item
1894
+	 * @throws EntityNotFoundException
1895
+	 * @throws EE_Error
1896
+	 */
1897
+	public function ticket_line_item()
1898
+	{
1899
+		$ticket = $this->ticket();
1900
+		$transaction = $this->transaction();
1901
+		$line_item = null;
1902
+		$ticket_line_items = \EEH_Line_Item::get_line_items_by_object_type_and_IDs(
1903
+			$transaction->total_line_item(),
1904
+			'Ticket',
1905
+			array($ticket->ID())
1906
+		);
1907
+		foreach ($ticket_line_items as $ticket_line_item) {
1908
+			if ($ticket_line_item instanceof \EE_Line_Item
1909
+				&& $ticket_line_item->OBJ_type() === 'Ticket'
1910
+				&& $ticket_line_item->OBJ_ID() === $ticket->ID()
1911
+			) {
1912
+				$line_item = $ticket_line_item;
1913
+				break;
1914
+			}
1915
+		}
1916
+		if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
1917
+			throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
1918
+		}
1919
+		return $line_item;
1920
+	}
1921
+
1922
+
1923
+	/**
1924
+	 * Soft Deletes this model object.
1925
+	 *
1926
+	 * @return boolean | int
1927
+	 * @throws RuntimeException
1928
+	 * @throws EE_Error
1929
+	 */
1930
+	public function delete()
1931
+	{
1932
+		if ($this->update_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY, $this->status_ID()) === true) {
1933
+			$this->set_status(EEM_Registration::status_id_cancelled);
1934
+		}
1935
+		return parent::delete();
1936
+	}
1937
+
1938
+
1939
+	/**
1940
+	 * Restores whatever the previous status was on a registration before it was trashed (if possible)
1941
+	 *
1942
+	 * @throws EE_Error
1943
+	 * @throws RuntimeException
1944
+	 */
1945
+	public function restore()
1946
+	{
1947
+		$previous_status = $this->get_extra_meta(
1948
+			EE_Registration::PRE_TRASH_REG_STATUS_KEY,
1949
+			true,
1950
+			EEM_Registration::status_id_cancelled
1951
+		);
1952
+		if ($previous_status) {
1953
+			$this->delete_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY);
1954
+			$this->set_status($previous_status);
1955
+		}
1956
+		return parent::restore();
1957
+	}
1958
+
1959
+
1960
+	/**
1961
+	 * possibly toggle Registration status based on comparison of REG_paid vs REG_final_price
1962
+	 *
1963
+	 * @param  boolean $trigger_set_status_logic EE_Registration::set_status() can trigger additional logic
1964
+	 *                                           depending on whether the reg status changes to or from "Approved"
1965
+	 * @return boolean whether the Registration status was updated
1966
+	 * @throws EE_Error
1967
+	 * @throws RuntimeException
1968
+	 */
1969
+	public function updateStatusBasedOnTotalPaid($trigger_set_status_logic = true)
1970
+	{
1971
+		$paid = $this->paid();
1972
+		$price = $this->final_price();
1973
+		switch (true) {
1974
+			// overpaid or paid
1975
+			case EEH_Money::compare_floats($paid, $price, '>'):
1976
+			case EEH_Money::compare_floats($paid, $price):
1977
+				$new_status = EEM_Registration::status_id_approved;
1978
+				break;
1979
+			//  underpaid
1980
+			case EEH_Money::compare_floats($paid, $price, '<'):
1981
+				$new_status = EEM_Registration::status_id_pending_payment;
1982
+				break;
1983
+			// uhhh Houston...
1984
+			default:
1985
+				throw new RuntimeException(
1986
+					esc_html__('The total paid calculation for this registration is inaccurate.', 'event_espresso')
1987
+				);
1988
+		}
1989
+		if ($new_status !== $this->status_ID()) {
1990
+			if ($trigger_set_status_logic) {
1991
+				return $this->set_status($new_status);
1992
+			}
1993
+			parent::set('STS_ID', $new_status);
1994
+			return true;
1995
+		}
1996
+		return false;
1997
+	}
1998
+
1999
+
2000
+	/*************************** DEPRECATED ***************************/
2001
+
2002
+
2003
+	/**
2004
+	 * @deprecated
2005
+	 * @since     4.7.0
2006
+	 * @access    public
2007
+	 */
2008
+	public function price_paid()
2009
+	{
2010
+		EE_Error::doing_it_wrong(
2011
+			'EE_Registration::price_paid()',
2012
+			esc_html__(
2013
+				'This method is deprecated, please use EE_Registration::final_price() instead.',
2014
+				'event_espresso'
2015
+			),
2016
+			'4.7.0'
2017
+		);
2018
+		return $this->final_price();
2019
+	}
2020
+
2021
+
2022
+	/**
2023
+	 * @deprecated
2024
+	 * @since     4.7.0
2025
+	 * @access    public
2026
+	 * @param    float $REG_final_price
2027
+	 * @throws EE_Error
2028
+	 * @throws RuntimeException
2029
+	 */
2030
+	public function set_price_paid($REG_final_price = 0.00)
2031
+	{
2032
+		EE_Error::doing_it_wrong(
2033
+			'EE_Registration::set_price_paid()',
2034
+			esc_html__(
2035
+				'This method is deprecated, please use EE_Registration::set_final_price() instead.',
2036
+				'event_espresso'
2037
+			),
2038
+			'4.7.0'
2039
+		);
2040
+		$this->set_final_price($REG_final_price);
2041
+	}
2042
+
2043
+
2044
+	/**
2045
+	 * @deprecated
2046
+	 * @since 4.7.0
2047
+	 * @return string
2048
+	 * @throws EE_Error
2049
+	 */
2050
+	public function pretty_price_paid()
2051
+	{
2052
+		EE_Error::doing_it_wrong(
2053
+			'EE_Registration::pretty_price_paid()',
2054
+			esc_html__(
2055
+				'This method is deprecated, please use EE_Registration::pretty_final_price() instead.',
2056
+				'event_espresso'
2057
+			),
2058
+			'4.7.0'
2059
+		);
2060
+		return $this->pretty_final_price();
2061
+	}
2062
+
2063
+
2064
+	/**
2065
+	 * Gets the primary datetime related to this registration via the related Event to this registration
2066
+	 *
2067
+	 * @deprecated 4.9.17
2068
+	 * @return EE_Datetime
2069
+	 * @throws EE_Error
2070
+	 * @throws EntityNotFoundException
2071
+	 */
2072
+	public function get_related_primary_datetime()
2073
+	{
2074
+		EE_Error::doing_it_wrong(
2075
+			__METHOD__,
2076
+			esc_html__(
2077
+				'Use EE_Registration::get_latest_related_datetime() or EE_Registration::get_earliest_related_datetime()',
2078
+				'event_espresso'
2079
+			),
2080
+			'4.9.17',
2081
+			'5.0.0'
2082
+		);
2083
+		return $this->event()->primary_datetime();
2084
+	}
2085 2085
 }
Please login to merge, or discard this patch.
caffeinated/admin/extend/about/templates/whats_new.template.php 2 patches
Indentation   +35 added lines, -35 removed lines patch added patch discarded remove patch
@@ -1,58 +1,58 @@
 block discarded – undo
1 1
 <div class="changelog point-releases">
2 2
     <!-- <h3><?php echo esc_html(
3
-        _n('Minor Release Information', 'Minor Releases', 1, 'event_espresso')
4
-    ); ?></h3> -->
3
+		_n('Minor Release Information', 'Minor Releases', 1, 'event_espresso')
4
+	); ?></h3> -->
5 5
     <h3><?php echo esc_html(
6
-        _n('Major Release Information', 'Major Releases', 1, 'event_espresso')
7
-    ); ?></h3>
6
+		_n('Major Release Information', 'Major Releases', 1, 'event_espresso')
7
+	); ?></h3>
8 8
     <?php // $type = 'minor'; ?>
9 9
     <?php $type = 'major'; ?>
10 10
     <p><?php
11
-        printf(
12
-            esc_html__('%1$sVersion %2$s%3$s is a %4$s release.', 'event_espresso'),
13
-            '<strong>',
14
-            EVENT_ESPRESSO_VERSION,
15
-            '</strong>',
16
-            $type
17
-        ); ?>
11
+		printf(
12
+			esc_html__('%1$sVersion %2$s%3$s is a %4$s release.', 'event_espresso'),
13
+			'<strong>',
14
+			EVENT_ESPRESSO_VERSION,
15
+			'</strong>',
16
+			$type
17
+		); ?>
18 18
         <?php
19
-        $ver = explode('.', EVENT_ESPRESSO_VERSION);
20
-        array_pop($ver);
21
-        $ver = implode('.', $ver);
22
-        ?>
19
+		$ver = explode('.', EVENT_ESPRESSO_VERSION);
20
+		array_pop($ver);
21
+		$ver = implode('.', $ver);
22
+		?>
23 23
         <?php printf(
24
-            esc_html__('For more information, see %1$sthe release notes%2$s.', 'event_espresso'),
25
-            '<a href="http://eventespresso.com/wiki/ee4-changelog/#' . $ver . '" target="_blank" rel="noopener noreferrer">',
26
-            '</a>'
27
-        ); ?>
24
+			esc_html__('For more information, see %1$sthe release notes%2$s.', 'event_espresso'),
25
+			'<a href="http://eventespresso.com/wiki/ee4-changelog/#' . $ver . '" target="_blank" rel="noopener noreferrer">',
26
+			'</a>'
27
+		); ?>
28 28
     </p>
29 29
 </div><!-- end .changelog .point-releases -->
30 30
 
31 31
 <div class="changelog">
32 32
     <?php
33
-    // maintenance mode on?
34
-    if (EE_Maintenance_Mode::instance()->level() == EE_Maintenance_Mode::level_2_complete_maintenance) {
35
-        ?>
33
+	// maintenance mode on?
34
+	if (EE_Maintenance_Mode::instance()->level() == EE_Maintenance_Mode::level_2_complete_maintenance) {
35
+		?>
36 36
         <div class="ee-attention">
37 37
             <h2 class="ee-maintenance-mode-callout"><?php
38
-                esc_html_e('Event Espresso is in full maintenance mode.', 'event_espresso');
39
-                ?></h2>
38
+				esc_html_e('Event Espresso is in full maintenance mode.', 'event_espresso');
39
+				?></h2>
40 40
             <p>
41 41
                 <?php
42
-                printf(
43
-                    esc_html__(
44
-                        'A previous version of Event Espresso has detected. But before anything else can happen, we need to know whether or not to migrate (copy over) your existing event data so that it can be utilized by EE4. For more instructions on what to do, please visit the %1$sEvent Espresso Maintenance%2$s page.',
45
-                        'event_espresso'
46
-                    ),
47
-                    '<a href="admin.php?page=espresso_maintenance_settings">',
48
-                    '</a>'
49
-                );
50
-                ?>
42
+				printf(
43
+					esc_html__(
44
+						'A previous version of Event Espresso has detected. But before anything else can happen, we need to know whether or not to migrate (copy over) your existing event data so that it can be utilized by EE4. For more instructions on what to do, please visit the %1$sEvent Espresso Maintenance%2$s page.',
45
+						'event_espresso'
46
+					),
47
+					'<a href="admin.php?page=espresso_maintenance_settings">',
48
+					'</a>'
49
+				);
50
+				?>
51 51
             </p>
52 52
         </div>
53 53
         <?php
54
-    }
55
-    ?>
54
+	}
55
+	?>
56 56
 
57 57
     <h2 class="about-headline-callout">Updates &amp; Fixes in EE 4.10</h2>
58 58
     <p>This release brought many background updates/improvements to existing core features, and support for many new
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -22,7 +22,7 @@
 block discarded – undo
22 22
         ?>
23 23
         <?php printf(
24 24
             esc_html__('For more information, see %1$sthe release notes%2$s.', 'event_espresso'),
25
-            '<a href="http://eventespresso.com/wiki/ee4-changelog/#' . $ver . '" target="_blank" rel="noopener noreferrer">',
25
+            '<a href="http://eventespresso.com/wiki/ee4-changelog/#'.$ver.'" target="_blank" rel="noopener noreferrer">',
26 26
             '</a>'
27 27
         ); ?>
28 28
     </p>
Please login to merge, or discard this patch.
payment_methods/Paypal_Express/EEG_Paypal_Express.gateway.php 1 patch
Indentation   +666 added lines, -666 removed lines patch added patch discarded remove patch
@@ -11,674 +11,674 @@
 block discarded – undo
11 11
  */
12 12
 // Quickfix to address https://events.codebasehq.com/projects/event-espresso/tickets/11089 ASAP
13 13
 if (! function_exists('mb_strcut')) {
14
-    /**
15
-     * Very simple mimic of mb_substr (which WP ensures exists in wp-includes/compat.php). Still has all the problems of mb_substr
16
-     * (namely, that we might send too many characters to PayPal; however in this case they just issue a warning but nothing breaks)
17
-     * @param $string
18
-     * @param $start
19
-     * @param $length
20
-     * @return bool|string
21
-     */
22
-    function mb_strcut($string, $start, $length = null)
23
-    {
24
-        return mb_substr($string, $start, $length);
25
-    }
14
+	/**
15
+	 * Very simple mimic of mb_substr (which WP ensures exists in wp-includes/compat.php). Still has all the problems of mb_substr
16
+	 * (namely, that we might send too many characters to PayPal; however in this case they just issue a warning but nothing breaks)
17
+	 * @param $string
18
+	 * @param $start
19
+	 * @param $length
20
+	 * @return bool|string
21
+	 */
22
+	function mb_strcut($string, $start, $length = null)
23
+	{
24
+		return mb_substr($string, $start, $length);
25
+	}
26 26
 }
27 27
 class EEG_Paypal_Express extends EE_Offsite_Gateway
28 28
 {
29 29
 
30
-    /**
31
-     * Merchant API Username.
32
-     *
33
-     * @var string
34
-     */
35
-    protected $_api_username;
36
-
37
-    /**
38
-     * Merchant API Password.
39
-     *
40
-     * @var string
41
-     */
42
-    protected $_api_password;
43
-
44
-    /**
45
-     * API Signature.
46
-     *
47
-     * @var string
48
-     */
49
-    protected $_api_signature;
50
-
51
-    /**
52
-     * Request Shipping address on PP checkout page.
53
-     *
54
-     * @var string
55
-     */
56
-    protected $_request_shipping_addr;
57
-
58
-    /**
59
-     * Business/personal logo.
60
-     *
61
-     * @var string
62
-     */
63
-    protected $_image_url;
64
-
65
-    /**
66
-     * gateway URL variable
67
-     *
68
-     * @var string
69
-     */
70
-    protected $_base_gateway_url = '';
71
-
72
-
73
-
74
-    /**
75
-     * EEG_Paypal_Express constructor.
76
-     */
77
-    public function __construct()
78
-    {
79
-        $this->_currencies_supported = array(
80
-            'USD',
81
-            'AUD',
82
-            'BRL',
83
-            'CAD',
84
-            'CZK',
85
-            'DKK',
86
-            'EUR',
87
-            'HKD',
88
-            'HUF',
89
-            'ILS',
90
-            'JPY',
91
-            'MYR',
92
-            'MXN',
93
-            'NOK',
94
-            'NZD',
95
-            'PHP',
96
-            'PLN',
97
-            'GBP',
98
-            'RUB',
99
-            'SGD',
100
-            'SEK',
101
-            'CHF',
102
-            'TWD',
103
-            'THB',
104
-            'TRY',
105
-            'INR',
106
-        );
107
-        parent::__construct();
108
-    }
109
-
110
-
111
-
112
-    /**
113
-     * Sets the gateway URL variable based on whether debug mode is enabled or not.
114
-     *
115
-     * @param array $settings_array
116
-     */
117
-    public function set_settings($settings_array)
118
-    {
119
-        parent::set_settings($settings_array);
120
-        // Redirect URL.
121
-        $this->_base_gateway_url = $this->_debug_mode
122
-            ? 'https://api-3t.sandbox.paypal.com/nvp'
123
-            : 'https://api-3t.paypal.com/nvp';
124
-    }
125
-
126
-
127
-
128
-    /**
129
-     * @param EEI_Payment $payment
130
-     * @param array       $billing_info
131
-     * @param string      $return_url
132
-     * @param string      $notify_url
133
-     * @param string      $cancel_url
134
-     * @return \EE_Payment|\EEI_Payment
135
-     * @throws \EE_Error
136
-     */
137
-    public function set_redirection_info(
138
-        $payment,
139
-        $billing_info = array(),
140
-        $return_url = null,
141
-        $notify_url = null,
142
-        $cancel_url = null
143
-    ) {
144
-        if (! $payment instanceof EEI_Payment) {
145
-            $payment->set_gateway_response(
146
-                esc_html__(
147
-                    'Error. No associated payment was found.',
148
-                    'event_espresso'
149
-                )
150
-            );
151
-            $payment->set_status($this->_pay_model->failed_status());
152
-            return $payment;
153
-        }
154
-        $transaction = $payment->transaction();
155
-        if (! $transaction instanceof EEI_Transaction) {
156
-            $payment->set_gateway_response(
157
-                esc_html__(
158
-                    'Could not process this payment because it has no associated transaction.',
159
-                    'event_espresso'
160
-                )
161
-            );
162
-            $payment->set_status($this->_pay_model->failed_status());
163
-            return $payment;
164
-        }
165
-        $gateway_formatter = $this->_get_gateway_formatter();
166
-        $order_description = mb_strcut($gateway_formatter->formatOrderDescription($payment), 0, 127);
167
-        $primary_registration = $transaction->primary_registration();
168
-        $primary_attendee = $primary_registration instanceof EE_Registration
169
-            ? $primary_registration->attendee()
170
-            : false;
171
-        $locale = explode('-', get_bloginfo('language'));
172
-        // Gather request parameters.
173
-        $token_request_dtls = array(
174
-            'METHOD'                         => 'SetExpressCheckout',
175
-            'PAYMENTREQUEST_0_AMT'           => $payment->amount(),
176
-            'PAYMENTREQUEST_0_CURRENCYCODE'  => $payment->currency_code(),
177
-            'PAYMENTREQUEST_0_DESC'          => $order_description,
178
-            'RETURNURL'                      => $return_url,
179
-            'CANCELURL'                      => $cancel_url,
180
-            'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
181
-            // Buyer does not need to create a PayPal account to check out.
182
-            // This is referred to as PayPal Account Optional.
183
-            'SOLUTIONTYPE'                   => 'Sole',
184
-            // Locale of the pages displayed by PayPal during Express Checkout.
185
-            'LOCALECODE'                     => $locale[1]
186
-        );
187
-        // Show itemized list.
188
-        $itemized_list = $this->itemize_list($payment, $transaction);
189
-        $token_request_dtls = array_merge($token_request_dtls, $itemized_list);
190
-        // Automatically filling out shipping and contact information.
191
-        if ($this->_request_shipping_addr && $primary_attendee instanceof EEI_Attendee) {
192
-            // If you do not pass the shipping address, PayPal obtains it from the buyer's account profile.
193
-            $token_request_dtls['NOSHIPPING'] = '2';
194
-            $token_request_dtls['PAYMENTREQUEST_0_SHIPTOSTREET'] = $primary_attendee->address();
195
-            $token_request_dtls['PAYMENTREQUEST_0_SHIPTOSTREET2'] = $primary_attendee->address2();
196
-            $token_request_dtls['PAYMENTREQUEST_0_SHIPTOCITY'] = $primary_attendee->city();
197
-            $token_request_dtls['PAYMENTREQUEST_0_SHIPTOSTATE'] = $primary_attendee->state_abbrev();
198
-            $token_request_dtls['PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE'] = $primary_attendee->country_ID();
199
-            $token_request_dtls['PAYMENTREQUEST_0_SHIPTOZIP'] = $primary_attendee->zip();
200
-            $token_request_dtls['PAYMENTREQUEST_0_EMAIL'] = $primary_attendee->email();
201
-            $token_request_dtls['PAYMENTREQUEST_0_SHIPTOPHONENUM'] = $primary_attendee->phone();
202
-        } elseif (! $this->_request_shipping_addr) {
203
-            // Do not request shipping details on the PP Checkout page.
204
-            $token_request_dtls['NOSHIPPING'] = '1';
205
-            $token_request_dtls['REQCONFIRMSHIPPING'] = '0';
206
-        }
207
-        // Used a business/personal logo on the PayPal page.
208
-        if (! empty($this->_image_url)) {
209
-            $token_request_dtls['LOGOIMG'] = $this->_image_url;
210
-        }
211
-        $token_request_dtls = apply_filters(
212
-            'FHEE__EEG_Paypal_Express__set_redirection_info__arguments',
213
-            $token_request_dtls,
214
-            $this
215
-        );
216
-        // Request PayPal token.
217
-        $token_request_response = $this->_ppExpress_request($token_request_dtls, 'Payment Token', $payment);
218
-        $token_rstatus = $this->_ppExpress_check_response($token_request_response);
219
-        $response_args = (isset($token_rstatus['args']) && is_array($token_rstatus['args']))
220
-            ? $token_rstatus['args']
221
-            : array();
222
-        if ($token_rstatus['status']) {
223
-            // We got the Token so we may continue with the payment and redirect the client.
224
-            $payment->set_details($response_args);
225
-            $gateway_url = $this->_debug_mode ? 'https://www.sandbox.paypal.com' : 'https://www.paypal.com';
226
-            $payment->set_redirect_url(
227
-                $gateway_url
228
-                . '/checkoutnow?useraction=commit&cmd=_express-checkout&token='
229
-                . $response_args['TOKEN']
230
-            );
231
-        } else {
232
-            if (isset($response_args['L_ERRORCODE'])) {
233
-                $payment->set_gateway_response($response_args['L_ERRORCODE'] . '; ' . $response_args['L_SHORTMESSAGE']);
234
-            } else {
235
-                $payment->set_gateway_response(
236
-                    esc_html__(
237
-                        'Error occurred while trying to setup the Express Checkout.',
238
-                        'event_espresso'
239
-                    )
240
-                );
241
-            }
242
-            $payment->set_details($response_args);
243
-            $payment->set_status($this->_pay_model->failed_status());
244
-        }
245
-        return $payment;
246
-    }
247
-
248
-
249
-
250
-    /**
251
-     * @param array           $update_info {
252
-     * @type string           $gateway_txn_id
253
-     * @type string status an EEMI_Payment status
254
-     *                                     }
255
-     * @param EEI_Transaction $transaction
256
-     * @return EEI_Payment
257
-     */
258
-    public function handle_payment_update($update_info, $transaction)
259
-    {
260
-        $payment = $transaction instanceof EEI_Transaction ? $transaction->last_payment() : null;
261
-        if ($payment instanceof EEI_Payment) {
262
-            $this->log(array('Return from Authorization' => $update_info), $payment);
263
-            $transaction = $payment->transaction();
264
-            if (! $transaction instanceof EEI_Transaction) {
265
-                $payment->set_gateway_response(
266
-                    esc_html__(
267
-                        'Could not process this payment because it has no associated transaction.',
268
-                        'event_espresso'
269
-                    )
270
-                );
271
-                $payment->set_status($this->_pay_model->failed_status());
272
-                return $payment;
273
-            }
274
-            $primary_registrant = $transaction->primary_registration();
275
-            $payment_details = $payment->details();
276
-            // Check if we still have the token.
277
-            if (! isset($payment_details['TOKEN']) || empty($payment_details['TOKEN'])) {
278
-                $payment->set_status($this->_pay_model->failed_status());
279
-                return $payment;
280
-            }
281
-            $cdetails_request_dtls = array(
282
-                'METHOD' => 'GetExpressCheckoutDetails',
283
-                'TOKEN'  => $payment_details['TOKEN'],
284
-            );
285
-            // Request Customer Details.
286
-            $cdetails_request_response = $this->_ppExpress_request(
287
-                $cdetails_request_dtls,
288
-                'Customer Details',
289
-                $payment
290
-            );
291
-            $cdetails_rstatus = $this->_ppExpress_check_response($cdetails_request_response);
292
-            $cdata_response_args = (isset($cdetails_rstatus['args']) && is_array($cdetails_rstatus['args']))
293
-                ? $cdetails_rstatus['args']
294
-                : array();
295
-            if ($cdetails_rstatus['status']) {
296
-                // We got the PayerID so now we can Complete the transaction.
297
-                $docheckout_request_dtls = array(
298
-                    'METHOD'                         => 'DoExpressCheckoutPayment',
299
-                    'PAYERID'                        => $cdata_response_args['PAYERID'],
300
-                    'TOKEN'                          => $payment_details['TOKEN'],
301
-                    'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
302
-                    'PAYMENTREQUEST_0_AMT'           => $payment->amount(),
303
-                    'PAYMENTREQUEST_0_CURRENCYCODE'  => $payment->currency_code(),
304
-                );
305
-                 // Include itemized list.
306
-                $itemized_list = $this->itemize_list(
307
-                    $payment,
308
-                    $transaction,
309
-                    $cdata_response_args
310
-                );
311
-                $docheckout_request_dtls = array_merge($docheckout_request_dtls, $itemized_list);
312
-                // Payment Checkout/Capture.
313
-                $docheckout_request_response = $this->_ppExpress_request(
314
-                    $docheckout_request_dtls,
315
-                    'Do Payment',
316
-                    $payment
317
-                );
318
-                $docheckout_rstatus = $this->_ppExpress_check_response($docheckout_request_response);
319
-                $docheckout_response_args = (isset($docheckout_rstatus['args']) && is_array($docheckout_rstatus['args']))
320
-                    ? $docheckout_rstatus['args']
321
-                    : array();
322
-                if ($docheckout_rstatus['status']) {
323
-                    // All is well, payment approved.
324
-                    $primary_registration_code = $primary_registrant instanceof EE_Registration ?
325
-                        $primary_registrant->reg_code()
326
-                        : '';
327
-                    $payment->set_extra_accntng($primary_registration_code);
328
-                    $payment->set_amount(isset($docheckout_response_args['PAYMENTINFO_0_AMT'])
329
-                        ? (float) $docheckout_response_args['PAYMENTINFO_0_AMT']
330
-                        : 0);
331
-                    $payment->set_txn_id_chq_nmbr(isset($docheckout_response_args['PAYMENTINFO_0_TRANSACTIONID'])
332
-                        ? $docheckout_response_args['PAYMENTINFO_0_TRANSACTIONID']
333
-                        : null);
334
-                    $payment->set_details($cdata_response_args);
335
-                    $payment->set_gateway_response(isset($docheckout_response_args['PAYMENTINFO_0_ACK'])
336
-                        ? $docheckout_response_args['PAYMENTINFO_0_ACK']
337
-                        : '');
338
-                    $payment->set_status($this->_pay_model->approved_status());
339
-                } else {
340
-                    if (isset($docheckout_response_args['L_ERRORCODE'])) {
341
-                        $payment->set_gateway_response(
342
-                            $docheckout_response_args['L_ERRORCODE']
343
-                            . '; '
344
-                            . $docheckout_response_args['L_SHORTMESSAGE']
345
-                        );
346
-                    } else {
347
-                        $payment->set_gateway_response(
348
-                            esc_html__(
349
-                                'Error occurred while trying to Capture the funds.',
350
-                                'event_espresso'
351
-                            )
352
-                        );
353
-                    }
354
-                    $payment->set_details($docheckout_response_args);
355
-                    $payment->set_status($this->_pay_model->declined_status());
356
-                }
357
-            } else {
358
-                if (isset($cdata_response_args['L_ERRORCODE'])) {
359
-                    $payment->set_gateway_response(
360
-                        $cdata_response_args['L_ERRORCODE']
361
-                        . '; '
362
-                        . $cdata_response_args['L_SHORTMESSAGE']
363
-                    );
364
-                } else {
365
-                    $payment->set_gateway_response(
366
-                        esc_html__(
367
-                            'Error occurred while trying to get payment Details from PayPal.',
368
-                            'event_espresso'
369
-                        )
370
-                    );
371
-                }
372
-                $payment->set_details($cdata_response_args);
373
-                $payment->set_status($this->_pay_model->failed_status());
374
-            }
375
-        } else {
376
-            $payment->set_gateway_response(
377
-                esc_html__(
378
-                    'Error occurred while trying to process the payment.',
379
-                    'event_espresso'
380
-                )
381
-            );
382
-            $payment->set_status($this->_pay_model->failed_status());
383
-        }
384
-        return $payment;
385
-    }
386
-
387
-
388
-
389
-    /**
390
-     *  Make a list of items that are in the giver transaction.
391
-     *
392
-     * @param EEI_Payment     $payment
393
-     * @param EEI_Transaction $transaction
394
-     * @param array           $request_response_args Data from a previous communication with PP.
395
-     * @return array
396
-     */
397
-    public function itemize_list(EEI_Payment $payment, EEI_Transaction $transaction, $request_response_args = array())
398
-    {
399
-        $itemized_list = array();
400
-        $gateway_formatter = $this->_get_gateway_formatter();
401
-        // If we have data from a previous communication with PP (on this transaction) we may use that for our list...
402
-        if (! empty($request_response_args)
403
-            && array_key_exists('L_PAYMENTREQUEST_0_AMT0', $request_response_args)
404
-            && array_key_exists('PAYMENTREQUEST_0_ITEMAMT', $request_response_args)
405
-        ) {
406
-            foreach ($request_response_args as $arg_key => $arg_val) {
407
-                if (strpos($arg_key, 'PAYMENTREQUEST_') !== false
408
-                    && strpos($arg_key, 'NOTIFYURL') === false
409
-                ) {
410
-                    $itemized_list[ $arg_key ] = $arg_val;
411
-                }
412
-            }
413
-            // If we got only a few Items then something is not right.
414
-            if (count($itemized_list) > 2) {
415
-                return $itemized_list;
416
-            } else {
417
-                if (WP_DEBUG) {
418
-                    throw new EE_Error(
419
-                        sprintf(
420
-                            esc_html__(
421
-                                // @codingStandardsIgnoreStart
422
-                                'Unable to continue with the checkout because a proper purchase list could not be generated. The purchased list we could have sent was %1$s',
423
-                                // @codingStandardsIgnoreEnd
424
-                                'event_espresso'
425
-                            ),
426
-                            wp_json_encode($itemized_list)
427
-                        )
428
-                    );
429
-                }
430
-                // Reset the list and log an error, maybe allow to try and generate a new list (below).
431
-                $itemized_list = array();
432
-                $this->log(
433
-                    array(
434
-                        (string) esc_html__(
435
-                            'Could not generate a proper item list with:',
436
-                            'event_espresso'
437
-                        ) => $request_response_args
438
-                    ),
439
-                    $payment
440
-                );
441
-            }
442
-        }
443
-        // ...otherwise we generate a new list for this transaction.
444
-        if ($this->_money->compare_floats($payment->amount(), $transaction->total(), '==')) {
445
-            $item_num = 0;
446
-            $itemized_sum = 0;
447
-            $total_line_items = $transaction->total_line_item();
448
-            // Go through each item in the list.
449
-            foreach ($total_line_items->get_items() as $line_item) {
450
-                if ($line_item instanceof EE_Line_Item) {
451
-                    // PayPal doesn't like line items with 0.00 amount, so we may skip those.
452
-                    if (EEH_Money::compare_floats($line_item->total(), '0.00', '==')) {
453
-                        continue;
454
-                    }
455
-                    $unit_price = $line_item->unit_price();
456
-                    $line_item_quantity = $line_item->quantity();
457
-                    // This is a discount.
458
-                    if ($line_item->is_percent()) {
459
-                        $unit_price = $line_item->total();
460
-                        $line_item_quantity = 1;
461
-                    }
462
-                    // Item Name.
463
-                    $itemized_list[ 'L_PAYMENTREQUEST_0_NAME' . $item_num ] = mb_strcut(
464
-                        $gateway_formatter->formatLineItemName($line_item, $payment),
465
-                        0,
466
-                        127
467
-                    );
468
-                    // Item description.
469
-                    $itemized_list[ 'L_PAYMENTREQUEST_0_DESC' . $item_num ] = mb_strcut(
470
-                        $gateway_formatter->formatLineItemDesc($line_item, $payment),
471
-                        0,
472
-                        127
473
-                    );
474
-                    // Cost of individual item.
475
-                    $itemized_list[ 'L_PAYMENTREQUEST_0_AMT' . $item_num ] = $gateway_formatter->formatCurrency($unit_price);
476
-                    // Item Number.
477
-                    $itemized_list[ 'L_PAYMENTREQUEST_0_NUMBER' . $item_num ] = $item_num + 1;
478
-                    // Item quantity.
479
-                    $itemized_list[ 'L_PAYMENTREQUEST_0_QTY' . $item_num ] = $line_item_quantity;
480
-                    // Digital item is sold.
481
-                    $itemized_list[ 'L_PAYMENTREQUEST_0_ITEMCATEGORY' . $item_num ] = 'Physical';
482
-                    $itemized_sum += $line_item->total();
483
-                    ++$item_num;
484
-                }
485
-            }
486
-            // Item's sales S/H and tax amount.
487
-            $itemized_list['PAYMENTREQUEST_0_ITEMAMT'] = $total_line_items->get_items_total();
488
-            $itemized_list['PAYMENTREQUEST_0_TAXAMT'] = $total_line_items->get_total_tax();
489
-            $itemized_list['PAYMENTREQUEST_0_SHIPPINGAMT'] = '0';
490
-            $itemized_list['PAYMENTREQUEST_0_HANDLINGAMT'] = '0';
491
-            $itemized_sum_diff_from_txn_total = round(
492
-                $transaction->total() - $itemized_sum - $total_line_items->get_total_tax(),
493
-                2
494
-            );
495
-            // If we were not able to recognize some item like promotion, surcharge or cancellation,
496
-            // add the difference as an extra line item.
497
-            if ($this->_money->compare_floats($itemized_sum_diff_from_txn_total, 0, '!=')) {
498
-                // Item Name.
499
-                $itemized_list[ 'L_PAYMENTREQUEST_0_NAME' . $item_num ] = mb_strcut(
500
-                    esc_html__(
501
-                        'Other (promotion/surcharge/cancellation)',
502
-                        'event_espresso'
503
-                    ),
504
-                    0,
505
-                    127
506
-                );
507
-                // Item description.
508
-                $itemized_list[ 'L_PAYMENTREQUEST_0_DESC' . $item_num ] = '';
509
-                // Cost of individual item.
510
-                $itemized_list[ 'L_PAYMENTREQUEST_0_AMT' . $item_num ] = $gateway_formatter->formatCurrency(
511
-                    $itemized_sum_diff_from_txn_total
512
-                );
513
-                // Item Number.
514
-                $itemized_list[ 'L_PAYMENTREQUEST_0_NUMBER' . $item_num ] = $item_num + 1;
515
-                // Item quantity.
516
-                $itemized_list[ 'L_PAYMENTREQUEST_0_QTY' . $item_num ] = 1;
517
-                // Digital item is sold.
518
-                $itemized_list[ 'L_PAYMENTREQUEST_0_ITEMCATEGORY' . $item_num ] = 'Physical';
519
-                $item_num++;
520
-            }
521
-        } else {
522
-            // Just one Item.
523
-            // Item Name.
524
-            $itemized_list['L_PAYMENTREQUEST_0_NAME0'] = mb_strcut(
525
-                $gateway_formatter->formatPartialPaymentLineItemName($payment),
526
-                0,
527
-                127
528
-            );
529
-            // Item description.
530
-            $itemized_list['L_PAYMENTREQUEST_0_DESC0'] = mb_strcut(
531
-                $gateway_formatter->formatPartialPaymentLineItemDesc($payment),
532
-                0,
533
-                127
534
-            );
535
-            // Cost of individual item.
536
-            $itemized_list['L_PAYMENTREQUEST_0_AMT0'] = $gateway_formatter->formatCurrency($payment->amount());
537
-            // Item Number.
538
-            $itemized_list['L_PAYMENTREQUEST_0_NUMBER0'] = 1;
539
-            // Item quantity.
540
-            $itemized_list['L_PAYMENTREQUEST_0_QTY0'] = 1;
541
-            // Digital item is sold.
542
-            $itemized_list['L_PAYMENTREQUEST_0_ITEMCATEGORY0'] = 'Physical';
543
-            // Item's sales S/H and tax amount.
544
-            $itemized_list['PAYMENTREQUEST_0_ITEMAMT'] = $gateway_formatter->formatCurrency($payment->amount());
545
-            $itemized_list['PAYMENTREQUEST_0_TAXAMT'] = '0';
546
-            $itemized_list['PAYMENTREQUEST_0_SHIPPINGAMT'] = '0';
547
-            $itemized_list['PAYMENTREQUEST_0_HANDLINGAMT'] = '0';
548
-        }
549
-        return $itemized_list;
550
-    }
551
-
552
-
553
-
554
-    /**
555
-     *  Make the Express checkout request.
556
-     *
557
-     * @param array       $request_params
558
-     * @param string      $request_text
559
-     * @param EEI_Payment $payment
560
-     * @return mixed
561
-     */
562
-    public function _ppExpress_request($request_params, $request_text, $payment)
563
-    {
564
-        $request_dtls = array(
565
-            'VERSION' => '204.0',
566
-            'USER' => $this->_api_username,
567
-            'PWD' => $this->_api_password,
568
-            'SIGNATURE' => $this->_api_signature,
569
-            // EE will blow up if you change this
570
-            'BUTTONSOURCE' => 'EventEspresso_SP',
571
-        );
572
-        $dtls = array_merge($request_dtls, $request_params);
573
-        $this->_log_clean_request($dtls, $payment, $request_text . ' Request');
574
-        // Request Customer Details.
575
-        $request_response = wp_remote_post(
576
-            $this->_base_gateway_url,
577
-            array(
578
-                'method'      => 'POST',
579
-                'timeout'     => 45,
580
-                'httpversion' => '1.1',
581
-                'cookies'     => array(),
582
-                'headers'     => array(),
583
-                'body'        => http_build_query($dtls, '', '&'),
584
-            )
585
-        );
586
-        // Log the response.
587
-        $this->log(array($request_text . ' Response' => $request_response), $payment);
588
-        return $request_response;
589
-    }
590
-
591
-
592
-
593
-    /**
594
-     *  Check the response status.
595
-     *
596
-     * @param mixed $request_response
597
-     * @return array
598
-     */
599
-    public function _ppExpress_check_response($request_response)
600
-    {
601
-        if (is_wp_error($request_response) || empty($request_response['body'])) {
602
-            // If we got here then there was an error in this request.
603
-            return array('status' => false, 'args' => $request_response);
604
-        }
605
-        $response_args = array();
606
-        parse_str(urldecode($request_response['body']), $response_args);
607
-        if (! isset($response_args['ACK'])) {
608
-            return array('status' => false, 'args' => $request_response);
609
-        }
610
-        if ((
611
-                isset($response_args['PAYERID'])
612
-                || isset($response_args['TOKEN'])
613
-                || isset($response_args['PAYMENTINFO_0_TRANSACTIONID'])
614
-                || (isset($response_args['PAYMENTSTATUS']) && $response_args['PAYMENTSTATUS'] === 'Completed')
615
-            )
616
-            && in_array($response_args['ACK'], array('Success', 'SuccessWithWarning'), true)
617
-        ) {
618
-            // Response status OK, return response parameters for further processing.
619
-            return array('status' => true, 'args' => $response_args);
620
-        }
621
-        $errors = $this->_get_errors($response_args);
622
-        return array('status' => false, 'args' => $errors);
623
-    }
624
-
625
-
626
-
627
-    /**
628
-     *  Log a "Cleared" request.
629
-     *
630
-     * @param array       $request
631
-     * @param EEI_Payment $payment
632
-     * @param string      $info
633
-     * @return void
634
-     */
635
-    private function _log_clean_request($request, $payment, $info)
636
-    {
637
-        $cleaned_request_data = $request;
638
-        unset($cleaned_request_data['PWD'], $cleaned_request_data['USER'], $cleaned_request_data['SIGNATURE']);
639
-        $this->log(array($info => $cleaned_request_data), $payment);
640
-    }
641
-
642
-
643
-
644
-    /**
645
-     *  Get error from the response data.
646
-     *
647
-     * @param array $data_array
648
-     * @return array
649
-     */
650
-    private function _get_errors($data_array)
651
-    {
652
-        $errors = array();
653
-        $n = 0;
654
-        while (isset($data_array[ "L_ERRORCODE{$n}" ])) {
655
-            $l_error_code = isset($data_array[ "L_ERRORCODE{$n}" ])
656
-                ? $data_array[ "L_ERRORCODE{$n}" ]
657
-                : '';
658
-            $l_severity_code = isset($data_array[ "L_SEVERITYCODE{$n}" ])
659
-                ? $data_array[ "L_SEVERITYCODE{$n}" ]
660
-                : '';
661
-            $l_short_message = isset($data_array[ "L_SHORTMESSAGE{$n}" ])
662
-                ? $data_array[ "L_SHORTMESSAGE{$n}" ]
663
-                : '';
664
-            $l_long_message = isset($data_array[ "L_LONGMESSAGE{$n}" ])
665
-                ? $data_array[ "L_LONGMESSAGE{$n}" ]
666
-                : '';
667
-            if ($n === 0) {
668
-                $errors = array(
669
-                    'L_ERRORCODE'    => $l_error_code,
670
-                    'L_SHORTMESSAGE' => $l_short_message,
671
-                    'L_LONGMESSAGE'  => $l_long_message,
672
-                    'L_SEVERITYCODE' => $l_severity_code,
673
-                );
674
-            } else {
675
-                $errors['L_ERRORCODE'] .= ', ' . $l_error_code;
676
-                $errors['L_SHORTMESSAGE'] .= ', ' . $l_short_message;
677
-                $errors['L_LONGMESSAGE'] .= ', ' . $l_long_message;
678
-                $errors['L_SEVERITYCODE'] .= ', ' . $l_severity_code;
679
-            }
680
-            $n++;
681
-        }
682
-        return $errors;
683
-    }
30
+	/**
31
+	 * Merchant API Username.
32
+	 *
33
+	 * @var string
34
+	 */
35
+	protected $_api_username;
36
+
37
+	/**
38
+	 * Merchant API Password.
39
+	 *
40
+	 * @var string
41
+	 */
42
+	protected $_api_password;
43
+
44
+	/**
45
+	 * API Signature.
46
+	 *
47
+	 * @var string
48
+	 */
49
+	protected $_api_signature;
50
+
51
+	/**
52
+	 * Request Shipping address on PP checkout page.
53
+	 *
54
+	 * @var string
55
+	 */
56
+	protected $_request_shipping_addr;
57
+
58
+	/**
59
+	 * Business/personal logo.
60
+	 *
61
+	 * @var string
62
+	 */
63
+	protected $_image_url;
64
+
65
+	/**
66
+	 * gateway URL variable
67
+	 *
68
+	 * @var string
69
+	 */
70
+	protected $_base_gateway_url = '';
71
+
72
+
73
+
74
+	/**
75
+	 * EEG_Paypal_Express constructor.
76
+	 */
77
+	public function __construct()
78
+	{
79
+		$this->_currencies_supported = array(
80
+			'USD',
81
+			'AUD',
82
+			'BRL',
83
+			'CAD',
84
+			'CZK',
85
+			'DKK',
86
+			'EUR',
87
+			'HKD',
88
+			'HUF',
89
+			'ILS',
90
+			'JPY',
91
+			'MYR',
92
+			'MXN',
93
+			'NOK',
94
+			'NZD',
95
+			'PHP',
96
+			'PLN',
97
+			'GBP',
98
+			'RUB',
99
+			'SGD',
100
+			'SEK',
101
+			'CHF',
102
+			'TWD',
103
+			'THB',
104
+			'TRY',
105
+			'INR',
106
+		);
107
+		parent::__construct();
108
+	}
109
+
110
+
111
+
112
+	/**
113
+	 * Sets the gateway URL variable based on whether debug mode is enabled or not.
114
+	 *
115
+	 * @param array $settings_array
116
+	 */
117
+	public function set_settings($settings_array)
118
+	{
119
+		parent::set_settings($settings_array);
120
+		// Redirect URL.
121
+		$this->_base_gateway_url = $this->_debug_mode
122
+			? 'https://api-3t.sandbox.paypal.com/nvp'
123
+			: 'https://api-3t.paypal.com/nvp';
124
+	}
125
+
126
+
127
+
128
+	/**
129
+	 * @param EEI_Payment $payment
130
+	 * @param array       $billing_info
131
+	 * @param string      $return_url
132
+	 * @param string      $notify_url
133
+	 * @param string      $cancel_url
134
+	 * @return \EE_Payment|\EEI_Payment
135
+	 * @throws \EE_Error
136
+	 */
137
+	public function set_redirection_info(
138
+		$payment,
139
+		$billing_info = array(),
140
+		$return_url = null,
141
+		$notify_url = null,
142
+		$cancel_url = null
143
+	) {
144
+		if (! $payment instanceof EEI_Payment) {
145
+			$payment->set_gateway_response(
146
+				esc_html__(
147
+					'Error. No associated payment was found.',
148
+					'event_espresso'
149
+				)
150
+			);
151
+			$payment->set_status($this->_pay_model->failed_status());
152
+			return $payment;
153
+		}
154
+		$transaction = $payment->transaction();
155
+		if (! $transaction instanceof EEI_Transaction) {
156
+			$payment->set_gateway_response(
157
+				esc_html__(
158
+					'Could not process this payment because it has no associated transaction.',
159
+					'event_espresso'
160
+				)
161
+			);
162
+			$payment->set_status($this->_pay_model->failed_status());
163
+			return $payment;
164
+		}
165
+		$gateway_formatter = $this->_get_gateway_formatter();
166
+		$order_description = mb_strcut($gateway_formatter->formatOrderDescription($payment), 0, 127);
167
+		$primary_registration = $transaction->primary_registration();
168
+		$primary_attendee = $primary_registration instanceof EE_Registration
169
+			? $primary_registration->attendee()
170
+			: false;
171
+		$locale = explode('-', get_bloginfo('language'));
172
+		// Gather request parameters.
173
+		$token_request_dtls = array(
174
+			'METHOD'                         => 'SetExpressCheckout',
175
+			'PAYMENTREQUEST_0_AMT'           => $payment->amount(),
176
+			'PAYMENTREQUEST_0_CURRENCYCODE'  => $payment->currency_code(),
177
+			'PAYMENTREQUEST_0_DESC'          => $order_description,
178
+			'RETURNURL'                      => $return_url,
179
+			'CANCELURL'                      => $cancel_url,
180
+			'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
181
+			// Buyer does not need to create a PayPal account to check out.
182
+			// This is referred to as PayPal Account Optional.
183
+			'SOLUTIONTYPE'                   => 'Sole',
184
+			// Locale of the pages displayed by PayPal during Express Checkout.
185
+			'LOCALECODE'                     => $locale[1]
186
+		);
187
+		// Show itemized list.
188
+		$itemized_list = $this->itemize_list($payment, $transaction);
189
+		$token_request_dtls = array_merge($token_request_dtls, $itemized_list);
190
+		// Automatically filling out shipping and contact information.
191
+		if ($this->_request_shipping_addr && $primary_attendee instanceof EEI_Attendee) {
192
+			// If you do not pass the shipping address, PayPal obtains it from the buyer's account profile.
193
+			$token_request_dtls['NOSHIPPING'] = '2';
194
+			$token_request_dtls['PAYMENTREQUEST_0_SHIPTOSTREET'] = $primary_attendee->address();
195
+			$token_request_dtls['PAYMENTREQUEST_0_SHIPTOSTREET2'] = $primary_attendee->address2();
196
+			$token_request_dtls['PAYMENTREQUEST_0_SHIPTOCITY'] = $primary_attendee->city();
197
+			$token_request_dtls['PAYMENTREQUEST_0_SHIPTOSTATE'] = $primary_attendee->state_abbrev();
198
+			$token_request_dtls['PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE'] = $primary_attendee->country_ID();
199
+			$token_request_dtls['PAYMENTREQUEST_0_SHIPTOZIP'] = $primary_attendee->zip();
200
+			$token_request_dtls['PAYMENTREQUEST_0_EMAIL'] = $primary_attendee->email();
201
+			$token_request_dtls['PAYMENTREQUEST_0_SHIPTOPHONENUM'] = $primary_attendee->phone();
202
+		} elseif (! $this->_request_shipping_addr) {
203
+			// Do not request shipping details on the PP Checkout page.
204
+			$token_request_dtls['NOSHIPPING'] = '1';
205
+			$token_request_dtls['REQCONFIRMSHIPPING'] = '0';
206
+		}
207
+		// Used a business/personal logo on the PayPal page.
208
+		if (! empty($this->_image_url)) {
209
+			$token_request_dtls['LOGOIMG'] = $this->_image_url;
210
+		}
211
+		$token_request_dtls = apply_filters(
212
+			'FHEE__EEG_Paypal_Express__set_redirection_info__arguments',
213
+			$token_request_dtls,
214
+			$this
215
+		);
216
+		// Request PayPal token.
217
+		$token_request_response = $this->_ppExpress_request($token_request_dtls, 'Payment Token', $payment);
218
+		$token_rstatus = $this->_ppExpress_check_response($token_request_response);
219
+		$response_args = (isset($token_rstatus['args']) && is_array($token_rstatus['args']))
220
+			? $token_rstatus['args']
221
+			: array();
222
+		if ($token_rstatus['status']) {
223
+			// We got the Token so we may continue with the payment and redirect the client.
224
+			$payment->set_details($response_args);
225
+			$gateway_url = $this->_debug_mode ? 'https://www.sandbox.paypal.com' : 'https://www.paypal.com';
226
+			$payment->set_redirect_url(
227
+				$gateway_url
228
+				. '/checkoutnow?useraction=commit&cmd=_express-checkout&token='
229
+				. $response_args['TOKEN']
230
+			);
231
+		} else {
232
+			if (isset($response_args['L_ERRORCODE'])) {
233
+				$payment->set_gateway_response($response_args['L_ERRORCODE'] . '; ' . $response_args['L_SHORTMESSAGE']);
234
+			} else {
235
+				$payment->set_gateway_response(
236
+					esc_html__(
237
+						'Error occurred while trying to setup the Express Checkout.',
238
+						'event_espresso'
239
+					)
240
+				);
241
+			}
242
+			$payment->set_details($response_args);
243
+			$payment->set_status($this->_pay_model->failed_status());
244
+		}
245
+		return $payment;
246
+	}
247
+
248
+
249
+
250
+	/**
251
+	 * @param array           $update_info {
252
+	 * @type string           $gateway_txn_id
253
+	 * @type string status an EEMI_Payment status
254
+	 *                                     }
255
+	 * @param EEI_Transaction $transaction
256
+	 * @return EEI_Payment
257
+	 */
258
+	public function handle_payment_update($update_info, $transaction)
259
+	{
260
+		$payment = $transaction instanceof EEI_Transaction ? $transaction->last_payment() : null;
261
+		if ($payment instanceof EEI_Payment) {
262
+			$this->log(array('Return from Authorization' => $update_info), $payment);
263
+			$transaction = $payment->transaction();
264
+			if (! $transaction instanceof EEI_Transaction) {
265
+				$payment->set_gateway_response(
266
+					esc_html__(
267
+						'Could not process this payment because it has no associated transaction.',
268
+						'event_espresso'
269
+					)
270
+				);
271
+				$payment->set_status($this->_pay_model->failed_status());
272
+				return $payment;
273
+			}
274
+			$primary_registrant = $transaction->primary_registration();
275
+			$payment_details = $payment->details();
276
+			// Check if we still have the token.
277
+			if (! isset($payment_details['TOKEN']) || empty($payment_details['TOKEN'])) {
278
+				$payment->set_status($this->_pay_model->failed_status());
279
+				return $payment;
280
+			}
281
+			$cdetails_request_dtls = array(
282
+				'METHOD' => 'GetExpressCheckoutDetails',
283
+				'TOKEN'  => $payment_details['TOKEN'],
284
+			);
285
+			// Request Customer Details.
286
+			$cdetails_request_response = $this->_ppExpress_request(
287
+				$cdetails_request_dtls,
288
+				'Customer Details',
289
+				$payment
290
+			);
291
+			$cdetails_rstatus = $this->_ppExpress_check_response($cdetails_request_response);
292
+			$cdata_response_args = (isset($cdetails_rstatus['args']) && is_array($cdetails_rstatus['args']))
293
+				? $cdetails_rstatus['args']
294
+				: array();
295
+			if ($cdetails_rstatus['status']) {
296
+				// We got the PayerID so now we can Complete the transaction.
297
+				$docheckout_request_dtls = array(
298
+					'METHOD'                         => 'DoExpressCheckoutPayment',
299
+					'PAYERID'                        => $cdata_response_args['PAYERID'],
300
+					'TOKEN'                          => $payment_details['TOKEN'],
301
+					'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
302
+					'PAYMENTREQUEST_0_AMT'           => $payment->amount(),
303
+					'PAYMENTREQUEST_0_CURRENCYCODE'  => $payment->currency_code(),
304
+				);
305
+				 // Include itemized list.
306
+				$itemized_list = $this->itemize_list(
307
+					$payment,
308
+					$transaction,
309
+					$cdata_response_args
310
+				);
311
+				$docheckout_request_dtls = array_merge($docheckout_request_dtls, $itemized_list);
312
+				// Payment Checkout/Capture.
313
+				$docheckout_request_response = $this->_ppExpress_request(
314
+					$docheckout_request_dtls,
315
+					'Do Payment',
316
+					$payment
317
+				);
318
+				$docheckout_rstatus = $this->_ppExpress_check_response($docheckout_request_response);
319
+				$docheckout_response_args = (isset($docheckout_rstatus['args']) && is_array($docheckout_rstatus['args']))
320
+					? $docheckout_rstatus['args']
321
+					: array();
322
+				if ($docheckout_rstatus['status']) {
323
+					// All is well, payment approved.
324
+					$primary_registration_code = $primary_registrant instanceof EE_Registration ?
325
+						$primary_registrant->reg_code()
326
+						: '';
327
+					$payment->set_extra_accntng($primary_registration_code);
328
+					$payment->set_amount(isset($docheckout_response_args['PAYMENTINFO_0_AMT'])
329
+						? (float) $docheckout_response_args['PAYMENTINFO_0_AMT']
330
+						: 0);
331
+					$payment->set_txn_id_chq_nmbr(isset($docheckout_response_args['PAYMENTINFO_0_TRANSACTIONID'])
332
+						? $docheckout_response_args['PAYMENTINFO_0_TRANSACTIONID']
333
+						: null);
334
+					$payment->set_details($cdata_response_args);
335
+					$payment->set_gateway_response(isset($docheckout_response_args['PAYMENTINFO_0_ACK'])
336
+						? $docheckout_response_args['PAYMENTINFO_0_ACK']
337
+						: '');
338
+					$payment->set_status($this->_pay_model->approved_status());
339
+				} else {
340
+					if (isset($docheckout_response_args['L_ERRORCODE'])) {
341
+						$payment->set_gateway_response(
342
+							$docheckout_response_args['L_ERRORCODE']
343
+							. '; '
344
+							. $docheckout_response_args['L_SHORTMESSAGE']
345
+						);
346
+					} else {
347
+						$payment->set_gateway_response(
348
+							esc_html__(
349
+								'Error occurred while trying to Capture the funds.',
350
+								'event_espresso'
351
+							)
352
+						);
353
+					}
354
+					$payment->set_details($docheckout_response_args);
355
+					$payment->set_status($this->_pay_model->declined_status());
356
+				}
357
+			} else {
358
+				if (isset($cdata_response_args['L_ERRORCODE'])) {
359
+					$payment->set_gateway_response(
360
+						$cdata_response_args['L_ERRORCODE']
361
+						. '; '
362
+						. $cdata_response_args['L_SHORTMESSAGE']
363
+					);
364
+				} else {
365
+					$payment->set_gateway_response(
366
+						esc_html__(
367
+							'Error occurred while trying to get payment Details from PayPal.',
368
+							'event_espresso'
369
+						)
370
+					);
371
+				}
372
+				$payment->set_details($cdata_response_args);
373
+				$payment->set_status($this->_pay_model->failed_status());
374
+			}
375
+		} else {
376
+			$payment->set_gateway_response(
377
+				esc_html__(
378
+					'Error occurred while trying to process the payment.',
379
+					'event_espresso'
380
+				)
381
+			);
382
+			$payment->set_status($this->_pay_model->failed_status());
383
+		}
384
+		return $payment;
385
+	}
386
+
387
+
388
+
389
+	/**
390
+	 *  Make a list of items that are in the giver transaction.
391
+	 *
392
+	 * @param EEI_Payment     $payment
393
+	 * @param EEI_Transaction $transaction
394
+	 * @param array           $request_response_args Data from a previous communication with PP.
395
+	 * @return array
396
+	 */
397
+	public function itemize_list(EEI_Payment $payment, EEI_Transaction $transaction, $request_response_args = array())
398
+	{
399
+		$itemized_list = array();
400
+		$gateway_formatter = $this->_get_gateway_formatter();
401
+		// If we have data from a previous communication with PP (on this transaction) we may use that for our list...
402
+		if (! empty($request_response_args)
403
+			&& array_key_exists('L_PAYMENTREQUEST_0_AMT0', $request_response_args)
404
+			&& array_key_exists('PAYMENTREQUEST_0_ITEMAMT', $request_response_args)
405
+		) {
406
+			foreach ($request_response_args as $arg_key => $arg_val) {
407
+				if (strpos($arg_key, 'PAYMENTREQUEST_') !== false
408
+					&& strpos($arg_key, 'NOTIFYURL') === false
409
+				) {
410
+					$itemized_list[ $arg_key ] = $arg_val;
411
+				}
412
+			}
413
+			// If we got only a few Items then something is not right.
414
+			if (count($itemized_list) > 2) {
415
+				return $itemized_list;
416
+			} else {
417
+				if (WP_DEBUG) {
418
+					throw new EE_Error(
419
+						sprintf(
420
+							esc_html__(
421
+								// @codingStandardsIgnoreStart
422
+								'Unable to continue with the checkout because a proper purchase list could not be generated. The purchased list we could have sent was %1$s',
423
+								// @codingStandardsIgnoreEnd
424
+								'event_espresso'
425
+							),
426
+							wp_json_encode($itemized_list)
427
+						)
428
+					);
429
+				}
430
+				// Reset the list and log an error, maybe allow to try and generate a new list (below).
431
+				$itemized_list = array();
432
+				$this->log(
433
+					array(
434
+						(string) esc_html__(
435
+							'Could not generate a proper item list with:',
436
+							'event_espresso'
437
+						) => $request_response_args
438
+					),
439
+					$payment
440
+				);
441
+			}
442
+		}
443
+		// ...otherwise we generate a new list for this transaction.
444
+		if ($this->_money->compare_floats($payment->amount(), $transaction->total(), '==')) {
445
+			$item_num = 0;
446
+			$itemized_sum = 0;
447
+			$total_line_items = $transaction->total_line_item();
448
+			// Go through each item in the list.
449
+			foreach ($total_line_items->get_items() as $line_item) {
450
+				if ($line_item instanceof EE_Line_Item) {
451
+					// PayPal doesn't like line items with 0.00 amount, so we may skip those.
452
+					if (EEH_Money::compare_floats($line_item->total(), '0.00', '==')) {
453
+						continue;
454
+					}
455
+					$unit_price = $line_item->unit_price();
456
+					$line_item_quantity = $line_item->quantity();
457
+					// This is a discount.
458
+					if ($line_item->is_percent()) {
459
+						$unit_price = $line_item->total();
460
+						$line_item_quantity = 1;
461
+					}
462
+					// Item Name.
463
+					$itemized_list[ 'L_PAYMENTREQUEST_0_NAME' . $item_num ] = mb_strcut(
464
+						$gateway_formatter->formatLineItemName($line_item, $payment),
465
+						0,
466
+						127
467
+					);
468
+					// Item description.
469
+					$itemized_list[ 'L_PAYMENTREQUEST_0_DESC' . $item_num ] = mb_strcut(
470
+						$gateway_formatter->formatLineItemDesc($line_item, $payment),
471
+						0,
472
+						127
473
+					);
474
+					// Cost of individual item.
475
+					$itemized_list[ 'L_PAYMENTREQUEST_0_AMT' . $item_num ] = $gateway_formatter->formatCurrency($unit_price);
476
+					// Item Number.
477
+					$itemized_list[ 'L_PAYMENTREQUEST_0_NUMBER' . $item_num ] = $item_num + 1;
478
+					// Item quantity.
479
+					$itemized_list[ 'L_PAYMENTREQUEST_0_QTY' . $item_num ] = $line_item_quantity;
480
+					// Digital item is sold.
481
+					$itemized_list[ 'L_PAYMENTREQUEST_0_ITEMCATEGORY' . $item_num ] = 'Physical';
482
+					$itemized_sum += $line_item->total();
483
+					++$item_num;
484
+				}
485
+			}
486
+			// Item's sales S/H and tax amount.
487
+			$itemized_list['PAYMENTREQUEST_0_ITEMAMT'] = $total_line_items->get_items_total();
488
+			$itemized_list['PAYMENTREQUEST_0_TAXAMT'] = $total_line_items->get_total_tax();
489
+			$itemized_list['PAYMENTREQUEST_0_SHIPPINGAMT'] = '0';
490
+			$itemized_list['PAYMENTREQUEST_0_HANDLINGAMT'] = '0';
491
+			$itemized_sum_diff_from_txn_total = round(
492
+				$transaction->total() - $itemized_sum - $total_line_items->get_total_tax(),
493
+				2
494
+			);
495
+			// If we were not able to recognize some item like promotion, surcharge or cancellation,
496
+			// add the difference as an extra line item.
497
+			if ($this->_money->compare_floats($itemized_sum_diff_from_txn_total, 0, '!=')) {
498
+				// Item Name.
499
+				$itemized_list[ 'L_PAYMENTREQUEST_0_NAME' . $item_num ] = mb_strcut(
500
+					esc_html__(
501
+						'Other (promotion/surcharge/cancellation)',
502
+						'event_espresso'
503
+					),
504
+					0,
505
+					127
506
+				);
507
+				// Item description.
508
+				$itemized_list[ 'L_PAYMENTREQUEST_0_DESC' . $item_num ] = '';
509
+				// Cost of individual item.
510
+				$itemized_list[ 'L_PAYMENTREQUEST_0_AMT' . $item_num ] = $gateway_formatter->formatCurrency(
511
+					$itemized_sum_diff_from_txn_total
512
+				);
513
+				// Item Number.
514
+				$itemized_list[ 'L_PAYMENTREQUEST_0_NUMBER' . $item_num ] = $item_num + 1;
515
+				// Item quantity.
516
+				$itemized_list[ 'L_PAYMENTREQUEST_0_QTY' . $item_num ] = 1;
517
+				// Digital item is sold.
518
+				$itemized_list[ 'L_PAYMENTREQUEST_0_ITEMCATEGORY' . $item_num ] = 'Physical';
519
+				$item_num++;
520
+			}
521
+		} else {
522
+			// Just one Item.
523
+			// Item Name.
524
+			$itemized_list['L_PAYMENTREQUEST_0_NAME0'] = mb_strcut(
525
+				$gateway_formatter->formatPartialPaymentLineItemName($payment),
526
+				0,
527
+				127
528
+			);
529
+			// Item description.
530
+			$itemized_list['L_PAYMENTREQUEST_0_DESC0'] = mb_strcut(
531
+				$gateway_formatter->formatPartialPaymentLineItemDesc($payment),
532
+				0,
533
+				127
534
+			);
535
+			// Cost of individual item.
536
+			$itemized_list['L_PAYMENTREQUEST_0_AMT0'] = $gateway_formatter->formatCurrency($payment->amount());
537
+			// Item Number.
538
+			$itemized_list['L_PAYMENTREQUEST_0_NUMBER0'] = 1;
539
+			// Item quantity.
540
+			$itemized_list['L_PAYMENTREQUEST_0_QTY0'] = 1;
541
+			// Digital item is sold.
542
+			$itemized_list['L_PAYMENTREQUEST_0_ITEMCATEGORY0'] = 'Physical';
543
+			// Item's sales S/H and tax amount.
544
+			$itemized_list['PAYMENTREQUEST_0_ITEMAMT'] = $gateway_formatter->formatCurrency($payment->amount());
545
+			$itemized_list['PAYMENTREQUEST_0_TAXAMT'] = '0';
546
+			$itemized_list['PAYMENTREQUEST_0_SHIPPINGAMT'] = '0';
547
+			$itemized_list['PAYMENTREQUEST_0_HANDLINGAMT'] = '0';
548
+		}
549
+		return $itemized_list;
550
+	}
551
+
552
+
553
+
554
+	/**
555
+	 *  Make the Express checkout request.
556
+	 *
557
+	 * @param array       $request_params
558
+	 * @param string      $request_text
559
+	 * @param EEI_Payment $payment
560
+	 * @return mixed
561
+	 */
562
+	public function _ppExpress_request($request_params, $request_text, $payment)
563
+	{
564
+		$request_dtls = array(
565
+			'VERSION' => '204.0',
566
+			'USER' => $this->_api_username,
567
+			'PWD' => $this->_api_password,
568
+			'SIGNATURE' => $this->_api_signature,
569
+			// EE will blow up if you change this
570
+			'BUTTONSOURCE' => 'EventEspresso_SP',
571
+		);
572
+		$dtls = array_merge($request_dtls, $request_params);
573
+		$this->_log_clean_request($dtls, $payment, $request_text . ' Request');
574
+		// Request Customer Details.
575
+		$request_response = wp_remote_post(
576
+			$this->_base_gateway_url,
577
+			array(
578
+				'method'      => 'POST',
579
+				'timeout'     => 45,
580
+				'httpversion' => '1.1',
581
+				'cookies'     => array(),
582
+				'headers'     => array(),
583
+				'body'        => http_build_query($dtls, '', '&'),
584
+			)
585
+		);
586
+		// Log the response.
587
+		$this->log(array($request_text . ' Response' => $request_response), $payment);
588
+		return $request_response;
589
+	}
590
+
591
+
592
+
593
+	/**
594
+	 *  Check the response status.
595
+	 *
596
+	 * @param mixed $request_response
597
+	 * @return array
598
+	 */
599
+	public function _ppExpress_check_response($request_response)
600
+	{
601
+		if (is_wp_error($request_response) || empty($request_response['body'])) {
602
+			// If we got here then there was an error in this request.
603
+			return array('status' => false, 'args' => $request_response);
604
+		}
605
+		$response_args = array();
606
+		parse_str(urldecode($request_response['body']), $response_args);
607
+		if (! isset($response_args['ACK'])) {
608
+			return array('status' => false, 'args' => $request_response);
609
+		}
610
+		if ((
611
+				isset($response_args['PAYERID'])
612
+				|| isset($response_args['TOKEN'])
613
+				|| isset($response_args['PAYMENTINFO_0_TRANSACTIONID'])
614
+				|| (isset($response_args['PAYMENTSTATUS']) && $response_args['PAYMENTSTATUS'] === 'Completed')
615
+			)
616
+			&& in_array($response_args['ACK'], array('Success', 'SuccessWithWarning'), true)
617
+		) {
618
+			// Response status OK, return response parameters for further processing.
619
+			return array('status' => true, 'args' => $response_args);
620
+		}
621
+		$errors = $this->_get_errors($response_args);
622
+		return array('status' => false, 'args' => $errors);
623
+	}
624
+
625
+
626
+
627
+	/**
628
+	 *  Log a "Cleared" request.
629
+	 *
630
+	 * @param array       $request
631
+	 * @param EEI_Payment $payment
632
+	 * @param string      $info
633
+	 * @return void
634
+	 */
635
+	private function _log_clean_request($request, $payment, $info)
636
+	{
637
+		$cleaned_request_data = $request;
638
+		unset($cleaned_request_data['PWD'], $cleaned_request_data['USER'], $cleaned_request_data['SIGNATURE']);
639
+		$this->log(array($info => $cleaned_request_data), $payment);
640
+	}
641
+
642
+
643
+
644
+	/**
645
+	 *  Get error from the response data.
646
+	 *
647
+	 * @param array $data_array
648
+	 * @return array
649
+	 */
650
+	private function _get_errors($data_array)
651
+	{
652
+		$errors = array();
653
+		$n = 0;
654
+		while (isset($data_array[ "L_ERRORCODE{$n}" ])) {
655
+			$l_error_code = isset($data_array[ "L_ERRORCODE{$n}" ])
656
+				? $data_array[ "L_ERRORCODE{$n}" ]
657
+				: '';
658
+			$l_severity_code = isset($data_array[ "L_SEVERITYCODE{$n}" ])
659
+				? $data_array[ "L_SEVERITYCODE{$n}" ]
660
+				: '';
661
+			$l_short_message = isset($data_array[ "L_SHORTMESSAGE{$n}" ])
662
+				? $data_array[ "L_SHORTMESSAGE{$n}" ]
663
+				: '';
664
+			$l_long_message = isset($data_array[ "L_LONGMESSAGE{$n}" ])
665
+				? $data_array[ "L_LONGMESSAGE{$n}" ]
666
+				: '';
667
+			if ($n === 0) {
668
+				$errors = array(
669
+					'L_ERRORCODE'    => $l_error_code,
670
+					'L_SHORTMESSAGE' => $l_short_message,
671
+					'L_LONGMESSAGE'  => $l_long_message,
672
+					'L_SEVERITYCODE' => $l_severity_code,
673
+				);
674
+			} else {
675
+				$errors['L_ERRORCODE'] .= ', ' . $l_error_code;
676
+				$errors['L_SHORTMESSAGE'] .= ', ' . $l_short_message;
677
+				$errors['L_LONGMESSAGE'] .= ', ' . $l_long_message;
678
+				$errors['L_SEVERITYCODE'] .= ', ' . $l_severity_code;
679
+			}
680
+			$n++;
681
+		}
682
+		return $errors;
683
+	}
684 684
 }
Please login to merge, or discard this patch.
core/services/payment_methods/forms/PayPalSettingsForm.php 1 patch
Indentation   +190 added lines, -190 removed lines patch added patch discarded remove patch
@@ -19,201 +19,201 @@
 block discarded – undo
19 19
  */
20 20
 class PayPalSettingsForm extends EE_Payment_Method_Form
21 21
 {
22
-    /**
23
-     * @var string of HTML being the help tab link
24
-     */
25
-    protected $helpTabLink;
22
+	/**
23
+	 * @var string of HTML being the help tab link
24
+	 */
25
+	protected $helpTabLink;
26 26
 
27
-    public function __construct(array $options_array = array(), $help_tab_link = '')
28
-    {
29
-        $this->helpTabLink = $help_tab_link;
30
-        $options_array = array_replace_recursive(
31
-            array(
32
-                'extra_meta_inputs' => array(
33
-                    'api_username' => new EE_Text_Input(
34
-                        array(
35
-                            'html_label_text' => sprintf(
36
-                                // translators: %s link to help doc
37
-                                esc_html__('API Username %s', 'event_espresso'),
38
-                                $help_tab_link
39
-                            ),
40
-                            'required'        => true,
41
-                        )
42
-                    ),
43
-                    'api_password' => new EE_Text_Input(
44
-                        array(
45
-                            'html_label_text' => sprintf(
46
-                                // translators: %s link to help doc
47
-                                esc_html__('API Password %s', 'event_espresso'),
48
-                                $help_tab_link
49
-                            ),
50
-                            'required'        => true,
51
-                        )
52
-                    ),
53
-                    'api_signature' => new EE_Text_Input(
54
-                        array(
55
-                            'html_label_text' => sprintf(
56
-                                // translators: %s link to help doc
57
-                                esc_html__('API Signature %s', 'event_espresso'),
58
-                                $help_tab_link
59
-                            ),
60
-                            'required'        => true,
61
-                        )
62
-                    ),
63
-                )
64
-            ),
65
-            $options_array
66
-        );
67
-        parent::__construct($options_array);
68
-    }
27
+	public function __construct(array $options_array = array(), $help_tab_link = '')
28
+	{
29
+		$this->helpTabLink = $help_tab_link;
30
+		$options_array = array_replace_recursive(
31
+			array(
32
+				'extra_meta_inputs' => array(
33
+					'api_username' => new EE_Text_Input(
34
+						array(
35
+							'html_label_text' => sprintf(
36
+								// translators: %s link to help doc
37
+								esc_html__('API Username %s', 'event_espresso'),
38
+								$help_tab_link
39
+							),
40
+							'required'        => true,
41
+						)
42
+					),
43
+					'api_password' => new EE_Text_Input(
44
+						array(
45
+							'html_label_text' => sprintf(
46
+								// translators: %s link to help doc
47
+								esc_html__('API Password %s', 'event_espresso'),
48
+								$help_tab_link
49
+							),
50
+							'required'        => true,
51
+						)
52
+					),
53
+					'api_signature' => new EE_Text_Input(
54
+						array(
55
+							'html_label_text' => sprintf(
56
+								// translators: %s link to help doc
57
+								esc_html__('API Signature %s', 'event_espresso'),
58
+								$help_tab_link
59
+							),
60
+							'required'        => true,
61
+						)
62
+					),
63
+				)
64
+			),
65
+			$options_array
66
+		);
67
+		parent::__construct($options_array);
68
+	}
69 69
 
70
-    /**
71
-     * Tests the the PayPal API credentials work ok
72
-     * @return string of an error using the credentials, otherwise, if the credentials work, returns a blank string
73
-     * @throws EE_Error
74
-     */
75
-    protected function checkForCredentialsErrors()
76
-    {
77
-        $request_params = array(
78
-            'METHOD'    => 'GetBalance',
79
-            'VERSION'   => '204.0',
80
-            'USER'      => $this->get_input_value('api_username'),
81
-            'PWD'       => $this->get_input_value('api_password'),
82
-            'SIGNATURE' => $this->get_input_value('api_signature'),
83
-        );
84
-        $gateway_url = $this->get_input_value('PMD_debug_mode')
85
-            ? 'https://api-3t.sandbox.paypal.com/nvp'
86
-            : 'https://api-3t.paypal.com/nvp';
87
-        // Request Customer Details.
88
-        $response = wp_remote_post(
89
-            $gateway_url,
90
-            array(
91
-                'method'      => 'POST',
92
-                'timeout'     => 45,
93
-                'httpversion' => '1.1',
94
-                'cookies'     => array(),
95
-                'headers'     => array(),
96
-                'body'        => http_build_query($request_params, '', '&'),
97
-            )
98
-        );
99
-        if (is_wp_error($response) || empty($response['body'])) {
100
-            // If we got here then there was an error in this request.
101
-            // maybe is turned off. We don't know the credentials are invalid
102
-            EE_Error::add_error(
103
-                sprintf(
104
-                    // translators: %1$s Error message received from PayPal
105
-                    esc_html__(
106
-                        // @codingStandardsIgnoreStart
107
-                        'Your PayPal credentials could not be verified. The following error occurred while communicating with PayPal: %1$s',
108
-                        // @codingStandardsIgnoreEnd
109
-                        'event_espresso'
110
-                    ),
111
-                    $response->get_error_message()
112
-                ),
113
-                __FILE__,
114
-                __FUNCTION__,
115
-                __LINE__
116
-            );
117
-        }
118
-        $response_args = array();
119
-        parse_str(urldecode($response['body']), $response_args);
70
+	/**
71
+	 * Tests the the PayPal API credentials work ok
72
+	 * @return string of an error using the credentials, otherwise, if the credentials work, returns a blank string
73
+	 * @throws EE_Error
74
+	 */
75
+	protected function checkForCredentialsErrors()
76
+	{
77
+		$request_params = array(
78
+			'METHOD'    => 'GetBalance',
79
+			'VERSION'   => '204.0',
80
+			'USER'      => $this->get_input_value('api_username'),
81
+			'PWD'       => $this->get_input_value('api_password'),
82
+			'SIGNATURE' => $this->get_input_value('api_signature'),
83
+		);
84
+		$gateway_url = $this->get_input_value('PMD_debug_mode')
85
+			? 'https://api-3t.sandbox.paypal.com/nvp'
86
+			: 'https://api-3t.paypal.com/nvp';
87
+		// Request Customer Details.
88
+		$response = wp_remote_post(
89
+			$gateway_url,
90
+			array(
91
+				'method'      => 'POST',
92
+				'timeout'     => 45,
93
+				'httpversion' => '1.1',
94
+				'cookies'     => array(),
95
+				'headers'     => array(),
96
+				'body'        => http_build_query($request_params, '', '&'),
97
+			)
98
+		);
99
+		if (is_wp_error($response) || empty($response['body'])) {
100
+			// If we got here then there was an error in this request.
101
+			// maybe is turned off. We don't know the credentials are invalid
102
+			EE_Error::add_error(
103
+				sprintf(
104
+					// translators: %1$s Error message received from PayPal
105
+					esc_html__(
106
+						// @codingStandardsIgnoreStart
107
+						'Your PayPal credentials could not be verified. The following error occurred while communicating with PayPal: %1$s',
108
+						// @codingStandardsIgnoreEnd
109
+						'event_espresso'
110
+					),
111
+					$response->get_error_message()
112
+				),
113
+				__FILE__,
114
+				__FUNCTION__,
115
+				__LINE__
116
+			);
117
+		}
118
+		$response_args = array();
119
+		parse_str(urldecode($response['body']), $response_args);
120 120
 
121
-        if (empty($response_args['ACK'])) {
122
-            EE_Error::add_error(
123
-                esc_html__(
124
-                    'Your PayPal credentials could not be verified. Part of their response was missing.',
125
-                    'event_espresso'
126
-                ),
127
-                __FILE__,
128
-                __FUNCTION__,
129
-                __LINE__
130
-            );
131
-        }
132
-        if (in_array(
133
-            $response_args['ACK'],
134
-            array(
135
-                'Success',
136
-                'SuccessWithWarning'
137
-            ),
138
-            true
139
-        )
140
-        ) {
141
-            return '';
142
-        } else {
143
-            return sprintf(
144
-                // translators: %1$s: PayPal response message, %2$s: PayPal response code
145
-                esc_html__(
146
-                    // @codingStandardsIgnoreStart
147
-                    'Your PayPal API credentials appear to be invalid. PayPal said "%1$s (%2$s)". Please see tips below.',
148
-                    // @codingStandardsIgnoreEnd
149
-                    'event_espresso'
150
-                ),
151
-                isset($response_args['L_LONGMESSAGE0'])
152
-                    ? $response_args['L_LONGMESSAGE0']
153
-                    : esc_html__('No error message received from PayPal', 'event_espresso'),
154
-                isset($response_args['L_ERRORCODE0']) ? $response_args['L_ERRORCODE0'] : 0
155
-            );
156
-        }
157
-    }
121
+		if (empty($response_args['ACK'])) {
122
+			EE_Error::add_error(
123
+				esc_html__(
124
+					'Your PayPal credentials could not be verified. Part of their response was missing.',
125
+					'event_espresso'
126
+				),
127
+				__FILE__,
128
+				__FUNCTION__,
129
+				__LINE__
130
+			);
131
+		}
132
+		if (in_array(
133
+			$response_args['ACK'],
134
+			array(
135
+				'Success',
136
+				'SuccessWithWarning'
137
+			),
138
+			true
139
+		)
140
+		) {
141
+			return '';
142
+		} else {
143
+			return sprintf(
144
+				// translators: %1$s: PayPal response message, %2$s: PayPal response code
145
+				esc_html__(
146
+					// @codingStandardsIgnoreStart
147
+					'Your PayPal API credentials appear to be invalid. PayPal said "%1$s (%2$s)". Please see tips below.',
148
+					// @codingStandardsIgnoreEnd
149
+					'event_espresso'
150
+				),
151
+				isset($response_args['L_LONGMESSAGE0'])
152
+					? $response_args['L_LONGMESSAGE0']
153
+					: esc_html__('No error message received from PayPal', 'event_espresso'),
154
+				isset($response_args['L_ERRORCODE0']) ? $response_args['L_ERRORCODE0'] : 0
155
+			);
156
+		}
157
+	}
158 158
 
159
-    /**
160
-     * Gets the HTML to show the link to the help tab
161
-     * @return string
162
-     */
163
-    protected function helpTabLink()
164
-    {
165
-        return $this->helpTabLink;
166
-    }
159
+	/**
160
+	 * Gets the HTML to show the link to the help tab
161
+	 * @return string
162
+	 */
163
+	protected function helpTabLink()
164
+	{
165
+		return $this->helpTabLink;
166
+	}
167 167
 
168
-    /**
169
-     * Does the normal validation, but also verifies the PayPal API credentials work.
170
-     * If they don't, sets a validation error on the entire form, and adds validation errors (which are really more
171
-     * tips) on each of the inputs that could be the cause of the problem.
172
-     * @throws EE_Error
173
-     */
174
-    public function _validate()
175
-    {
176
-        parent::_validate();
177
-        $credentials_message = $this->checkForCredentialsErrors();
178
-        if ($credentials_message !== '') {
179
-            $this->add_validation_error($credentials_message);
180
-            $this->get_input('PMD_debug_mode')->add_validation_error(
181
-                esc_html__(
182
-                    // @codingStandardsIgnoreStart
183
-                    'If you are using PayPal Sandbox (test) credentials, Debug mode should be set to "Yes". Otherwise, if you are using live PayPal credentials, set this to "No".',
184
-                    // @codingStandardsIgnoreEnd
185
-                    'event_espresso'
186
-                )
187
-            );
188
-            $this->get_input('api_username')->add_validation_error(
189
-                sprintf(
190
-                    // translators: $1$s HTML for a link to the help tab
191
-                    esc_html__(
192
-                        'Are you sure this is your API username, not your login username? %1$s',
193
-                        'event_espresso'
194
-                    ),
195
-                    $this->helpTabLink()
196
-                )
197
-            );
198
-            $this->get_input('api_password')->add_validation_error(
199
-                sprintf(
200
-                    // translators: $1$s HTML for a link to the help tab
201
-                    esc_html__(
202
-                        'Are you sure this is your API password, not your login password? %1$s',
203
-                        'event_espresso'
204
-                    ),
205
-                    $this->helpTabLink()
206
-                )
207
-            );
208
-            $this->get_input('api_signature')->add_validation_error(
209
-                sprintf(
210
-                    // translators: $1$s HTML for a link to the help tab
211
-                    esc_html__('Please verify your API signature is correct. %1$s', 'event_espresso'),
212
-                    $this->helpTabLink()
213
-                )
214
-            );
215
-        }
216
-    }
168
+	/**
169
+	 * Does the normal validation, but also verifies the PayPal API credentials work.
170
+	 * If they don't, sets a validation error on the entire form, and adds validation errors (which are really more
171
+	 * tips) on each of the inputs that could be the cause of the problem.
172
+	 * @throws EE_Error
173
+	 */
174
+	public function _validate()
175
+	{
176
+		parent::_validate();
177
+		$credentials_message = $this->checkForCredentialsErrors();
178
+		if ($credentials_message !== '') {
179
+			$this->add_validation_error($credentials_message);
180
+			$this->get_input('PMD_debug_mode')->add_validation_error(
181
+				esc_html__(
182
+					// @codingStandardsIgnoreStart
183
+					'If you are using PayPal Sandbox (test) credentials, Debug mode should be set to "Yes". Otherwise, if you are using live PayPal credentials, set this to "No".',
184
+					// @codingStandardsIgnoreEnd
185
+					'event_espresso'
186
+				)
187
+			);
188
+			$this->get_input('api_username')->add_validation_error(
189
+				sprintf(
190
+					// translators: $1$s HTML for a link to the help tab
191
+					esc_html__(
192
+						'Are you sure this is your API username, not your login username? %1$s',
193
+						'event_espresso'
194
+					),
195
+					$this->helpTabLink()
196
+				)
197
+			);
198
+			$this->get_input('api_password')->add_validation_error(
199
+				sprintf(
200
+					// translators: $1$s HTML for a link to the help tab
201
+					esc_html__(
202
+						'Are you sure this is your API password, not your login password? %1$s',
203
+						'event_espresso'
204
+					),
205
+					$this->helpTabLink()
206
+				)
207
+			);
208
+			$this->get_input('api_signature')->add_validation_error(
209
+				sprintf(
210
+					// translators: $1$s HTML for a link to the help tab
211
+					esc_html__('Please verify your API signature is correct. %1$s', 'event_espresso'),
212
+					$this->helpTabLink()
213
+				)
214
+			);
215
+		}
216
+	}
217 217
 }
218 218
 // End of file PayPalSettingsForm.php
219 219
 // Location: ${NAMESPACE}/PayPalSettingsForm.php
Please login to merge, or discard this patch.
core/libraries/form_sections/inputs/EE_State_Select_Input.php 2 patches
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -36,7 +36,7 @@  discard block
 block discarded – undo
36 36
     {
37 37
         if (isset($input_settings['value_field_name'])) {
38 38
             $this->valueFieldName = $input_settings['value_field_name'];
39
-            if (! EEM_State::instance()->has_field((string) $this->valueFieldName())) {
39
+            if ( ! EEM_State::instance()->has_field((string) $this->valueFieldName())) {
40 40
                 throw new InvalidArgumentException(
41 41
                     sprintf(
42 42
                         esc_html__('An invalid state field "%1$s" was specified for the state input\'s option values.', 'event_espresso'),
@@ -53,7 +53,7 @@  discard block
 block discarded – undo
53 53
             $this
54 54
         );
55 55
         $input_settings['html_class'] = isset($input_settings['html_class'])
56
-            ? $input_settings['html_class'] . ' ee-state-select-js'
56
+            ? $input_settings['html_class'].' ee-state-select-js'
57 57
             : 'ee-state-select-js';
58 58
         parent::__construct($state_options, $input_settings);
59 59
     }
@@ -83,7 +83,7 @@  discard block
 block discarded – undo
83 83
     public function get_state_answer_options($state_options = null)
84 84
     {
85 85
         // if passed something that is NOT an array
86
-        if (! is_array($state_options) || empty($state_options)) {
86
+        if ( ! is_array($state_options) || empty($state_options)) {
87 87
             // get possibly cached list of states
88 88
             $states = EEM_State::instance()->get_all_active_states();
89 89
         }
@@ -91,12 +91,12 @@  discard block
 block discarded – undo
91 91
             $states = $state_options;
92 92
             $state_options = array();
93 93
         }
94
-        if (! empty($states)) {
94
+        if ( ! empty($states)) {
95 95
             // set the default
96 96
             $state_options[''][''] = '';
97 97
             foreach ($states as $state) {
98 98
                 if ($state instanceof EE_State) {
99
-                    $state_options[ $state->country()->name() ][ $state->get($this->valueFieldName()) ] = $state->name();
99
+                    $state_options[$state->country()->name()][$state->get($this->valueFieldName())] = $state->name();
100 100
                 }
101 101
             }
102 102
         }
Please login to merge, or discard this patch.
Indentation   +86 added lines, -86 removed lines patch added patch discarded remove patch
@@ -12,94 +12,94 @@
 block discarded – undo
12 12
  */
13 13
 class EE_State_Select_Input extends EE_Select_Input
14 14
 {
15
-    /**
16
-     * @var string the name of the EE_State field to use for option values in the HTML form input.
17
-     */
18
-    protected $valueFieldName;
15
+	/**
16
+	 * @var string the name of the EE_State field to use for option values in the HTML form input.
17
+	 */
18
+	protected $valueFieldName;
19 19
 
20
-    /**
21
-     * @param EE_State[]|array|null $state_options. If a flat array of string is provided,
22
-     * $input_settings['value_field_name'] is ignored. If an array of states is passed, that field will be used for
23
-     * the keys (which will become the option values). If null or empty is passed, all active states will be used,
24
-     * and $input_settings['value_field_name'] will again be used.     *
25
-     * @param array $input_settings same as parent, but also {
26
-     *   @type string $value_field_name the name of the field to use
27
-     *   for the HTML option values, ie, `STA_ID`, `STA_abbrev`, or `STA_name`.
28
-     * }
29
-     * @throws EE_Error
30
-     * @throws InvalidArgumentException
31
-     * @throws InvalidDataTypeException
32
-     * @throws InvalidInterfaceException
33
-     * @throws ReflectionException
34
-     */
35
-    public function __construct($state_options, $input_settings = array())
36
-    {
37
-        if (isset($input_settings['value_field_name'])) {
38
-            $this->valueFieldName = $input_settings['value_field_name'];
39
-            if (! EEM_State::instance()->has_field((string) $this->valueFieldName())) {
40
-                throw new InvalidArgumentException(
41
-                    sprintf(
42
-                        esc_html__('An invalid state field "%1$s" was specified for the state input\'s option values.', 'event_espresso'),
43
-                        $this->valueFieldName()
44
-                    )
45
-                );
46
-            }
47
-        } else {
48
-            $this->valueFieldName = 'STA_ID';
49
-        }
50
-        $state_options = apply_filters(
51
-            'FHEE__EE_State_Select_Input____construct__state_options',
52
-            $this->get_state_answer_options($state_options),
53
-            $this
54
-        );
55
-        $input_settings['html_class'] = isset($input_settings['html_class'])
56
-            ? $input_settings['html_class'] . ' ee-state-select-js'
57
-            : 'ee-state-select-js';
58
-        parent::__construct($state_options, $input_settings);
59
-    }
20
+	/**
21
+	 * @param EE_State[]|array|null $state_options. If a flat array of string is provided,
22
+	 * $input_settings['value_field_name'] is ignored. If an array of states is passed, that field will be used for
23
+	 * the keys (which will become the option values). If null or empty is passed, all active states will be used,
24
+	 * and $input_settings['value_field_name'] will again be used.     *
25
+	 * @param array $input_settings same as parent, but also {
26
+	 *   @type string $value_field_name the name of the field to use
27
+	 *   for the HTML option values, ie, `STA_ID`, `STA_abbrev`, or `STA_name`.
28
+	 * }
29
+	 * @throws EE_Error
30
+	 * @throws InvalidArgumentException
31
+	 * @throws InvalidDataTypeException
32
+	 * @throws InvalidInterfaceException
33
+	 * @throws ReflectionException
34
+	 */
35
+	public function __construct($state_options, $input_settings = array())
36
+	{
37
+		if (isset($input_settings['value_field_name'])) {
38
+			$this->valueFieldName = $input_settings['value_field_name'];
39
+			if (! EEM_State::instance()->has_field((string) $this->valueFieldName())) {
40
+				throw new InvalidArgumentException(
41
+					sprintf(
42
+						esc_html__('An invalid state field "%1$s" was specified for the state input\'s option values.', 'event_espresso'),
43
+						$this->valueFieldName()
44
+					)
45
+				);
46
+			}
47
+		} else {
48
+			$this->valueFieldName = 'STA_ID';
49
+		}
50
+		$state_options = apply_filters(
51
+			'FHEE__EE_State_Select_Input____construct__state_options',
52
+			$this->get_state_answer_options($state_options),
53
+			$this
54
+		);
55
+		$input_settings['html_class'] = isset($input_settings['html_class'])
56
+			? $input_settings['html_class'] . ' ee-state-select-js'
57
+			: 'ee-state-select-js';
58
+		parent::__construct($state_options, $input_settings);
59
+	}
60 60
 
61
-    /**
62
-     * Returns the name of the state field used for the HTML option values.
63
-     * @since 4.10.0.p
64
-     * @return string
65
-     */
66
-    public function valueFieldName()
67
-    {
68
-        return $this->valueFieldName;
69
-    }
61
+	/**
62
+	 * Returns the name of the state field used for the HTML option values.
63
+	 * @since 4.10.0.p
64
+	 * @return string
65
+	 */
66
+	public function valueFieldName()
67
+	{
68
+		return $this->valueFieldName;
69
+	}
70 70
 
71 71
 
72
-    /**
73
-     * get_state_answer_options
74
-     *
75
-     * @param array $state_options
76
-     * @return array
77
-     * @throws EE_Error
78
-     * @throws InvalidArgumentException
79
-     * @throws ReflectionException
80
-     * @throws InvalidDataTypeException
81
-     * @throws InvalidInterfaceException
82
-     */
83
-    public function get_state_answer_options($state_options = null)
84
-    {
85
-        // if passed something that is NOT an array
86
-        if (! is_array($state_options) || empty($state_options)) {
87
-            // get possibly cached list of states
88
-            $states = EEM_State::instance()->get_all_active_states();
89
-        }
90
-        if (is_array($state_options) && reset($state_options) instanceof EE_State) {
91
-            $states = $state_options;
92
-            $state_options = array();
93
-        }
94
-        if (! empty($states)) {
95
-            // set the default
96
-            $state_options[''][''] = '';
97
-            foreach ($states as $state) {
98
-                if ($state instanceof EE_State) {
99
-                    $state_options[ $state->country()->name() ][ $state->get($this->valueFieldName()) ] = $state->name();
100
-                }
101
-            }
102
-        }
103
-        return $state_options;
104
-    }
72
+	/**
73
+	 * get_state_answer_options
74
+	 *
75
+	 * @param array $state_options
76
+	 * @return array
77
+	 * @throws EE_Error
78
+	 * @throws InvalidArgumentException
79
+	 * @throws ReflectionException
80
+	 * @throws InvalidDataTypeException
81
+	 * @throws InvalidInterfaceException
82
+	 */
83
+	public function get_state_answer_options($state_options = null)
84
+	{
85
+		// if passed something that is NOT an array
86
+		if (! is_array($state_options) || empty($state_options)) {
87
+			// get possibly cached list of states
88
+			$states = EEM_State::instance()->get_all_active_states();
89
+		}
90
+		if (is_array($state_options) && reset($state_options) instanceof EE_State) {
91
+			$states = $state_options;
92
+			$state_options = array();
93
+		}
94
+		if (! empty($states)) {
95
+			// set the default
96
+			$state_options[''][''] = '';
97
+			foreach ($states as $state) {
98
+				if ($state instanceof EE_State) {
99
+					$state_options[ $state->country()->name() ][ $state->get($this->valueFieldName()) ] = $state->name();
100
+				}
101
+			}
102
+		}
103
+		return $state_options;
104
+	}
105 105
 }
Please login to merge, or discard this patch.
public/template_tags.php 1 patch
Spacing   +291 added lines, -291 removed lines patch added patch discarded remove patch
@@ -14,12 +14,12 @@  discard block
 block discarded – undo
14 14
  * @param int | \EE_Event $event
15 15
  * @return bool
16 16
  */
17
-function is_espresso_event( $event = NULL ) {
18
-	if ( can_use_espresso_conditionals( __FUNCTION__ )) {
17
+function is_espresso_event($event = NULL) {
18
+	if (can_use_espresso_conditionals(__FUNCTION__)) {
19 19
 		// extract EE_Event object from passed param regardless of what it is (within reason of course)
20
-		$event = EEH_Event_View::get_event( $event );
20
+		$event = EEH_Event_View::get_event($event);
21 21
 		// do we have a valid event ?
22
-		return $event instanceof EE_Event  ? TRUE : FALSE;
22
+		return $event instanceof EE_Event ? TRUE : FALSE;
23 23
 	}
24 24
 	return FALSE;
25 25
 }
@@ -31,7 +31,7 @@  discard block
 block discarded – undo
31 31
  * @return bool
32 32
  */
33 33
 function is_espresso_event_single() {
34
-	if ( can_use_espresso_conditionals( __FUNCTION__ )) {
34
+	if (can_use_espresso_conditionals(__FUNCTION__)) {
35 35
 		global $wp_query;
36 36
 		// return conditionals set by CPTs
37 37
 		return $wp_query instanceof WP_Query ? $wp_query->is_espresso_event_single : FALSE;
@@ -46,7 +46,7 @@  discard block
 block discarded – undo
46 46
  * @return bool
47 47
  */
48 48
 function is_espresso_event_archive() {
49
-	if ( can_use_espresso_conditionals( __FUNCTION__ )) {
49
+	if (can_use_espresso_conditionals(__FUNCTION__)) {
50 50
 		global $wp_query;
51 51
 		return $wp_query instanceof WP_Query ? $wp_query->is_espresso_event_archive : FALSE;
52 52
 	}
@@ -60,7 +60,7 @@  discard block
 block discarded – undo
60 60
  * @return bool
61 61
  */
62 62
 function is_espresso_event_taxonomy() {
63
-	if ( can_use_espresso_conditionals( __FUNCTION__ )) {
63
+	if (can_use_espresso_conditionals(__FUNCTION__)) {
64 64
 		global $wp_query;
65 65
 		return $wp_query instanceof WP_Query ? $wp_query->is_espresso_event_taxonomy : FALSE;
66 66
 	}
@@ -74,10 +74,10 @@  discard block
 block discarded – undo
74 74
  * @param int | \EE_Venue $venue
75 75
  * @return bool
76 76
  */
77
-function is_espresso_venue( $venue = NULL ) {
78
-	if ( can_use_espresso_conditionals( __FUNCTION__ )) {
77
+function is_espresso_venue($venue = NULL) {
78
+	if (can_use_espresso_conditionals(__FUNCTION__)) {
79 79
 		// extract EE_Venue object from passed param regardless of what it is (within reason of course)
80
-		$venue = EEH_Venue_View::get_venue( $venue, FALSE );
80
+		$venue = EEH_Venue_View::get_venue($venue, FALSE);
81 81
 		// do we have a valid event ?
82 82
 		return $venue instanceof EE_Venue ? TRUE : FALSE;
83 83
 	}
@@ -91,7 +91,7 @@  discard block
 block discarded – undo
91 91
  * @return bool
92 92
  */
93 93
 function is_espresso_venue_single() {
94
-	if ( can_use_espresso_conditionals( __FUNCTION__ )) {
94
+	if (can_use_espresso_conditionals(__FUNCTION__)) {
95 95
 		global $wp_query;
96 96
 		return $wp_query instanceof WP_Query ? $wp_query->is_espresso_venue_single : FALSE;
97 97
 	}
@@ -105,7 +105,7 @@  discard block
 block discarded – undo
105 105
  * @return bool
106 106
  */
107 107
 function is_espresso_venue_archive() {
108
-	if ( can_use_espresso_conditionals( __FUNCTION__ )) {
108
+	if (can_use_espresso_conditionals(__FUNCTION__)) {
109 109
 		global $wp_query;
110 110
 		return $wp_query instanceof WP_Query ? $wp_query->is_espresso_venue_archive : FALSE;
111 111
 	}
@@ -119,7 +119,7 @@  discard block
 block discarded – undo
119 119
  * @return bool
120 120
  */
121 121
 function is_espresso_venue_taxonomy() {
122
-	if ( can_use_espresso_conditionals( __FUNCTION__ )) {
122
+	if (can_use_espresso_conditionals(__FUNCTION__)) {
123 123
 		global $wp_query;
124 124
 		return $wp_query instanceof WP_Query ? $wp_query->is_espresso_venue_taxonomy : FALSE;
125 125
 	}
@@ -133,12 +133,12 @@  discard block
 block discarded – undo
133 133
  * @param $conditional_tag
134 134
  * @return bool
135 135
  */
136
-function can_use_espresso_conditionals( $conditional_tag ) {
137
-	if ( ! did_action( 'AHEE__EE_System__initialize' )) {
136
+function can_use_espresso_conditionals($conditional_tag) {
137
+	if ( ! did_action('AHEE__EE_System__initialize')) {
138 138
 		EE_Error::doing_it_wrong(
139 139
 			__FUNCTION__,
140 140
 			sprintf(
141
-				esc_html__( 'The "%s" conditional tag can not be used until after the "init" hook has run, but works best when used within a theme\'s template files.','event_espresso'),
141
+				esc_html__('The "%s" conditional tag can not be used until after the "init" hook has run, but works best when used within a theme\'s template files.', 'event_espresso'),
142 142
 				$conditional_tag
143 143
 			),
144 144
 			'4.4.0'
@@ -153,13 +153,13 @@  discard block
 block discarded – undo
153 153
 
154 154
 /*************************** Event Queries ***************************/
155 155
 
156
-if ( ! function_exists( 'espresso_get_events' )) {
156
+if ( ! function_exists('espresso_get_events')) {
157 157
 	/**
158 158
 	 * 	espresso_get_events
159 159
 	 * @param array $params
160 160
 	 * @return array
161 161
 	 */
162
-	function espresso_get_events( $params = array() ) {
162
+	function espresso_get_events($params = array()) {
163 163
 		//set default params
164 164
 		$default_espresso_events_params = array(
165 165
 			'limit' => 10,
@@ -170,18 +170,18 @@  discard block
 block discarded – undo
170 170
 			'sort' => 'ASC'
171 171
 		);
172 172
 		// allow the defaults to be filtered
173
-		$default_espresso_events_params = apply_filters( 'espresso_get_events__default_espresso_events_params', $default_espresso_events_params );
173
+		$default_espresso_events_params = apply_filters('espresso_get_events__default_espresso_events_params', $default_espresso_events_params);
174 174
 		// grab params and merge with defaults, then extract
175
-		$params = array_merge( $default_espresso_events_params, $params );
175
+		$params = array_merge($default_espresso_events_params, $params);
176 176
 		// run the query
177
-		$events_query = new EventEspresso\core\domain\services\wp_queries\EventListQuery( $params );
177
+		$events_query = new EventEspresso\core\domain\services\wp_queries\EventListQuery($params);
178 178
 		// assign results to a variable so we can return it
179 179
 		$events = $events_query->have_posts() ? $events_query->posts : array();
180 180
 		// but first reset the query and postdata
181 181
 		wp_reset_query();
182 182
 		wp_reset_postdata();
183 183
 		EED_Events_Archive::remove_all_events_archive_filters();
184
-		unset( $events_query );
184
+		unset($events_query);
185 185
 		return $events;
186 186
 	}
187 187
 }
@@ -195,33 +195,33 @@  discard block
 block discarded – undo
195 195
  * espresso_load_ticket_selector
196 196
  */
197 197
 function espresso_load_ticket_selector() {
198
-	EE_Registry::instance()->load_file( EE_MODULES . 'ticket_selector', 'EED_Ticket_Selector', 'module' );
198
+	EE_Registry::instance()->load_file(EE_MODULES.'ticket_selector', 'EED_Ticket_Selector', 'module');
199 199
 }
200 200
 
201
-if ( ! function_exists( 'espresso_ticket_selector' )) {
201
+if ( ! function_exists('espresso_ticket_selector')) {
202 202
 	/**
203 203
 	 * espresso_ticket_selector
204 204
 	 * @param null $event
205 205
 	 */
206
-	function espresso_ticket_selector( $event = NULL ) {
207
-		if (  ! apply_filters( 'FHEE_disable_espresso_ticket_selector', FALSE ) ) {
206
+	function espresso_ticket_selector($event = NULL) {
207
+		if ( ! apply_filters('FHEE_disable_espresso_ticket_selector', FALSE)) {
208 208
 			espresso_load_ticket_selector();
209 209
             \EED_Ticket_Selector::set_definitions();
210
-			echo EED_Ticket_Selector::display_ticket_selector( $event );
210
+			echo EED_Ticket_Selector::display_ticket_selector($event);
211 211
 		}
212 212
 	}
213 213
 }
214 214
 
215 215
 
216
-	if ( ! function_exists( 'espresso_view_details_btn' )) {
216
+	if ( ! function_exists('espresso_view_details_btn')) {
217 217
 	/**
218 218
 	 * espresso_view_details_btn
219 219
 	 * @param null $event
220 220
 	 */
221
-	function espresso_view_details_btn( $event = NULL ) {
222
-		if (  ! apply_filters( 'FHEE_disable_espresso_view_details_btn', FALSE ) ) {
221
+	function espresso_view_details_btn($event = NULL) {
222
+		if ( ! apply_filters('FHEE_disable_espresso_view_details_btn', FALSE)) {
223 223
 			espresso_load_ticket_selector();
224
-			echo EED_Ticket_Selector::display_ticket_selector( $event, TRUE );
224
+			echo EED_Ticket_Selector::display_ticket_selector($event, TRUE);
225 225
 		}
226 226
 	}
227 227
 }
@@ -231,7 +231,7 @@  discard block
 block discarded – undo
231 231
 
232 232
 /*************************** EEH_Event_View ***************************/
233 233
 
234
-if ( ! function_exists( 'espresso_load_event_list_assets' )) {
234
+if ( ! function_exists('espresso_load_event_list_assets')) {
235 235
 	/**
236 236
 	 * espresso_load_event_list_assets
237 237
 	 * ensures that event list styles and scripts are loaded
@@ -240,13 +240,13 @@  discard block
 block discarded – undo
240 240
 	 */
241 241
 	function espresso_load_event_list_assets() {
242 242
 		$event_list = EED_Events_Archive::instance();
243
-		add_action( 'AHEE__EE_System__initialize_last', array( $event_list, 'load_event_list_assets' ), 10 );
244
-		add_filter( 'FHEE_enable_default_espresso_css', '__return_true' );
243
+		add_action('AHEE__EE_System__initialize_last', array($event_list, 'load_event_list_assets'), 10);
244
+		add_filter('FHEE_enable_default_espresso_css', '__return_true');
245 245
 	}
246 246
 }
247 247
 
248 248
 
249
-if ( ! function_exists( 'espresso_event_reg_button' )) {
249
+if ( ! function_exists('espresso_event_reg_button')) {
250 250
 	/**
251 251
 	 * espresso_event_reg_button
252 252
 	 * returns the "Register Now" button if event is active,
@@ -258,13 +258,13 @@  discard block
 block discarded – undo
258 258
 	 * @param bool $EVT_ID
259 259
 	 * @return string
260 260
 	 */
261
-	function espresso_event_reg_button( $btn_text_if_active = NULL, $btn_text_if_inactive = FALSE, $EVT_ID = FALSE ) {
262
-		$event = EEH_Event_View::get_event( $EVT_ID );
263
-		if ( ! $event instanceof EE_Event ) {
261
+	function espresso_event_reg_button($btn_text_if_active = NULL, $btn_text_if_inactive = FALSE, $EVT_ID = FALSE) {
262
+		$event = EEH_Event_View::get_event($EVT_ID);
263
+		if ( ! $event instanceof EE_Event) {
264 264
 			return;
265 265
 		}
266 266
 		$event_status = $event->get_active_status();
267
-		switch ( $event_status ) {
267
+		switch ($event_status) {
268 268
 			case EE_Datetime::sold_out :
269 269
 				$btn_text = esc_html__('Sold Out', 'event_espresso');
270 270
 				$class = 'ee-pink';
@@ -284,15 +284,15 @@  discard block
 block discarded – undo
284 284
 			case EE_Datetime::upcoming :
285 285
 			case EE_Datetime::active :
286 286
 			default :
287
-				$btn_text =! empty( $btn_text_if_active ) ? $btn_text_if_active : esc_html__( 'Register Now', 'event_espresso' );
287
+				$btn_text = ! empty($btn_text_if_active) ? $btn_text_if_active : esc_html__('Register Now', 'event_espresso');
288 288
 				$class = 'ee-green';
289 289
 		}
290
-		if ( $event_status < 1 && ! empty( $btn_text_if_inactive )) {
290
+		if ($event_status < 1 && ! empty($btn_text_if_inactive)) {
291 291
 			$btn_text = $btn_text_if_inactive;
292 292
 			$class = 'ee-grey';
293 293
 		}
294 294
 		?>
295
-		<a class="ee-button ee-register-button <?php echo $class; ?>" href="<?php espresso_event_link_url( $EVT_ID ); ?>"<?php echo \EED_Events_Archive::link_target(); ?>>
295
+		<a class="ee-button ee-register-button <?php echo $class; ?>" href="<?php espresso_event_link_url($EVT_ID); ?>"<?php echo \EED_Events_Archive::link_target(); ?>>
296 296
 			<?php echo $btn_text; ?>
297 297
 		</a>
298 298
 	<?php
@@ -301,7 +301,7 @@  discard block
 block discarded – undo
301 301
 
302 302
 
303 303
 
304
-if ( ! function_exists( 'espresso_display_ticket_selector' )) {
304
+if ( ! function_exists('espresso_display_ticket_selector')) {
305 305
 	/**
306 306
 	 * espresso_display_ticket_selector
307 307
 	 * whether or not to display the Ticket Selector for an event
@@ -309,14 +309,14 @@  discard block
 block discarded – undo
309 309
 	 * @param bool $EVT_ID
310 310
 	 * @return boolean
311 311
 	 */
312
-	function espresso_display_ticket_selector( $EVT_ID = FALSE ) {
313
-		return EEH_Event_View::display_ticket_selector( $EVT_ID );
312
+	function espresso_display_ticket_selector($EVT_ID = FALSE) {
313
+		return EEH_Event_View::display_ticket_selector($EVT_ID);
314 314
 	}
315 315
 }
316 316
 
317 317
 
318 318
 
319
-if ( ! function_exists( 'espresso_event_status_banner' )) {
319
+if ( ! function_exists('espresso_event_status_banner')) {
320 320
 	/**
321 321
 	 * espresso_event_status
322 322
 	 * returns a banner showing the event status if it is sold out, expired, or inactive
@@ -324,13 +324,13 @@  discard block
 block discarded – undo
324 324
 	 * @param bool $EVT_ID
325 325
 	 * @return string
326 326
 	 */
327
-	function espresso_event_status_banner( $EVT_ID = FALSE ) {
328
-		return EEH_Event_View::event_status( $EVT_ID );
327
+	function espresso_event_status_banner($EVT_ID = FALSE) {
328
+		return EEH_Event_View::event_status($EVT_ID);
329 329
 	}
330 330
 }
331 331
 
332 332
 
333
-if ( ! function_exists( 'espresso_event_status' )) {
333
+if ( ! function_exists('espresso_event_status')) {
334 334
 	/**
335 335
 	 * espresso_event_status
336 336
 	 * returns the event status if it is sold out, expired, or inactive
@@ -339,13 +339,13 @@  discard block
 block discarded – undo
339 339
 	 * @param bool $echo
340 340
 	 * @return string
341 341
 	 */
342
-	function espresso_event_status( $EVT_ID = 0, $echo = TRUE ) {
343
-		return EEH_Event_View::event_active_status( $EVT_ID, $echo );
342
+	function espresso_event_status($EVT_ID = 0, $echo = TRUE) {
343
+		return EEH_Event_View::event_active_status($EVT_ID, $echo);
344 344
 	}
345 345
 }
346 346
 
347 347
 
348
-if ( ! function_exists( 'espresso_event_categories' )) {
348
+if ( ! function_exists('espresso_event_categories')) {
349 349
 	/**
350 350
 	 * espresso_event_categories
351 351
 	 * returns the terms associated with an event
@@ -355,17 +355,17 @@  discard block
 block discarded – undo
355 355
 	 * @param bool $echo
356 356
 	 * @return string
357 357
 	 */
358
-	function espresso_event_categories( $EVT_ID = 0, $hide_uncategorized = TRUE, $echo = TRUE ) {
359
-		if ( $echo ) {
360
-			echo EEH_Event_View::event_categories( $EVT_ID, $hide_uncategorized );
358
+	function espresso_event_categories($EVT_ID = 0, $hide_uncategorized = TRUE, $echo = TRUE) {
359
+		if ($echo) {
360
+			echo EEH_Event_View::event_categories($EVT_ID, $hide_uncategorized);
361 361
 			return '';
362 362
 		}
363
-		return EEH_Event_View::event_categories( $EVT_ID, $hide_uncategorized );
363
+		return EEH_Event_View::event_categories($EVT_ID, $hide_uncategorized);
364 364
 	}
365 365
 }
366 366
 
367 367
 
368
-if ( ! function_exists( 'espresso_event_tickets_available' )) {
368
+if ( ! function_exists('espresso_event_tickets_available')) {
369 369
 	/**
370 370
 	 * espresso_event_tickets_available
371 371
 	 * returns the ticket types available for purchase for an event
@@ -375,26 +375,26 @@  discard block
 block discarded – undo
375 375
 	 * @param bool $format
376 376
 	 * @return string
377 377
 	 */
378
-	function espresso_event_tickets_available( $EVT_ID = 0, $echo = TRUE, $format = TRUE ) {
379
-		$tickets = EEH_Event_View::event_tickets_available( $EVT_ID );
380
-		if ( is_array( $tickets ) && ! empty( $tickets )) {
378
+	function espresso_event_tickets_available($EVT_ID = 0, $echo = TRUE, $format = TRUE) {
379
+		$tickets = EEH_Event_View::event_tickets_available($EVT_ID);
380
+		if (is_array($tickets) && ! empty($tickets)) {
381 381
 			// if formatting then $html will be a string, else it will be an array of ticket objects
382
-			$html = $format ? '<ul id="ee-event-tickets-ul-' . $EVT_ID . '" class="ee-event-tickets-ul">' : array();
383
-			foreach ( $tickets as $ticket ) {
384
-				if ( $ticket instanceof EE_Ticket ) {
385
-					if ( $format ) {
386
-						$html .= '<li id="ee-event-tickets-li-' . $ticket->ID() . '" class="ee-event-tickets-li">';
387
-						$html .= $ticket->name() . ' ' . EEH_Template::format_currency( $ticket->get_ticket_total_with_taxes() );
382
+			$html = $format ? '<ul id="ee-event-tickets-ul-'.$EVT_ID.'" class="ee-event-tickets-ul">' : array();
383
+			foreach ($tickets as $ticket) {
384
+				if ($ticket instanceof EE_Ticket) {
385
+					if ($format) {
386
+						$html .= '<li id="ee-event-tickets-li-'.$ticket->ID().'" class="ee-event-tickets-li">';
387
+						$html .= $ticket->name().' '.EEH_Template::format_currency($ticket->get_ticket_total_with_taxes());
388 388
 						$html .= '</li>';
389 389
 					} else {
390 390
 						$html[] = $ticket;
391 391
 					}
392 392
 				}
393 393
 			}
394
-			if ( $format ) {
394
+			if ($format) {
395 395
 				$html .= '</ul>';
396 396
 			}
397
-			if ( $echo && $format ) {
397
+			if ($echo && $format) {
398 398
 				echo $html;
399 399
 				return '';
400 400
 			}
@@ -404,7 +404,7 @@  discard block
 block discarded – undo
404 404
 	}
405 405
 }
406 406
 
407
-if ( ! function_exists( 'espresso_event_date_obj' )) {
407
+if ( ! function_exists('espresso_event_date_obj')) {
408 408
 	/**
409 409
 	 * espresso_event_date_obj
410 410
 	 * returns the primary date object for an event
@@ -412,13 +412,13 @@  discard block
 block discarded – undo
412 412
 	 * @param bool $EVT_ID
413 413
 	 * @return object
414 414
 	 */
415
-	function espresso_event_date_obj( $EVT_ID = FALSE ) {
416
-		return EEH_Event_View::get_primary_date_obj( $EVT_ID );
415
+	function espresso_event_date_obj($EVT_ID = FALSE) {
416
+		return EEH_Event_View::get_primary_date_obj($EVT_ID);
417 417
 	}
418 418
 }
419 419
 
420 420
 
421
-if ( ! function_exists( 'espresso_event_date' )) {
421
+if ( ! function_exists('espresso_event_date')) {
422 422
 	/**
423 423
 	 * espresso_event_date
424 424
 	 * returns the primary date for an event
@@ -429,22 +429,22 @@  discard block
 block discarded – undo
429 429
 	 * @param bool $echo
430 430
 	 * @return string
431 431
 	 */
432
-	function espresso_event_date( $date_format = '', $time_format = '', $EVT_ID = FALSE, $echo = TRUE ) {
433
-		$date_format = ! empty( $date_format ) ? $date_format : get_option( 'date_format' );
434
-		$time_format = ! empty( $time_format ) ? $time_format : get_option( 'time_format' );
435
-		$date_format = apply_filters( 'FHEE__espresso_event_date__date_format', $date_format );
436
-		$time_format = apply_filters( 'FHEE__espresso_event_date__time_format', $time_format );
437
-		if($echo){
438
-			echo EEH_Event_View::the_event_date( $date_format, $time_format, $EVT_ID );
432
+	function espresso_event_date($date_format = '', $time_format = '', $EVT_ID = FALSE, $echo = TRUE) {
433
+		$date_format = ! empty($date_format) ? $date_format : get_option('date_format');
434
+		$time_format = ! empty($time_format) ? $time_format : get_option('time_format');
435
+		$date_format = apply_filters('FHEE__espresso_event_date__date_format', $date_format);
436
+		$time_format = apply_filters('FHEE__espresso_event_date__time_format', $time_format);
437
+		if ($echo) {
438
+			echo EEH_Event_View::the_event_date($date_format, $time_format, $EVT_ID);
439 439
 			return '';
440 440
 		}
441
-		return EEH_Event_View::the_event_date( $date_format, $time_format, $EVT_ID );
441
+		return EEH_Event_View::the_event_date($date_format, $time_format, $EVT_ID);
442 442
 
443 443
 	}
444 444
 }
445 445
 
446 446
 
447
-if ( ! function_exists( 'espresso_list_of_event_dates' )) {
447
+if ( ! function_exists('espresso_list_of_event_dates')) {
448 448
 	/**
449 449
 	 * espresso_list_of_event_dates
450 450
 	 * returns a unordered list of dates for an event
@@ -459,40 +459,40 @@  discard block
 block discarded – undo
459 459
 	 * @param null   $limit
460 460
 	 * @return string
461 461
 	 */
462
-	function espresso_list_of_event_dates( $EVT_ID = 0, $date_format = '', $time_format = '', $echo = TRUE, $show_expired = NULL, $format = TRUE, $add_breaks = TRUE, $limit = NULL ) {
463
-		$date_format = ! empty( $date_format ) ? $date_format : get_option( 'date_format' );
464
-		$time_format = ! empty( $time_format ) ? $time_format : get_option( 'time_format' );
465
-		$date_format = apply_filters( 'FHEE__espresso_list_of_event_dates__date_format', $date_format );
466
-		$time_format = apply_filters( 'FHEE__espresso_list_of_event_dates__time_format', $time_format );
467
-		$datetimes = EEH_Event_View::get_all_date_obj( $EVT_ID, $show_expired, FALSE, $limit );
468
-		if ( ! $format ) {
469
-			return apply_filters( 'FHEE__espresso_list_of_event_dates__datetimes', $datetimes );
462
+	function espresso_list_of_event_dates($EVT_ID = 0, $date_format = '', $time_format = '', $echo = TRUE, $show_expired = NULL, $format = TRUE, $add_breaks = TRUE, $limit = NULL) {
463
+		$date_format = ! empty($date_format) ? $date_format : get_option('date_format');
464
+		$time_format = ! empty($time_format) ? $time_format : get_option('time_format');
465
+		$date_format = apply_filters('FHEE__espresso_list_of_event_dates__date_format', $date_format);
466
+		$time_format = apply_filters('FHEE__espresso_list_of_event_dates__time_format', $time_format);
467
+		$datetimes = EEH_Event_View::get_all_date_obj($EVT_ID, $show_expired, FALSE, $limit);
468
+		if ( ! $format) {
469
+			return apply_filters('FHEE__espresso_list_of_event_dates__datetimes', $datetimes);
470 470
 		}
471 471
 		//d( $datetimes );
472
-		if ( is_array( $datetimes ) && ! empty( $datetimes )) {
472
+		if (is_array($datetimes) && ! empty($datetimes)) {
473 473
 			global $post;
474
-			$html = $format ? '<ul id="ee-event-datetimes-ul-' . $post->ID . '" class="ee-event-datetimes-ul ee-clearfix">' : '';
475
-			foreach ( $datetimes as $datetime ) {
476
-				if ( $datetime instanceof EE_Datetime ) {
477
-					$html .= '<li id="ee-event-datetimes-li-' . $datetime->ID();
478
-					$html .= '" class="ee-event-datetimes-li ee-event-datetimes-li-' . $datetime->get_active_status() . '">';
474
+			$html = $format ? '<ul id="ee-event-datetimes-ul-'.$post->ID.'" class="ee-event-datetimes-ul ee-clearfix">' : '';
475
+			foreach ($datetimes as $datetime) {
476
+				if ($datetime instanceof EE_Datetime) {
477
+					$html .= '<li id="ee-event-datetimes-li-'.$datetime->ID();
478
+					$html .= '" class="ee-event-datetimes-li ee-event-datetimes-li-'.$datetime->get_active_status().'">';
479 479
 					$datetime_name = $datetime->name();
480
-					$html .= ! empty( $datetime_name ) ? '<strong>' . $datetime_name . '</strong>' : '';
481
-					$html .= ! empty( $datetime_name )  && $add_breaks ? '<br />' : '';
482
-					$html .= '<span class="dashicons dashicons-calendar"></span><span class="ee-event-datetimes-li-daterange">' . $datetime->date_range( $date_format ) . '</span><br/>';
483
-					$html .= '<span class="dashicons dashicons-clock"></span><span class="ee-event-datetimes-li-timerange">' . $datetime->time_range( $time_format ) . '</span>';
480
+					$html .= ! empty($datetime_name) ? '<strong>'.$datetime_name.'</strong>' : '';
481
+					$html .= ! empty($datetime_name) && $add_breaks ? '<br />' : '';
482
+					$html .= '<span class="dashicons dashicons-calendar"></span><span class="ee-event-datetimes-li-daterange">'.$datetime->date_range($date_format).'</span><br/>';
483
+					$html .= '<span class="dashicons dashicons-clock"></span><span class="ee-event-datetimes-li-timerange">'.$datetime->time_range($time_format).'</span>';
484 484
 					$datetime_description = $datetime->description();
485
-					$html .= ! empty( $datetime_description )  && $add_breaks ? '<br />' : '';
486
-					$html .= ! empty( $datetime_description ) ? ' - ' . $datetime_description : '';
487
-					$html = apply_filters( 'FHEE__espresso_list_of_event_dates__datetime_html', $html, $datetime );
485
+					$html .= ! empty($datetime_description) && $add_breaks ? '<br />' : '';
486
+					$html .= ! empty($datetime_description) ? ' - '.$datetime_description : '';
487
+					$html = apply_filters('FHEE__espresso_list_of_event_dates__datetime_html', $html, $datetime);
488 488
 					$html .= '</li>';
489 489
 				}
490 490
 			}
491 491
 			$html .= $format ? '</ul>' : '';
492 492
 		} else {
493
-			$html = $format ?  '<p><span class="dashicons dashicons-marker pink-text"></span>' . esc_html__( 'There are no upcoming dates for this event.', 'event_espresso' ) . '</p><br/>' : '';
493
+			$html = $format ? '<p><span class="dashicons dashicons-marker pink-text"></span>'.esc_html__('There are no upcoming dates for this event.', 'event_espresso').'</p><br/>' : '';
494 494
 		}
495
-		if ( $echo ) {
495
+		if ($echo) {
496 496
 			echo $html;
497 497
 			return '';
498 498
 		}
@@ -501,7 +501,7 @@  discard block
 block discarded – undo
501 501
 }
502 502
 
503 503
 
504
-if ( ! function_exists( 'espresso_event_end_date' )) {
504
+if ( ! function_exists('espresso_event_end_date')) {
505 505
 	/**
506 506
 	 * espresso_event_end_date
507 507
 	 * returns the last date for an event
@@ -512,20 +512,20 @@  discard block
 block discarded – undo
512 512
 	 * @param bool   $echo
513 513
 	 * @return string
514 514
 	 */
515
-	function espresso_event_end_date( $date_format = '', $time_format = '', $EVT_ID = FALSE, $echo = TRUE ) {
516
-		$date_format = ! empty( $date_format ) ? $date_format : get_option( 'date_format' );
517
-		$time_format = ! empty( $time_format ) ? $time_format : get_option( 'time_format' );
518
-		$date_format = apply_filters( 'FHEE__espresso_event_end_date__date_format', $date_format );
519
-		$time_format = apply_filters( 'FHEE__espresso_event_end_date__time_format', $time_format );
520
-		if($echo){
521
-			echo EEH_Event_View::the_event_end_date( $date_format, $time_format, $EVT_ID );
515
+	function espresso_event_end_date($date_format = '', $time_format = '', $EVT_ID = FALSE, $echo = TRUE) {
516
+		$date_format = ! empty($date_format) ? $date_format : get_option('date_format');
517
+		$time_format = ! empty($time_format) ? $time_format : get_option('time_format');
518
+		$date_format = apply_filters('FHEE__espresso_event_end_date__date_format', $date_format);
519
+		$time_format = apply_filters('FHEE__espresso_event_end_date__time_format', $time_format);
520
+		if ($echo) {
521
+			echo EEH_Event_View::the_event_end_date($date_format, $time_format, $EVT_ID);
522 522
 			return '';
523 523
 		}
524
-		return EEH_Event_View::the_event_end_date( $date_format, $time_format, $EVT_ID );
524
+		return EEH_Event_View::the_event_end_date($date_format, $time_format, $EVT_ID);
525 525
 	}
526 526
 }
527 527
 
528
-if ( ! function_exists( 'espresso_event_date_range' )) {
528
+if ( ! function_exists('espresso_event_date_range')) {
529 529
 	/**
530 530
 	 * espresso_event_date_range
531 531
 	 * returns the first and last chronologically ordered dates for an event (if different)
@@ -538,32 +538,32 @@  discard block
 block discarded – undo
538 538
 	 * @param bool   $echo
539 539
 	 * @return string
540 540
 	 */
541
-	function espresso_event_date_range( $date_format = '', $time_format = '', $single_date_format = '', $single_time_format = '', $EVT_ID = FALSE, $echo = TRUE ) {
541
+	function espresso_event_date_range($date_format = '', $time_format = '', $single_date_format = '', $single_time_format = '', $EVT_ID = FALSE, $echo = TRUE) {
542 542
 		// set and filter date and time formats when a range is returned
543
-		$date_format = ! empty( $date_format ) ? $date_format : get_option( 'date_format' );
544
-		$date_format = apply_filters( 'FHEE__espresso_event_date_range__date_format', $date_format );
543
+		$date_format = ! empty($date_format) ? $date_format : get_option('date_format');
544
+		$date_format = apply_filters('FHEE__espresso_event_date_range__date_format', $date_format);
545 545
 		// get the start and end date with NO time portion
546
-		$the_event_date = EEH_Event_View::the_earliest_event_date( $date_format, '', $EVT_ID );
547
-		$the_event_end_date = EEH_Event_View::the_latest_event_date( $date_format, '', $EVT_ID );
546
+		$the_event_date = EEH_Event_View::the_earliest_event_date($date_format, '', $EVT_ID);
547
+		$the_event_end_date = EEH_Event_View::the_latest_event_date($date_format, '', $EVT_ID);
548 548
 		// now we can determine if date range spans more than one day
549
-		if ( $the_event_date != $the_event_end_date ) {
550
-			$time_format = ! empty( $time_format ) ? $time_format : get_option( 'time_format' );
551
-			$time_format = apply_filters( 'FHEE__espresso_event_date_range__time_format', $time_format );
549
+		if ($the_event_date != $the_event_end_date) {
550
+			$time_format = ! empty($time_format) ? $time_format : get_option('time_format');
551
+			$time_format = apply_filters('FHEE__espresso_event_date_range__time_format', $time_format);
552 552
 			$html = sprintf(
553 553
 				/* translators: 1: first event date, 2: last event date */
554
-				esc_html__( '%1$s - %2$s', 'event_espresso' ),
555
-				EEH_Event_View::the_earliest_event_date( $date_format, $time_format, $EVT_ID ),
556
-				EEH_Event_View::the_latest_event_date( $date_format, $time_format, $EVT_ID )
554
+				esc_html__('%1$s - %2$s', 'event_espresso'),
555
+				EEH_Event_View::the_earliest_event_date($date_format, $time_format, $EVT_ID),
556
+				EEH_Event_View::the_latest_event_date($date_format, $time_format, $EVT_ID)
557 557
 			);
558 558
 		} else {
559 559
 			// set and filter date and time formats when only a single datetime is returned
560
-			$single_date_format = ! empty( $single_date_format ) ? $single_date_format : get_option( 'date_format' );
561
-			$single_time_format = ! empty( $single_time_format ) ? $single_time_format : get_option( 'time_format' );
562
-			$single_date_format = apply_filters( 'FHEE__espresso_event_date_range__single_date_format', $single_date_format );
563
-			$single_time_format = apply_filters( 'FHEE__espresso_event_date_range__single_time_format', $single_time_format );
564
-			$html = EEH_Event_View::the_earliest_event_date( $single_date_format, $single_time_format, $EVT_ID );
560
+			$single_date_format = ! empty($single_date_format) ? $single_date_format : get_option('date_format');
561
+			$single_time_format = ! empty($single_time_format) ? $single_time_format : get_option('time_format');
562
+			$single_date_format = apply_filters('FHEE__espresso_event_date_range__single_date_format', $single_date_format);
563
+			$single_time_format = apply_filters('FHEE__espresso_event_date_range__single_time_format', $single_time_format);
564
+			$html = EEH_Event_View::the_earliest_event_date($single_date_format, $single_time_format, $EVT_ID);
565 565
 		}
566
-		if ( $echo ) {
566
+		if ($echo) {
567 567
 			echo $html;
568 568
 			return '';
569 569
 		}
@@ -571,7 +571,7 @@  discard block
 block discarded – undo
571 571
 	}
572 572
 }
573 573
 
574
-if ( ! function_exists( 'espresso_next_upcoming_datetime_obj' )) {
574
+if ( ! function_exists('espresso_next_upcoming_datetime_obj')) {
575 575
 	/**
576 576
 	 * espresso_next_upcoming_datetime_obj
577 577
 	 * returns the next upcoming datetime object for an event
@@ -579,12 +579,12 @@  discard block
 block discarded – undo
579 579
 	 * @param int $EVT_ID
580 580
 	 * @return EE_Datetime|null
581 581
 	 */
582
-	function espresso_next_upcoming_datetime_obj( $EVT_ID = 0 ) {
583
-		return EEH_Event_View::get_next_upcoming_date_obj( $EVT_ID );
582
+	function espresso_next_upcoming_datetime_obj($EVT_ID = 0) {
583
+		return EEH_Event_View::get_next_upcoming_date_obj($EVT_ID);
584 584
 	}
585 585
 }
586 586
 
587
-if ( ! function_exists( 'espresso_next_upcoming_datetime' ) ) {
587
+if ( ! function_exists('espresso_next_upcoming_datetime')) {
588 588
 	/**
589 589
 	 * espresso_next_upcoming_datetime
590 590
 	 * returns the start date and time for the next upcoming event.
@@ -595,30 +595,30 @@  discard block
 block discarded – undo
595 595
 	 * @param bool $echo
596 596
 	 * @return string
597 597
 	 */
598
-	function espresso_next_upcoming_datetime( $date_format = '', $time_format = '', $EVT_ID = 0, $echo = true ) {
598
+	function espresso_next_upcoming_datetime($date_format = '', $time_format = '', $EVT_ID = 0, $echo = true) {
599 599
 
600
-		$date_format = ! empty( $date_format ) ? $date_format : get_option( 'date_format' );
601
-		$date_format = apply_filters( 'FHEE__espresso_next_upcoming_datetime__date_format', $date_format );
600
+		$date_format = ! empty($date_format) ? $date_format : get_option('date_format');
601
+		$date_format = apply_filters('FHEE__espresso_next_upcoming_datetime__date_format', $date_format);
602 602
 
603
-		$time_format = ! empty( $time_format ) ? $time_format : get_option( 'time_format' );
604
-		$time_format = apply_filters( 'FHEE__espresso_next_upcoming_datetime__time_format', $time_format );
603
+		$time_format = ! empty($time_format) ? $time_format : get_option('time_format');
604
+		$time_format = apply_filters('FHEE__espresso_next_upcoming_datetime__time_format', $time_format);
605 605
 
606
-		$datetime_format = trim( $date_format . ' ' . $time_format);
606
+		$datetime_format = trim($date_format.' '.$time_format);
607 607
 
608
-		$datetime = espresso_next_upcoming_datetime_obj( $EVT_ID );
608
+		$datetime = espresso_next_upcoming_datetime_obj($EVT_ID);
609 609
 
610
-		if( ! $datetime instanceof EE_Datetime ) {
610
+		if ( ! $datetime instanceof EE_Datetime) {
611 611
 			return '';
612 612
 		}
613
-		if ( $echo ){
614
-			echo $datetime->get_i18n_datetime( 'DTT_EVT_start', $datetime_format );
613
+		if ($echo) {
614
+			echo $datetime->get_i18n_datetime('DTT_EVT_start', $datetime_format);
615 615
 			return '';
616 616
 		}
617
-		return $datetime->get_i18n_datetime( 'DTT_EVT_start', $datetime_format );
617
+		return $datetime->get_i18n_datetime('DTT_EVT_start', $datetime_format);
618 618
 	}
619 619
 }
620 620
 
621
-if ( ! function_exists( 'espresso_event_date_as_calendar_page' )) {
621
+if ( ! function_exists('espresso_event_date_as_calendar_page')) {
622 622
 	/**
623 623
 	 * espresso_event_date_as_calendar_page
624 624
 	 * returns the primary date for an event, stylized to appear as the page of a calendar
@@ -626,15 +626,15 @@  discard block
 block discarded – undo
626 626
 	 * @param bool $EVT_ID
627 627
 	 * @return string
628 628
 	 */
629
-	function espresso_event_date_as_calendar_page( $EVT_ID = FALSE ) {
630
-		EEH_Event_View::event_date_as_calendar_page( $EVT_ID );
629
+	function espresso_event_date_as_calendar_page($EVT_ID = FALSE) {
630
+		EEH_Event_View::event_date_as_calendar_page($EVT_ID);
631 631
 	}
632 632
 }
633 633
 
634 634
 
635 635
 
636 636
 
637
-if ( ! function_exists( 'espresso_event_link_url' )) {
637
+if ( ! function_exists('espresso_event_link_url')) {
638 638
 	/**
639 639
 	 * espresso_event_link_url
640 640
 	 *
@@ -642,18 +642,18 @@  discard block
 block discarded – undo
642 642
 	 * @param bool $echo
643 643
 	 * @return string
644 644
 	 */
645
-	function espresso_event_link_url( $EVT_ID = 0, $echo = TRUE ) {
646
-		if ( $echo ) {
647
-			echo EEH_Event_View::event_link_url( $EVT_ID );
645
+	function espresso_event_link_url($EVT_ID = 0, $echo = TRUE) {
646
+		if ($echo) {
647
+			echo EEH_Event_View::event_link_url($EVT_ID);
648 648
 			return '';
649 649
 		}
650
-		return EEH_Event_View::event_link_url( $EVT_ID );
650
+		return EEH_Event_View::event_link_url($EVT_ID);
651 651
 	}
652 652
 }
653 653
 
654 654
 
655 655
 
656
-if ( ! function_exists( 'espresso_event_has_content_or_excerpt' )) {
656
+if ( ! function_exists('espresso_event_has_content_or_excerpt')) {
657 657
 	/**
658 658
 	 *    espresso_event_has_content_or_excerpt
659 659
 	 *
@@ -661,15 +661,15 @@  discard block
 block discarded – undo
661 661
 	 * @param bool $EVT_ID
662 662
 	 * @return    boolean
663 663
 	 */
664
-	function espresso_event_has_content_or_excerpt( $EVT_ID = FALSE ) {
665
-		return EEH_Event_View::event_has_content_or_excerpt( $EVT_ID );
664
+	function espresso_event_has_content_or_excerpt($EVT_ID = FALSE) {
665
+		return EEH_Event_View::event_has_content_or_excerpt($EVT_ID);
666 666
 	}
667 667
 }
668 668
 
669 669
 
670 670
 
671 671
 
672
-if ( ! function_exists( 'espresso_event_content_or_excerpt' )) {
672
+if ( ! function_exists('espresso_event_content_or_excerpt')) {
673 673
 	/**
674 674
 	 * espresso_event_content_or_excerpt
675 675
 	 *
@@ -678,18 +678,18 @@  discard block
 block discarded – undo
678 678
 	 * @param bool $echo
679 679
 	 * @return string
680 680
 	 */
681
-	function espresso_event_content_or_excerpt( $num_words = 55, $more = NULL, $echo = TRUE ) {
682
-		if ( $echo ) {
683
-			echo EEH_Event_View::event_content_or_excerpt( $num_words, $more );
681
+	function espresso_event_content_or_excerpt($num_words = 55, $more = NULL, $echo = TRUE) {
682
+		if ($echo) {
683
+			echo EEH_Event_View::event_content_or_excerpt($num_words, $more);
684 684
 			return '';
685 685
 		}
686
-		return EEH_Event_View::event_content_or_excerpt( $num_words, $more );
686
+		return EEH_Event_View::event_content_or_excerpt($num_words, $more);
687 687
 	}
688 688
 }
689 689
 
690 690
 
691 691
 
692
-if ( ! function_exists( 'espresso_event_phone' )) {
692
+if ( ! function_exists('espresso_event_phone')) {
693 693
 	/**
694 694
 	 * espresso_event_phone
695 695
 	 *
@@ -697,18 +697,18 @@  discard block
 block discarded – undo
697 697
 	 * @param bool $echo
698 698
 	 * @return string
699 699
 	 */
700
-	function espresso_event_phone( $EVT_ID = 0, $echo = TRUE ) {
701
-		if ( $echo ) {
702
-			echo EEH_Event_View::event_phone( $EVT_ID );
700
+	function espresso_event_phone($EVT_ID = 0, $echo = TRUE) {
701
+		if ($echo) {
702
+			echo EEH_Event_View::event_phone($EVT_ID);
703 703
 			return '';
704 704
 		}
705
-		return EEH_Event_View::event_phone( $EVT_ID );
705
+		return EEH_Event_View::event_phone($EVT_ID);
706 706
 	}
707 707
 }
708 708
 
709 709
 
710 710
 
711
-if ( ! function_exists( 'espresso_edit_event_link' )) {
711
+if ( ! function_exists('espresso_edit_event_link')) {
712 712
 	/**
713 713
 	 * espresso_edit_event_link
714 714
 	 * returns a link to edit an event
@@ -717,39 +717,39 @@  discard block
 block discarded – undo
717 717
 	 * @param bool $echo
718 718
 	 * @return string
719 719
 	 */
720
-	function espresso_edit_event_link( $EVT_ID = 0, $echo = TRUE ) {
721
-		if ( $echo ) {
722
-			echo EEH_Event_View::edit_event_link( $EVT_ID );
720
+	function espresso_edit_event_link($EVT_ID = 0, $echo = TRUE) {
721
+		if ($echo) {
722
+			echo EEH_Event_View::edit_event_link($EVT_ID);
723 723
 			return '';
724 724
 		}
725
-		return EEH_Event_View::edit_event_link( $EVT_ID );
725
+		return EEH_Event_View::edit_event_link($EVT_ID);
726 726
 	}
727 727
 }
728 728
 
729 729
 
730
-if ( ! function_exists( 'espresso_organization_name' )) {
730
+if ( ! function_exists('espresso_organization_name')) {
731 731
 	/**
732 732
 	 * espresso_organization_name
733 733
 	 * @param bool $echo
734 734
 	 * @return string
735 735
 	 */
736 736
 	function espresso_organization_name($echo = TRUE) {
737
-		if($echo){
738
-			echo EE_Registry::instance()->CFG->organization->get_pretty( 'name' );
737
+		if ($echo) {
738
+			echo EE_Registry::instance()->CFG->organization->get_pretty('name');
739 739
 			return '';
740 740
 		}
741
-		return EE_Registry::instance()->CFG->organization->get_pretty( 'name' );
741
+		return EE_Registry::instance()->CFG->organization->get_pretty('name');
742 742
 	}
743 743
 }
744 744
 
745
-if ( ! function_exists( 'espresso_organization_address' )) {
745
+if ( ! function_exists('espresso_organization_address')) {
746 746
 	/**
747 747
 	 * espresso_organization_address
748 748
 	 * @param string $type
749 749
 	 * @return string
750 750
 	 */
751
-	function espresso_organization_address( $type = 'inline' ) {
752
-		if ( EE_Registry::instance()->CFG->organization instanceof EE_Organization_Config ) {
751
+	function espresso_organization_address($type = 'inline') {
752
+		if (EE_Registry::instance()->CFG->organization instanceof EE_Organization_Config) {
753 753
 			$address = new EventEspresso\core\domain\entities\GenericAddress(
754 754
 				EE_Registry::instance()->CFG->organization->address_1,
755 755
 				EE_Registry::instance()->CFG->organization->address_2,
@@ -758,129 +758,129 @@  discard block
 block discarded – undo
758 758
 				EE_Registry::instance()->CFG->organization->zip,
759 759
 				EE_Registry::instance()->CFG->organization->CNT_ISO
760 760
 			);
761
-			return EEH_Address::format( $address, $type );
761
+			return EEH_Address::format($address, $type);
762 762
 		}
763 763
 		return '';
764 764
 	}
765 765
 }
766 766
 
767
-if ( ! function_exists( 'espresso_organization_email' )) {
767
+if ( ! function_exists('espresso_organization_email')) {
768 768
 	/**
769 769
 	 * espresso_organization_email
770 770
 	 * @param bool $echo
771 771
 	 * @return string
772 772
 	 */
773
-	function espresso_organization_email( $echo = TRUE ) {
774
-		if($echo){
775
-			echo EE_Registry::instance()->CFG->organization->get_pretty( 'email' );
773
+	function espresso_organization_email($echo = TRUE) {
774
+		if ($echo) {
775
+			echo EE_Registry::instance()->CFG->organization->get_pretty('email');
776 776
 			return '';
777 777
 		}
778
-		return EE_Registry::instance()->CFG->organization->get_pretty( 'email' );
778
+		return EE_Registry::instance()->CFG->organization->get_pretty('email');
779 779
 	}
780 780
 }
781 781
 
782
-if ( ! function_exists( 'espresso_organization_logo_url' )) {
782
+if ( ! function_exists('espresso_organization_logo_url')) {
783 783
 	/**
784 784
 	 * espresso_organization_logo_url
785 785
 	 * @param bool $echo
786 786
 	 * @return string
787 787
 	 */
788
-	function espresso_organization_logo_url( $echo = TRUE ) {
789
-		if($echo){
790
-			echo EE_Registry::instance()->CFG->organization->get_pretty( 'logo_url' );
788
+	function espresso_organization_logo_url($echo = TRUE) {
789
+		if ($echo) {
790
+			echo EE_Registry::instance()->CFG->organization->get_pretty('logo_url');
791 791
 			return '';
792 792
 		}
793
-		return EE_Registry::instance()->CFG->organization->get_pretty( 'logo_url' );
793
+		return EE_Registry::instance()->CFG->organization->get_pretty('logo_url');
794 794
 	}
795 795
 }
796 796
 
797
-if ( ! function_exists( 'espresso_organization_facebook' )) {
797
+if ( ! function_exists('espresso_organization_facebook')) {
798 798
 	/**
799 799
 	 * espresso_organization_facebook
800 800
 	 * @param bool $echo
801 801
 	 * @return string
802 802
 	 */
803
-	function espresso_organization_facebook( $echo = TRUE ) {
804
-		if($echo){
805
-			echo EE_Registry::instance()->CFG->organization->get_pretty( 'facebook' );
803
+	function espresso_organization_facebook($echo = TRUE) {
804
+		if ($echo) {
805
+			echo EE_Registry::instance()->CFG->organization->get_pretty('facebook');
806 806
 			return '';
807 807
 		}
808
-		return EE_Registry::instance()->CFG->organization->get_pretty( 'facebook' );
808
+		return EE_Registry::instance()->CFG->organization->get_pretty('facebook');
809 809
 	}
810 810
 }
811 811
 
812
-if ( ! function_exists( 'espresso_organization_twitter' )) {
812
+if ( ! function_exists('espresso_organization_twitter')) {
813 813
 	/**
814 814
 	 * espresso_organization_twitter
815 815
 	 * @param bool $echo
816 816
 	 * @return string
817 817
 	 */
818
-	function espresso_organization_twitter( $echo = TRUE ) {
819
-		if($echo){
820
-			echo EE_Registry::instance()->CFG->organization->get_pretty( 'twitter' );
818
+	function espresso_organization_twitter($echo = TRUE) {
819
+		if ($echo) {
820
+			echo EE_Registry::instance()->CFG->organization->get_pretty('twitter');
821 821
 			return '';
822 822
 		}
823
-		return EE_Registry::instance()->CFG->organization->get_pretty( 'twitter' );
823
+		return EE_Registry::instance()->CFG->organization->get_pretty('twitter');
824 824
 	}
825 825
 }
826 826
 
827
-if ( ! function_exists( 'espresso_organization_linkedin' )) {
827
+if ( ! function_exists('espresso_organization_linkedin')) {
828 828
 	/**
829 829
 	 * espresso_organization_linkedin
830 830
 	 * @param bool $echo
831 831
 	 * @return string
832 832
 	 */
833
-	function espresso_organization_linkedin( $echo = TRUE ) {
834
-		if($echo){
835
-			echo EE_Registry::instance()->CFG->organization->get_pretty( 'linkedin' );
833
+	function espresso_organization_linkedin($echo = TRUE) {
834
+		if ($echo) {
835
+			echo EE_Registry::instance()->CFG->organization->get_pretty('linkedin');
836 836
 			return '';
837 837
 		}
838
-		return EE_Registry::instance()->CFG->organization->get_pretty( 'linkedin' );
838
+		return EE_Registry::instance()->CFG->organization->get_pretty('linkedin');
839 839
 	}
840 840
 }
841 841
 
842
-if ( ! function_exists( 'espresso_organization_pinterest' )) {
842
+if ( ! function_exists('espresso_organization_pinterest')) {
843 843
 	/**
844 844
 	 * espresso_organization_pinterest
845 845
 	 * @param bool $echo
846 846
 	 * @return string
847 847
 	 */
848
-	function espresso_organization_pinterest( $echo = TRUE ) {
849
-		if($echo){
850
-			echo EE_Registry::instance()->CFG->organization->get_pretty( 'pinterest' );
848
+	function espresso_organization_pinterest($echo = TRUE) {
849
+		if ($echo) {
850
+			echo EE_Registry::instance()->CFG->organization->get_pretty('pinterest');
851 851
 			return '';
852 852
 		}
853
-		return EE_Registry::instance()->CFG->organization->get_pretty( 'pinterest' );
853
+		return EE_Registry::instance()->CFG->organization->get_pretty('pinterest');
854 854
 	}
855 855
 }
856 856
 
857
-if ( ! function_exists( 'espresso_organization_google' )) {
857
+if ( ! function_exists('espresso_organization_google')) {
858 858
 	/**
859 859
 	 * espresso_organization_google
860 860
 	 * @param bool $echo
861 861
 	 * @return string
862 862
 	 */
863
-	function espresso_organization_google( $echo = TRUE ) {
864
-		if($echo){
865
-			echo EE_Registry::instance()->CFG->organization->get_pretty( 'google' );
863
+	function espresso_organization_google($echo = TRUE) {
864
+		if ($echo) {
865
+			echo EE_Registry::instance()->CFG->organization->get_pretty('google');
866 866
 			return '';
867 867
 		}
868
-		return EE_Registry::instance()->CFG->organization->get_pretty( 'google' );
868
+		return EE_Registry::instance()->CFG->organization->get_pretty('google');
869 869
 	}
870 870
 }
871 871
 
872
-if ( ! function_exists( 'espresso_organization_instagram' )) {
872
+if ( ! function_exists('espresso_organization_instagram')) {
873 873
 	/**
874 874
 	 * espresso_organization_instagram
875 875
 	 * @param bool $echo
876 876
 	 * @return string
877 877
 	 */
878
-	function espresso_organization_instagram( $echo = TRUE ) {
879
-		if($echo){
880
-			echo EE_Registry::instance()->CFG->organization->get_pretty( 'instagram' );
878
+	function espresso_organization_instagram($echo = TRUE) {
879
+		if ($echo) {
880
+			echo EE_Registry::instance()->CFG->organization->get_pretty('instagram');
881 881
 			return '';
882 882
 		}
883
-		return EE_Registry::instance()->CFG->organization->get_pretty( 'instagram' );
883
+		return EE_Registry::instance()->CFG->organization->get_pretty('instagram');
884 884
 	}
885 885
 }
886 886
 
@@ -890,7 +890,7 @@  discard block
 block discarded – undo
890 890
 
891 891
 
892 892
 
893
-if ( ! function_exists( 'espresso_event_venues' )) {
893
+if ( ! function_exists('espresso_event_venues')) {
894 894
 	/**
895 895
 	 * espresso_event_venues
896 896
 	 *
@@ -904,7 +904,7 @@  discard block
 block discarded – undo
904 904
 
905 905
 
906 906
 
907
-if ( ! function_exists( 'espresso_venue_id' )) {
907
+if ( ! function_exists('espresso_venue_id')) {
908 908
 	/**
909 909
 	 *    espresso_venue_name
910 910
 	 *
@@ -912,15 +912,15 @@  discard block
 block discarded – undo
912 912
 	 * @param     int $EVT_ID
913 913
 	 * @return    string
914 914
 	 */
915
-	function espresso_venue_id( $EVT_ID = 0 ) {
916
-		$venue = EEH_Venue_View::get_venue( $EVT_ID );
915
+	function espresso_venue_id($EVT_ID = 0) {
916
+		$venue = EEH_Venue_View::get_venue($EVT_ID);
917 917
 		return $venue instanceof EE_Venue ? $venue->ID() : 0;
918 918
 	}
919 919
 }
920 920
 
921 921
 
922 922
 
923
-if ( ! function_exists( 'espresso_is_venue_private' ) ) {
923
+if ( ! function_exists('espresso_is_venue_private')) {
924 924
 	/**
925 925
 	 * Return whether a venue is private or not.
926 926
 	 * @see EEH_Venue_View::get_venue() for more info on expected return results.
@@ -929,45 +929,45 @@  discard block
 block discarded – undo
929 929
 	 *
930 930
 	 * @return bool | null
931 931
 	 */
932
-	function espresso_is_venue_private( $VNU_ID = 0 ) {
933
-		return EEH_Venue_View::is_venue_private( $VNU_ID );
932
+	function espresso_is_venue_private($VNU_ID = 0) {
933
+		return EEH_Venue_View::is_venue_private($VNU_ID);
934 934
 	}
935 935
 }
936 936
 
937 937
 
938 938
 
939
-if ( ! function_exists( 'espresso_venue_is_password_protected' ) ) {
939
+if ( ! function_exists('espresso_venue_is_password_protected')) {
940 940
 	/**
941 941
 	 * returns true or false if a venue is password protected or not
942 942
 	 *
943 943
 	 * @param int     $VNU_ID optional, the venue id to check.
944 944
 	 * @return string
945 945
 	 */
946
-	function espresso_venue_is_password_protected( $VNU_ID = 0 ) {
947
-		EE_Registry::instance()->load_helper( 'Venue_View' );
948
-		return EEH_Venue_View::is_venue_password_protected( $VNU_ID );
946
+	function espresso_venue_is_password_protected($VNU_ID = 0) {
947
+		EE_Registry::instance()->load_helper('Venue_View');
948
+		return EEH_Venue_View::is_venue_password_protected($VNU_ID);
949 949
 	}
950 950
 }
951 951
 
952 952
 
953 953
 
954
-if ( ! function_exists( 'espresso_password_protected_venue_form' ) ) {
954
+if ( ! function_exists('espresso_password_protected_venue_form')) {
955 955
 	/**
956 956
 	 * Returns a password form if venue is password protected.
957 957
 	 *
958 958
 	 * @param int     $VNU_ID optional, the venue id to check.
959 959
 	 * @return string
960 960
 	 */
961
-	function espresso_password_protected_venue_form( $VNU_ID = 0 ) {
962
-		EE_Registry::instance()->load_helper( 'Venue_View' );
963
-		return EEH_Venue_View::password_protected_venue_form( $VNU_ID );
961
+	function espresso_password_protected_venue_form($VNU_ID = 0) {
962
+		EE_Registry::instance()->load_helper('Venue_View');
963
+		return EEH_Venue_View::password_protected_venue_form($VNU_ID);
964 964
 	}
965 965
 }
966 966
 
967 967
 
968 968
 
969 969
 
970
-if ( ! function_exists( 'espresso_venue_name' )) {
970
+if ( ! function_exists('espresso_venue_name')) {
971 971
 	/**
972 972
 	 *    espresso_venue_name
973 973
 	 *
@@ -977,19 +977,19 @@  discard block
 block discarded – undo
977 977
 	 * @param bool   $echo
978 978
 	 * @return    string
979 979
 	 */
980
-	function espresso_venue_name( $VNU_ID = 0, $link_to = 'details', $echo = TRUE ) {
981
-		if($echo){
982
-			echo EEH_Venue_View::venue_name( $link_to, $VNU_ID );
980
+	function espresso_venue_name($VNU_ID = 0, $link_to = 'details', $echo = TRUE) {
981
+		if ($echo) {
982
+			echo EEH_Venue_View::venue_name($link_to, $VNU_ID);
983 983
 			return '';
984 984
 		}
985
-		return EEH_Venue_View::venue_name( $link_to, $VNU_ID );
985
+		return EEH_Venue_View::venue_name($link_to, $VNU_ID);
986 986
 	}
987 987
 }
988 988
 
989 989
 
990 990
 
991 991
 
992
-if ( ! function_exists( 'espresso_venue_link' )) {
992
+if ( ! function_exists('espresso_venue_link')) {
993 993
 	/**
994 994
 	 * 	espresso_venue_link
995 995
 	 *
@@ -998,14 +998,14 @@  discard block
 block discarded – undo
998 998
 	 *  @param 	string 	$text
999 999
 	 *  @return 	string
1000 1000
 	 */
1001
-	function espresso_venue_link( $VNU_ID = 0, $text = '' ) {
1002
-		return EEH_Venue_View::venue_details_link( $VNU_ID, $text );
1001
+	function espresso_venue_link($VNU_ID = 0, $text = '') {
1002
+		return EEH_Venue_View::venue_details_link($VNU_ID, $text);
1003 1003
 	}
1004 1004
 }
1005 1005
 
1006 1006
 
1007 1007
 
1008
-if ( ! function_exists( 'espresso_venue_description' )) {
1008
+if ( ! function_exists('espresso_venue_description')) {
1009 1009
 	/**
1010 1010
 	 *    espresso_venue_description
1011 1011
 	 *
@@ -1014,17 +1014,17 @@  discard block
 block discarded – undo
1014 1014
 	 * @param bool $echo
1015 1015
 	 * @return    string
1016 1016
 	 */
1017
-	function espresso_venue_description( $VNU_ID = FALSE, $echo = TRUE ) {
1018
-		if($echo){
1019
-			echo EEH_Venue_View::venue_description( $VNU_ID );
1017
+	function espresso_venue_description($VNU_ID = FALSE, $echo = TRUE) {
1018
+		if ($echo) {
1019
+			echo EEH_Venue_View::venue_description($VNU_ID);
1020 1020
 			return '';
1021 1021
 		}
1022
-		return EEH_Venue_View::venue_description( $VNU_ID );
1022
+		return EEH_Venue_View::venue_description($VNU_ID);
1023 1023
 	}
1024 1024
 }
1025 1025
 
1026 1026
 
1027
-if ( ! function_exists( 'espresso_venue_excerpt' )) {
1027
+if ( ! function_exists('espresso_venue_excerpt')) {
1028 1028
 	/**
1029 1029
 	 *    espresso_venue_excerpt
1030 1030
 	 *
@@ -1033,18 +1033,18 @@  discard block
 block discarded – undo
1033 1033
 	 * @param bool $echo
1034 1034
 	 * @return    string
1035 1035
 	 */
1036
-	function espresso_venue_excerpt( $VNU_ID = 0,  $echo = TRUE ) {
1037
-		if ( $echo ) {
1038
-			echo EEH_Venue_View::venue_excerpt( $VNU_ID );
1036
+	function espresso_venue_excerpt($VNU_ID = 0, $echo = TRUE) {
1037
+		if ($echo) {
1038
+			echo EEH_Venue_View::venue_excerpt($VNU_ID);
1039 1039
 			return '';
1040 1040
 		}
1041
-		return EEH_Venue_View::venue_excerpt( $VNU_ID );
1041
+		return EEH_Venue_View::venue_excerpt($VNU_ID);
1042 1042
 	}
1043 1043
 }
1044 1044
 
1045 1045
 
1046 1046
 
1047
-if ( ! function_exists( 'espresso_venue_categories' )) {
1047
+if ( ! function_exists('espresso_venue_categories')) {
1048 1048
 	/**
1049 1049
 	 * espresso_venue_categories
1050 1050
 	 * returns the terms associated with a venue
@@ -1054,17 +1054,17 @@  discard block
 block discarded – undo
1054 1054
 	 * @param bool $echo
1055 1055
 	 * @return string
1056 1056
 	 */
1057
-	function espresso_venue_categories( $VNU_ID = 0, $hide_uncategorized = TRUE,  $echo = TRUE ) {
1058
-		if ( $echo ) {
1059
-			echo EEH_Venue_View::venue_categories( $VNU_ID, $hide_uncategorized );
1057
+	function espresso_venue_categories($VNU_ID = 0, $hide_uncategorized = TRUE, $echo = TRUE) {
1058
+		if ($echo) {
1059
+			echo EEH_Venue_View::venue_categories($VNU_ID, $hide_uncategorized);
1060 1060
 			return '';
1061 1061
 		}
1062
-		return EEH_Venue_View::venue_categories( $VNU_ID, $hide_uncategorized );
1062
+		return EEH_Venue_View::venue_categories($VNU_ID, $hide_uncategorized);
1063 1063
 	}
1064 1064
 }
1065 1065
 
1066 1066
 
1067
-if ( ! function_exists( 'espresso_venue_address' )) {
1067
+if ( ! function_exists('espresso_venue_address')) {
1068 1068
 	/**
1069 1069
 	 * espresso_venue_address
1070 1070
 	 * returns a formatted block of html  for displaying a venue's address
@@ -1074,17 +1074,17 @@  discard block
 block discarded – undo
1074 1074
 	 * @param bool   $echo
1075 1075
 	 * @return string
1076 1076
 	 */
1077
-	function espresso_venue_address( $type = 'multiline', $VNU_ID = 0, $echo = TRUE ) {
1078
-		if ( $echo ) {
1079
-			echo EEH_Venue_View::venue_address( $type, $VNU_ID );
1077
+	function espresso_venue_address($type = 'multiline', $VNU_ID = 0, $echo = TRUE) {
1078
+		if ($echo) {
1079
+			echo EEH_Venue_View::venue_address($type, $VNU_ID);
1080 1080
 			return '';
1081 1081
 		}
1082
-		return EEH_Venue_View::venue_address( $type, $VNU_ID );
1082
+		return EEH_Venue_View::venue_address($type, $VNU_ID);
1083 1083
 	}
1084 1084
 }
1085 1085
 
1086 1086
 
1087
-if ( ! function_exists( 'espresso_venue_raw_address' )) {
1087
+if ( ! function_exists('espresso_venue_raw_address')) {
1088 1088
 	/**
1089 1089
 	 * espresso_venue_address
1090 1090
 	 * returns an UN-formatted string containing a venue's address
@@ -1094,17 +1094,17 @@  discard block
 block discarded – undo
1094 1094
 	 * @param bool     $echo
1095 1095
 	 * @return string
1096 1096
 	 */
1097
-	function espresso_venue_raw_address( $type = 'multiline', $VNU_ID = 0, $echo = TRUE ) {
1098
-		if ( $echo ) {
1099
-			echo EEH_Venue_View::venue_address( $type, $VNU_ID, FALSE, FALSE );
1097
+	function espresso_venue_raw_address($type = 'multiline', $VNU_ID = 0, $echo = TRUE) {
1098
+		if ($echo) {
1099
+			echo EEH_Venue_View::venue_address($type, $VNU_ID, FALSE, FALSE);
1100 1100
 			return '';
1101 1101
 		}
1102
-		return EEH_Venue_View::venue_address( $type, $VNU_ID, FALSE, FALSE );
1102
+		return EEH_Venue_View::venue_address($type, $VNU_ID, FALSE, FALSE);
1103 1103
 	}
1104 1104
 }
1105 1105
 
1106 1106
 
1107
-if ( ! function_exists( 'espresso_venue_has_address' )) {
1107
+if ( ! function_exists('espresso_venue_has_address')) {
1108 1108
 	/**
1109 1109
 	 * espresso_venue_has_address
1110 1110
 	 * returns TRUE or FALSE if a Venue has address information
@@ -1112,13 +1112,13 @@  discard block
 block discarded – undo
1112 1112
 	 * @param int $VNU_ID
1113 1113
 	 * @return bool
1114 1114
 	 */
1115
-	function espresso_venue_has_address( $VNU_ID = 0 ) {
1116
-		return EEH_Venue_View::venue_has_address( $VNU_ID );
1115
+	function espresso_venue_has_address($VNU_ID = 0) {
1116
+		return EEH_Venue_View::venue_has_address($VNU_ID);
1117 1117
 	}
1118 1118
 }
1119 1119
 
1120 1120
 
1121
-if ( ! function_exists( 'espresso_venue_gmap' )) {
1121
+if ( ! function_exists('espresso_venue_gmap')) {
1122 1122
 	/**
1123 1123
 	 * espresso_venue_gmap
1124 1124
 	 * returns a google map for the venue address
@@ -1129,17 +1129,17 @@  discard block
 block discarded – undo
1129 1129
 	 * @param bool     $echo
1130 1130
 	 * @return string
1131 1131
 	 */
1132
-	function espresso_venue_gmap( $VNU_ID = 0, $map_ID = FALSE, $gmap = array(), $echo = TRUE  ) {
1133
-		if ( $echo ) {
1134
-			echo EEH_Venue_View::venue_gmap( $VNU_ID, $map_ID, $gmap );
1132
+	function espresso_venue_gmap($VNU_ID = 0, $map_ID = FALSE, $gmap = array(), $echo = TRUE) {
1133
+		if ($echo) {
1134
+			echo EEH_Venue_View::venue_gmap($VNU_ID, $map_ID, $gmap);
1135 1135
 			return '';
1136 1136
 		}
1137
-		return EEH_Venue_View::venue_gmap( $VNU_ID, $map_ID, $gmap );
1137
+		return EEH_Venue_View::venue_gmap($VNU_ID, $map_ID, $gmap);
1138 1138
 	}
1139 1139
 }
1140 1140
 
1141 1141
 
1142
-if ( ! function_exists( 'espresso_venue_phone' )) {
1142
+if ( ! function_exists('espresso_venue_phone')) {
1143 1143
 	/**
1144 1144
 	 * espresso_venue_phone
1145 1145
 	 *
@@ -1147,18 +1147,18 @@  discard block
 block discarded – undo
1147 1147
 	 * @param bool $echo
1148 1148
 	 * @return string
1149 1149
 	 */
1150
-	function espresso_venue_phone( $VNU_ID = 0, $echo = TRUE ) {
1151
-		if ( $echo ) {
1152
-			echo EEH_Venue_View::venue_phone( $VNU_ID );
1150
+	function espresso_venue_phone($VNU_ID = 0, $echo = TRUE) {
1151
+		if ($echo) {
1152
+			echo EEH_Venue_View::venue_phone($VNU_ID);
1153 1153
 			return '';
1154 1154
 		}
1155
-		return EEH_Venue_View::venue_phone( $VNU_ID );
1155
+		return EEH_Venue_View::venue_phone($VNU_ID);
1156 1156
 	}
1157 1157
 }
1158 1158
 
1159 1159
 
1160 1160
 
1161
-if ( ! function_exists( 'espresso_venue_website' )) {
1161
+if ( ! function_exists('espresso_venue_website')) {
1162 1162
 	/**
1163 1163
 	 * espresso_venue_website
1164 1164
 	 *
@@ -1166,18 +1166,18 @@  discard block
 block discarded – undo
1166 1166
 	 * @param bool $echo
1167 1167
 	 * @return string
1168 1168
 	 */
1169
-	function espresso_venue_website( $VNU_ID = 0, $echo = TRUE ) {
1170
-		if ( $echo ) {
1171
-			echo EEH_Venue_View::venue_website_link( $VNU_ID );
1169
+	function espresso_venue_website($VNU_ID = 0, $echo = TRUE) {
1170
+		if ($echo) {
1171
+			echo EEH_Venue_View::venue_website_link($VNU_ID);
1172 1172
 			return '';
1173 1173
 		}
1174
-		return EEH_Venue_View::venue_website_link( $VNU_ID );
1174
+		return EEH_Venue_View::venue_website_link($VNU_ID);
1175 1175
 	}
1176 1176
 }
1177 1177
 
1178 1178
 
1179 1179
 
1180
-if ( ! function_exists( 'espresso_edit_venue_link' )) {
1180
+if ( ! function_exists('espresso_edit_venue_link')) {
1181 1181
 	/**
1182 1182
 	 * espresso_edit_venue_link
1183 1183
 	 *
@@ -1185,12 +1185,12 @@  discard block
 block discarded – undo
1185 1185
 	 * @param bool $echo
1186 1186
 	 * @return string
1187 1187
 	 */
1188
-	function espresso_edit_venue_link( $VNU_ID = 0, $echo = TRUE ) {
1189
-		if($echo){
1190
-			echo EEH_Venue_View::edit_venue_link( $VNU_ID );
1188
+	function espresso_edit_venue_link($VNU_ID = 0, $echo = TRUE) {
1189
+		if ($echo) {
1190
+			echo EEH_Venue_View::edit_venue_link($VNU_ID);
1191 1191
 			return '';
1192 1192
 		}
1193
-		return EEH_Venue_View::edit_venue_link( $VNU_ID );
1193
+		return EEH_Venue_View::edit_venue_link($VNU_ID);
1194 1194
 	}
1195 1195
 }
1196 1196
 
Please login to merge, or discard this patch.