Completed
Branch dev (97838e)
by
unknown
18:15 queued 10:24
created
core/db_models/EEM_Attendee.model.php 1 patch
Indentation   +419 added lines, -419 removed lines patch added patch discarded remove patch
@@ -12,432 +12,432 @@
 block discarded – undo
12 12
  */
13 13
 class EEM_Attendee extends EEM_CPT_Base
14 14
 {
15
-    // private instance of the Attendee object
16
-    protected static $_instance = null;
15
+	// private instance of the Attendee object
16
+	protected static $_instance = null;
17 17
 
18
-    /**
19
-     * QST_system for questions are strings not integers now,
20
-     * so these constants are deprecated.
21
-     * Please instead use the EEM_Attendee::system_question_* constants
22
-     *
23
-     * @deprecated
24
-     */
25
-    const fname_question_id = 1;
18
+	/**
19
+	 * QST_system for questions are strings not integers now,
20
+	 * so these constants are deprecated.
21
+	 * Please instead use the EEM_Attendee::system_question_* constants
22
+	 *
23
+	 * @deprecated
24
+	 */
25
+	const fname_question_id = 1;
26 26
 
27
-    /**
28
-     * @deprecated
29
-     */
30
-    const lname_question_id = 2;
27
+	/**
28
+	 * @deprecated
29
+	 */
30
+	const lname_question_id = 2;
31 31
 
32 32
 
33
-    /**
34
-     * @deprecated
35
-     */
36
-    const email_question_id = 3;
33
+	/**
34
+	 * @deprecated
35
+	 */
36
+	const email_question_id = 3;
37 37
 
38 38
 
39
-    /**
40
-     * @deprecated
41
-     */
42
-    const address_question_id = 4;
39
+	/**
40
+	 * @deprecated
41
+	 */
42
+	const address_question_id = 4;
43 43
 
44 44
 
45
-    /**
46
-     * @deprecated
47
-     */
48
-    const address2_question_id = 5;
45
+	/**
46
+	 * @deprecated
47
+	 */
48
+	const address2_question_id = 5;
49 49
 
50
-
51
-    /**
52
-     * @deprecated
53
-     */
54
-    const city_question_id = 6;
55
-
56
-
57
-    /**
58
-     * @deprecated
59
-     */
60
-    const state_question_id = 7;
61
-
62
-
63
-    /**
64
-     * @deprecated
65
-     */
66
-    const country_question_id = 8;
67
-
68
-
69
-    /**
70
-     * @deprecated
71
-     */
72
-    const zip_question_id = 9;
73
-
74
-
75
-    /**
76
-     * @deprecated
77
-     */
78
-    const phone_question_id = 10;
79
-
80
-    /**
81
-     * When looking for questions that correspond to attendee fields,
82
-     * look for the question with this QST_system value.
83
-     * These replace the old constants like EEM_Attendee::*_question_id
84
-     */
85
-    const system_question_fname = 'fname';
86
-
87
-    const system_question_lname = 'lname';
88
-
89
-    const system_question_email = 'email';
90
-
91
-    const system_question_email_confirm = 'email_confirm';
92
-
93
-    const system_question_address = 'address';
94
-
95
-    const system_question_address2 = 'address2';
96
-
97
-    const system_question_city = 'city';
98
-
99
-    const system_question_state = 'state';
100
-
101
-    const system_question_country = 'country';
102
-
103
-    const system_question_zip = 'zip';
104
-
105
-    const system_question_phone = 'phone';
106
-
107
-    /**
108
-     * Keys are all the EEM_Attendee::system_question_* constants, which are
109
-     * also all the values of QST_system in the questions table, and values
110
-     * are their corresponding Attendee field names
111
-     *
112
-     * @var array
113
-     */
114
-    protected $_system_question_to_attendee_field_name = array(
115
-        EEM_Attendee::system_question_fname    => 'ATT_fname',
116
-        EEM_Attendee::system_question_lname    => 'ATT_lname',
117
-        EEM_Attendee::system_question_email    => 'ATT_email',
118
-        EEM_Attendee::system_question_address  => 'ATT_address',
119
-        EEM_Attendee::system_question_address2 => 'ATT_address2',
120
-        EEM_Attendee::system_question_city     => 'ATT_city',
121
-        EEM_Attendee::system_question_state    => 'STA_ID',
122
-        EEM_Attendee::system_question_country  => 'CNT_ISO',
123
-        EEM_Attendee::system_question_zip      => 'ATT_zip',
124
-        EEM_Attendee::system_question_phone    => 'ATT_phone',
125
-    );
126
-
127
-
128
-
129
-    /**
130
-     * EEM_Attendee constructor.
131
-     *
132
-     * @param null              $timezone
133
-     * @param ModelFieldFactory $model_field_factory
134
-     * @throws EE_Error
135
-     * @throws InvalidArgumentException
136
-     */
137
-    protected function __construct($timezone, ModelFieldFactory $model_field_factory)
138
-    {
139
-        $this->singular_item = esc_html__('Attendee', 'event_espresso');
140
-        $this->plural_item = esc_html__('Attendees', 'event_espresso');
141
-        $this->_tables = array(
142
-            'Attendee_CPT'  => new EE_Primary_Table('posts', 'ID'),
143
-            'Attendee_Meta' => new EE_Secondary_Table(
144
-                'esp_attendee_meta',
145
-                'ATTM_ID',
146
-                'ATT_ID'
147
-            ),
148
-        );
149
-        $this->_fields = array(
150
-            'Attendee_CPT'  => array(
151
-                'ATT_ID'        => $model_field_factory->createPrimaryKeyIntField(
152
-                    'ID',
153
-                    esc_html__('Attendee ID', 'event_espresso')
154
-                ),
155
-                'ATT_full_name' => $model_field_factory->createPlainTextField(
156
-                    'post_title',
157
-                    esc_html__('Attendee Full Name', 'event_espresso'),
158
-                    false,
159
-                    esc_html__('Unknown', 'event_espresso')
160
-                ),
161
-                'ATT_bio'       => $model_field_factory->createPostContentField(
162
-                    'post_content',
163
-                    esc_html__('Attendee Biography', 'event_espresso'),
164
-                    false,
165
-                    esc_html__('No Biography Provided', 'event_espresso')
166
-                ),
167
-                'ATT_slug'      => $model_field_factory->createSlugField(
168
-                    'post_name',
169
-                    esc_html__('Attendee URL Slug', 'event_espresso')
170
-                ),
171
-                'ATT_created'   => $model_field_factory->createDatetimeField(
172
-                    'post_date',
173
-                    esc_html__('Time Attendee Created', 'event_espresso')
174
-                ),
175
-                'ATT_short_bio' => $model_field_factory->createSimpleHtmlField(
176
-                    'post_excerpt',
177
-                    esc_html__('Attendee Short Biography', 'event_espresso'),
178
-                    true,
179
-                    esc_html__('No Biography Provided', 'event_espresso')
180
-                ),
181
-                'ATT_modified'  => $model_field_factory->createDatetimeField(
182
-                    'post_modified',
183
-                    esc_html__('Time Attendee Last Modified', 'event_espresso')
184
-                ),
185
-                'ATT_author'    => $model_field_factory->createWpUserField(
186
-                    'post_author',
187
-                    esc_html__('Creator ID of the first Event attended', 'event_espresso'),
188
-                    false
189
-                ),
190
-                'ATT_parent'    => $model_field_factory->createDbOnlyIntField(
191
-                    'post_parent',
192
-                    esc_html__('Parent Attendee (unused)', 'event_espresso'),
193
-                    false,
194
-                    0
195
-                ),
196
-                'post_type'     => $model_field_factory->createWpPostTypeField('espresso_attendees'),
197
-                'status'        => $model_field_factory->createWpPostStatusField(
198
-                    'post_status',
199
-                    esc_html__('Attendee Status', 'event_espresso'),
200
-                    false,
201
-                    'publish'
202
-                ),
203
-                'password' => new EE_Password_Field(
204
-                    'post_password',
205
-                    esc_html__('Password', 'event_espresso'),
206
-                    false,
207
-                    '',
208
-                    array(
209
-                        'ATT_bio',
210
-                        'ATT_short_bio',
211
-                        'ATT_address',
212
-                        'ATT_address2',
213
-                        'ATT_city',
214
-                        'STA_ID',
215
-                        'CNT_ISO',
216
-                        'ATT_zip',
217
-                        'ATT_email',
218
-                        'ATT_phone'
219
-                    )
220
-                )
221
-            ),
222
-            'Attendee_Meta' => array(
223
-                'ATTM_ID'      => $model_field_factory->createDbOnlyIntField(
224
-                    'ATTM_ID',
225
-                    esc_html__('Attendee Meta Row ID', 'event_espresso'),
226
-                    false
227
-                ),
228
-                'ATT_ID_fk'    => $model_field_factory->createDbOnlyIntField(
229
-                    'ATT_ID',
230
-                    esc_html__('Foreign Key to Attendee in Post Table', 'event_espresso'),
231
-                    false
232
-                ),
233
-                'ATT_fname'    => $model_field_factory->createPlainTextField(
234
-                    'ATT_fname',
235
-                    esc_html__('First Name', 'event_espresso')
236
-                ),
237
-                'ATT_lname'    => $model_field_factory->createPlainTextField(
238
-                    'ATT_lname',
239
-                    esc_html__('Last Name', 'event_espresso')
240
-                ),
241
-                'ATT_address'  => $model_field_factory->createPlainTextField(
242
-                    'ATT_address',
243
-                    esc_html__('Address Part 1', 'event_espresso')
244
-                ),
245
-                'ATT_address2' => $model_field_factory->createPlainTextField(
246
-                    'ATT_address2',
247
-                    esc_html__('Address Part 2', 'event_espresso')
248
-                ),
249
-                'ATT_city'     => $model_field_factory->createPlainTextField(
250
-                    'ATT_city',
251
-                    esc_html__('City', 'event_espresso')
252
-                ),
253
-                'STA_ID'       => $model_field_factory->createForeignKeyIntField(
254
-                    'STA_ID',
255
-                    esc_html__('State', 'event_espresso'),
256
-                    true,
257
-                    0,
258
-                    'State'
259
-                ),
260
-                'CNT_ISO'      => $model_field_factory->createForeignKeyStringField(
261
-                    'CNT_ISO',
262
-                    esc_html__('Country', 'event_espresso'),
263
-                    true,
264
-                    '',
265
-                    'Country'
266
-                ),
267
-                'ATT_zip'      => $model_field_factory->createPlainTextField(
268
-                    'ATT_zip',
269
-                    esc_html__('ZIP/Postal Code', 'event_espresso')
270
-                ),
271
-                'ATT_email'    => $model_field_factory->createEmailField(
272
-                    'ATT_email',
273
-                    esc_html__('Email Address', 'event_espresso')
274
-                ),
275
-                'ATT_phone'    => $model_field_factory->createPlainTextField(
276
-                    'ATT_phone',
277
-                    esc_html__('Phone', 'event_espresso')
278
-                ),
279
-            ),
280
-        );
281
-        $this->_model_relations = array(
282
-            'Registration'      => new EE_Has_Many_Relation(),
283
-            'State'             => new EE_Belongs_To_Relation(),
284
-            'Country'           => new EE_Belongs_To_Relation(),
285
-            'Event'             => new EE_HABTM_Relation('Registration', false),
286
-            'WP_User'           => new EE_Belongs_To_Relation(),
287
-            'Message'           => new EE_Has_Many_Any_Relation(false),
288
-            // allow deletion of attendees even if they have messages in the queue for them.
289
-            'Term_Relationship' => new EE_Has_Many_Relation(),
290
-            'Term_Taxonomy'     => new EE_HABTM_Relation('Term_Relationship'),
291
-        );
292
-        $this->_caps_slug = 'contacts';
293
-        $this->model_chain_to_password = '';
294
-        parent::__construct($timezone);
295
-    }
296
-
297
-
298
-
299
-    /**
300
-     * Gets the name of the field on the attendee model corresponding to the system question string
301
-     * which should be one of the keys from EEM_Attendee::_system_question_to_attendee_field_name
302
-     *
303
-     * @param string $system_question_string
304
-     * @return string|null if not found
305
-     */
306
-    public function get_attendee_field_for_system_question($system_question_string)
307
-    {
308
-        return isset($this->_system_question_to_attendee_field_name[ $system_question_string ])
309
-            ? $this->_system_question_to_attendee_field_name[ $system_question_string ]
310
-            : null;
311
-    }
312
-
313
-
314
-
315
-    /**
316
-     * Gets mapping from esp_question.QST_system values to their corresponding attendee field names
317
-     *
318
-     * @return array
319
-     */
320
-    public function system_question_to_attendee_field_mapping()
321
-    {
322
-        return $this->_system_question_to_attendee_field_name;
323
-    }
324
-
325
-
326
-
327
-    /**
328
-     * Gets all the attendees for a transaction (by using the esp_registration as a join table)
329
-     *
330
-     * @param EE_Transaction /int $transaction_id_or_obj EE_Transaction or its ID
331
-     * @return EE_Attendee[]|EE_Base_Class[]
332
-     * @throws EE_Error
333
-     */
334
-    public function get_attendees_for_transaction($transaction_id_or_obj)
335
-    {
336
-        return $this->get_all(
337
-            array(
338
-                array(
339
-                    'Registration.Transaction.TXN_ID' => $transaction_id_or_obj instanceof EE_Transaction
340
-                        ? $transaction_id_or_obj->ID()
341
-                        : $transaction_id_or_obj,
342
-                ),
343
-            )
344
-        );
345
-    }
346
-
347
-
348
-
349
-    /**
350
-     * retrieve  a single attendee from db via their ID
351
-     *
352
-     * @param $ATT_ID
353
-     * @return mixed array on success, FALSE on fail
354
-     * @deprecated
355
-     */
356
-    public function get_attendee_by_ID($ATT_ID = false)
357
-    {
358
-        // retrieve a particular EE_Attendee
359
-        return $this->get_one_by_ID($ATT_ID);
360
-    }
361
-
362
-
363
-
364
-    /**
365
-     * retrieve  a single attendee from db via their ID
366
-     *
367
-     * @param array $where_cols_n_values
368
-     * @return mixed array on success, FALSE on fail
369
-     * @throws EE_Error
370
-     */
371
-    public function get_attendee($where_cols_n_values = array())
372
-    {
373
-        if (empty($where_cols_n_values)) {
374
-            return false;
375
-        }
376
-        $attendee = $this->get_all(array($where_cols_n_values));
377
-        if (! empty($attendee)) {
378
-            return array_shift($attendee);
379
-        }
380
-        return false;
381
-    }
382
-
383
-
384
-
385
-    /**
386
-     * Search for an existing Attendee record in the DB
387
-     *
388
-     * @param array $where_cols_n_values
389
-     * @return bool|mixed
390
-     * @throws EE_Error
391
-     */
392
-    public function find_existing_attendee($where_cols_n_values = null)
393
-    {
394
-        // search by combo of first and last names plus the email address
395
-        $attendee_data_keys = array(
396
-            'ATT_fname' => $this->_ATT_fname,
397
-            'ATT_lname' => $this->_ATT_lname,
398
-            'ATT_email' => $this->_ATT_email,
399
-        );
400
-        // no search params means attendee object already exists.
401
-        $where_cols_n_values = is_array($where_cols_n_values) && ! empty($where_cols_n_values)
402
-            ? $where_cols_n_values
403
-            : $attendee_data_keys;
404
-        $valid_data = true;
405
-        // check for required values
406
-        $valid_data = isset($where_cols_n_values['ATT_fname']) && ! empty($where_cols_n_values['ATT_fname'])
407
-            ? $valid_data
408
-            : false;
409
-        $valid_data = isset($where_cols_n_values['ATT_lname']) && ! empty($where_cols_n_values['ATT_lname'])
410
-            ? $valid_data
411
-            : false;
412
-        $valid_data = isset($where_cols_n_values['ATT_email']) && ! empty($where_cols_n_values['ATT_email'])
413
-            ? $valid_data
414
-            : false;
415
-        if ($valid_data) {
416
-            $attendee = $this->get_attendee($where_cols_n_values);
417
-            if ($attendee instanceof EE_Attendee) {
418
-                return $attendee;
419
-            }
420
-        }
421
-        return false;
422
-    }
423
-
424
-
425
-
426
-    /**
427
-     * Takes an incoming array of EE_Registration ids
428
-     * and sends back a list of corresponding non duplicate EE_Attendee objects.
429
-     *
430
-     * @since  4.3.0
431
-     * @param  array $ids array of EE_Registration ids
432
-     * @return EE_Attendee[]|EE_Base_Class[]
433
-     * @throws EE_Error
434
-     */
435
-    public function get_array_of_contacts_from_reg_ids($ids)
436
-    {
437
-        $ids = (array) $ids;
438
-        $_where = array(
439
-            'Registration.REG_ID' => array('in', $ids),
440
-        );
441
-        return $this->get_all(array($_where));
442
-    }
50
+
51
+	/**
52
+	 * @deprecated
53
+	 */
54
+	const city_question_id = 6;
55
+
56
+
57
+	/**
58
+	 * @deprecated
59
+	 */
60
+	const state_question_id = 7;
61
+
62
+
63
+	/**
64
+	 * @deprecated
65
+	 */
66
+	const country_question_id = 8;
67
+
68
+
69
+	/**
70
+	 * @deprecated
71
+	 */
72
+	const zip_question_id = 9;
73
+
74
+
75
+	/**
76
+	 * @deprecated
77
+	 */
78
+	const phone_question_id = 10;
79
+
80
+	/**
81
+	 * When looking for questions that correspond to attendee fields,
82
+	 * look for the question with this QST_system value.
83
+	 * These replace the old constants like EEM_Attendee::*_question_id
84
+	 */
85
+	const system_question_fname = 'fname';
86
+
87
+	const system_question_lname = 'lname';
88
+
89
+	const system_question_email = 'email';
90
+
91
+	const system_question_email_confirm = 'email_confirm';
92
+
93
+	const system_question_address = 'address';
94
+
95
+	const system_question_address2 = 'address2';
96
+
97
+	const system_question_city = 'city';
98
+
99
+	const system_question_state = 'state';
100
+
101
+	const system_question_country = 'country';
102
+
103
+	const system_question_zip = 'zip';
104
+
105
+	const system_question_phone = 'phone';
106
+
107
+	/**
108
+	 * Keys are all the EEM_Attendee::system_question_* constants, which are
109
+	 * also all the values of QST_system in the questions table, and values
110
+	 * are their corresponding Attendee field names
111
+	 *
112
+	 * @var array
113
+	 */
114
+	protected $_system_question_to_attendee_field_name = array(
115
+		EEM_Attendee::system_question_fname    => 'ATT_fname',
116
+		EEM_Attendee::system_question_lname    => 'ATT_lname',
117
+		EEM_Attendee::system_question_email    => 'ATT_email',
118
+		EEM_Attendee::system_question_address  => 'ATT_address',
119
+		EEM_Attendee::system_question_address2 => 'ATT_address2',
120
+		EEM_Attendee::system_question_city     => 'ATT_city',
121
+		EEM_Attendee::system_question_state    => 'STA_ID',
122
+		EEM_Attendee::system_question_country  => 'CNT_ISO',
123
+		EEM_Attendee::system_question_zip      => 'ATT_zip',
124
+		EEM_Attendee::system_question_phone    => 'ATT_phone',
125
+	);
126
+
127
+
128
+
129
+	/**
130
+	 * EEM_Attendee constructor.
131
+	 *
132
+	 * @param null              $timezone
133
+	 * @param ModelFieldFactory $model_field_factory
134
+	 * @throws EE_Error
135
+	 * @throws InvalidArgumentException
136
+	 */
137
+	protected function __construct($timezone, ModelFieldFactory $model_field_factory)
138
+	{
139
+		$this->singular_item = esc_html__('Attendee', 'event_espresso');
140
+		$this->plural_item = esc_html__('Attendees', 'event_espresso');
141
+		$this->_tables = array(
142
+			'Attendee_CPT'  => new EE_Primary_Table('posts', 'ID'),
143
+			'Attendee_Meta' => new EE_Secondary_Table(
144
+				'esp_attendee_meta',
145
+				'ATTM_ID',
146
+				'ATT_ID'
147
+			),
148
+		);
149
+		$this->_fields = array(
150
+			'Attendee_CPT'  => array(
151
+				'ATT_ID'        => $model_field_factory->createPrimaryKeyIntField(
152
+					'ID',
153
+					esc_html__('Attendee ID', 'event_espresso')
154
+				),
155
+				'ATT_full_name' => $model_field_factory->createPlainTextField(
156
+					'post_title',
157
+					esc_html__('Attendee Full Name', 'event_espresso'),
158
+					false,
159
+					esc_html__('Unknown', 'event_espresso')
160
+				),
161
+				'ATT_bio'       => $model_field_factory->createPostContentField(
162
+					'post_content',
163
+					esc_html__('Attendee Biography', 'event_espresso'),
164
+					false,
165
+					esc_html__('No Biography Provided', 'event_espresso')
166
+				),
167
+				'ATT_slug'      => $model_field_factory->createSlugField(
168
+					'post_name',
169
+					esc_html__('Attendee URL Slug', 'event_espresso')
170
+				),
171
+				'ATT_created'   => $model_field_factory->createDatetimeField(
172
+					'post_date',
173
+					esc_html__('Time Attendee Created', 'event_espresso')
174
+				),
175
+				'ATT_short_bio' => $model_field_factory->createSimpleHtmlField(
176
+					'post_excerpt',
177
+					esc_html__('Attendee Short Biography', 'event_espresso'),
178
+					true,
179
+					esc_html__('No Biography Provided', 'event_espresso')
180
+				),
181
+				'ATT_modified'  => $model_field_factory->createDatetimeField(
182
+					'post_modified',
183
+					esc_html__('Time Attendee Last Modified', 'event_espresso')
184
+				),
185
+				'ATT_author'    => $model_field_factory->createWpUserField(
186
+					'post_author',
187
+					esc_html__('Creator ID of the first Event attended', 'event_espresso'),
188
+					false
189
+				),
190
+				'ATT_parent'    => $model_field_factory->createDbOnlyIntField(
191
+					'post_parent',
192
+					esc_html__('Parent Attendee (unused)', 'event_espresso'),
193
+					false,
194
+					0
195
+				),
196
+				'post_type'     => $model_field_factory->createWpPostTypeField('espresso_attendees'),
197
+				'status'        => $model_field_factory->createWpPostStatusField(
198
+					'post_status',
199
+					esc_html__('Attendee Status', 'event_espresso'),
200
+					false,
201
+					'publish'
202
+				),
203
+				'password' => new EE_Password_Field(
204
+					'post_password',
205
+					esc_html__('Password', 'event_espresso'),
206
+					false,
207
+					'',
208
+					array(
209
+						'ATT_bio',
210
+						'ATT_short_bio',
211
+						'ATT_address',
212
+						'ATT_address2',
213
+						'ATT_city',
214
+						'STA_ID',
215
+						'CNT_ISO',
216
+						'ATT_zip',
217
+						'ATT_email',
218
+						'ATT_phone'
219
+					)
220
+				)
221
+			),
222
+			'Attendee_Meta' => array(
223
+				'ATTM_ID'      => $model_field_factory->createDbOnlyIntField(
224
+					'ATTM_ID',
225
+					esc_html__('Attendee Meta Row ID', 'event_espresso'),
226
+					false
227
+				),
228
+				'ATT_ID_fk'    => $model_field_factory->createDbOnlyIntField(
229
+					'ATT_ID',
230
+					esc_html__('Foreign Key to Attendee in Post Table', 'event_espresso'),
231
+					false
232
+				),
233
+				'ATT_fname'    => $model_field_factory->createPlainTextField(
234
+					'ATT_fname',
235
+					esc_html__('First Name', 'event_espresso')
236
+				),
237
+				'ATT_lname'    => $model_field_factory->createPlainTextField(
238
+					'ATT_lname',
239
+					esc_html__('Last Name', 'event_espresso')
240
+				),
241
+				'ATT_address'  => $model_field_factory->createPlainTextField(
242
+					'ATT_address',
243
+					esc_html__('Address Part 1', 'event_espresso')
244
+				),
245
+				'ATT_address2' => $model_field_factory->createPlainTextField(
246
+					'ATT_address2',
247
+					esc_html__('Address Part 2', 'event_espresso')
248
+				),
249
+				'ATT_city'     => $model_field_factory->createPlainTextField(
250
+					'ATT_city',
251
+					esc_html__('City', 'event_espresso')
252
+				),
253
+				'STA_ID'       => $model_field_factory->createForeignKeyIntField(
254
+					'STA_ID',
255
+					esc_html__('State', 'event_espresso'),
256
+					true,
257
+					0,
258
+					'State'
259
+				),
260
+				'CNT_ISO'      => $model_field_factory->createForeignKeyStringField(
261
+					'CNT_ISO',
262
+					esc_html__('Country', 'event_espresso'),
263
+					true,
264
+					'',
265
+					'Country'
266
+				),
267
+				'ATT_zip'      => $model_field_factory->createPlainTextField(
268
+					'ATT_zip',
269
+					esc_html__('ZIP/Postal Code', 'event_espresso')
270
+				),
271
+				'ATT_email'    => $model_field_factory->createEmailField(
272
+					'ATT_email',
273
+					esc_html__('Email Address', 'event_espresso')
274
+				),
275
+				'ATT_phone'    => $model_field_factory->createPlainTextField(
276
+					'ATT_phone',
277
+					esc_html__('Phone', 'event_espresso')
278
+				),
279
+			),
280
+		);
281
+		$this->_model_relations = array(
282
+			'Registration'      => new EE_Has_Many_Relation(),
283
+			'State'             => new EE_Belongs_To_Relation(),
284
+			'Country'           => new EE_Belongs_To_Relation(),
285
+			'Event'             => new EE_HABTM_Relation('Registration', false),
286
+			'WP_User'           => new EE_Belongs_To_Relation(),
287
+			'Message'           => new EE_Has_Many_Any_Relation(false),
288
+			// allow deletion of attendees even if they have messages in the queue for them.
289
+			'Term_Relationship' => new EE_Has_Many_Relation(),
290
+			'Term_Taxonomy'     => new EE_HABTM_Relation('Term_Relationship'),
291
+		);
292
+		$this->_caps_slug = 'contacts';
293
+		$this->model_chain_to_password = '';
294
+		parent::__construct($timezone);
295
+	}
296
+
297
+
298
+
299
+	/**
300
+	 * Gets the name of the field on the attendee model corresponding to the system question string
301
+	 * which should be one of the keys from EEM_Attendee::_system_question_to_attendee_field_name
302
+	 *
303
+	 * @param string $system_question_string
304
+	 * @return string|null if not found
305
+	 */
306
+	public function get_attendee_field_for_system_question($system_question_string)
307
+	{
308
+		return isset($this->_system_question_to_attendee_field_name[ $system_question_string ])
309
+			? $this->_system_question_to_attendee_field_name[ $system_question_string ]
310
+			: null;
311
+	}
312
+
313
+
314
+
315
+	/**
316
+	 * Gets mapping from esp_question.QST_system values to their corresponding attendee field names
317
+	 *
318
+	 * @return array
319
+	 */
320
+	public function system_question_to_attendee_field_mapping()
321
+	{
322
+		return $this->_system_question_to_attendee_field_name;
323
+	}
324
+
325
+
326
+
327
+	/**
328
+	 * Gets all the attendees for a transaction (by using the esp_registration as a join table)
329
+	 *
330
+	 * @param EE_Transaction /int $transaction_id_or_obj EE_Transaction or its ID
331
+	 * @return EE_Attendee[]|EE_Base_Class[]
332
+	 * @throws EE_Error
333
+	 */
334
+	public function get_attendees_for_transaction($transaction_id_or_obj)
335
+	{
336
+		return $this->get_all(
337
+			array(
338
+				array(
339
+					'Registration.Transaction.TXN_ID' => $transaction_id_or_obj instanceof EE_Transaction
340
+						? $transaction_id_or_obj->ID()
341
+						: $transaction_id_or_obj,
342
+				),
343
+			)
344
+		);
345
+	}
346
+
347
+
348
+
349
+	/**
350
+	 * retrieve  a single attendee from db via their ID
351
+	 *
352
+	 * @param $ATT_ID
353
+	 * @return mixed array on success, FALSE on fail
354
+	 * @deprecated
355
+	 */
356
+	public function get_attendee_by_ID($ATT_ID = false)
357
+	{
358
+		// retrieve a particular EE_Attendee
359
+		return $this->get_one_by_ID($ATT_ID);
360
+	}
361
+
362
+
363
+
364
+	/**
365
+	 * retrieve  a single attendee from db via their ID
366
+	 *
367
+	 * @param array $where_cols_n_values
368
+	 * @return mixed array on success, FALSE on fail
369
+	 * @throws EE_Error
370
+	 */
371
+	public function get_attendee($where_cols_n_values = array())
372
+	{
373
+		if (empty($where_cols_n_values)) {
374
+			return false;
375
+		}
376
+		$attendee = $this->get_all(array($where_cols_n_values));
377
+		if (! empty($attendee)) {
378
+			return array_shift($attendee);
379
+		}
380
+		return false;
381
+	}
382
+
383
+
384
+
385
+	/**
386
+	 * Search for an existing Attendee record in the DB
387
+	 *
388
+	 * @param array $where_cols_n_values
389
+	 * @return bool|mixed
390
+	 * @throws EE_Error
391
+	 */
392
+	public function find_existing_attendee($where_cols_n_values = null)
393
+	{
394
+		// search by combo of first and last names plus the email address
395
+		$attendee_data_keys = array(
396
+			'ATT_fname' => $this->_ATT_fname,
397
+			'ATT_lname' => $this->_ATT_lname,
398
+			'ATT_email' => $this->_ATT_email,
399
+		);
400
+		// no search params means attendee object already exists.
401
+		$where_cols_n_values = is_array($where_cols_n_values) && ! empty($where_cols_n_values)
402
+			? $where_cols_n_values
403
+			: $attendee_data_keys;
404
+		$valid_data = true;
405
+		// check for required values
406
+		$valid_data = isset($where_cols_n_values['ATT_fname']) && ! empty($where_cols_n_values['ATT_fname'])
407
+			? $valid_data
408
+			: false;
409
+		$valid_data = isset($where_cols_n_values['ATT_lname']) && ! empty($where_cols_n_values['ATT_lname'])
410
+			? $valid_data
411
+			: false;
412
+		$valid_data = isset($where_cols_n_values['ATT_email']) && ! empty($where_cols_n_values['ATT_email'])
413
+			? $valid_data
414
+			: false;
415
+		if ($valid_data) {
416
+			$attendee = $this->get_attendee($where_cols_n_values);
417
+			if ($attendee instanceof EE_Attendee) {
418
+				return $attendee;
419
+			}
420
+		}
421
+		return false;
422
+	}
423
+
424
+
425
+
426
+	/**
427
+	 * Takes an incoming array of EE_Registration ids
428
+	 * and sends back a list of corresponding non duplicate EE_Attendee objects.
429
+	 *
430
+	 * @since  4.3.0
431
+	 * @param  array $ids array of EE_Registration ids
432
+	 * @return EE_Attendee[]|EE_Base_Class[]
433
+	 * @throws EE_Error
434
+	 */
435
+	public function get_array_of_contacts_from_reg_ids($ids)
436
+	{
437
+		$ids = (array) $ids;
438
+		$_where = array(
439
+			'Registration.REG_ID' => array('in', $ids),
440
+		);
441
+		return $this->get_all(array($_where));
442
+	}
443 443
 }
Please login to merge, or discard this patch.
core/services/notices/NoticesContainer.php 1 patch
Indentation   +214 added lines, -214 removed lines patch added patch discarded remove patch
@@ -13,218 +13,218 @@
 block discarded – undo
13 13
  */
14 14
 class NoticesContainer implements NoticesContainerInterface
15 15
 {
16
-    /**
17
-     * @var NoticeInterface[] $information
18
-     */
19
-    private $information = array();
20
-
21
-
22
-    /**
23
-     * @var NoticeInterface[] $attention
24
-     */
25
-    private $attention = array();
26
-
27
-
28
-    /**
29
-     * @var NoticeInterface[] $error
30
-     */
31
-    private $error = array();
32
-
33
-
34
-    /**
35
-     * @var NoticeInterface[] $success
36
-     */
37
-    private $success = array();
38
-
39
-
40
-    /**
41
-     * @param string $notice
42
-     * @param bool   $dismissible
43
-     * @param string $file
44
-     * @param string $func
45
-     * @param string $line
46
-     * @throws InvalidDataTypeException
47
-     */
48
-    public function addInformation($notice, $dismissible = true, $file = '', $func = '', $line = '')
49
-    {
50
-        $this->information[] = new Notice(
51
-            Notice::INFORMATION,
52
-            $notice,
53
-            $dismissible,
54
-            $file,
55
-            $func,
56
-            $line
57
-        );
58
-    }
59
-
60
-
61
-    /**
62
-     * @param string $notice
63
-     * @param bool   $dismissible
64
-     * @param string $file
65
-     * @param string $func
66
-     * @param string $line
67
-     * @throws InvalidDataTypeException
68
-     */
69
-    public function addAttention($notice, $dismissible = true, $file = '', $func = '', $line = '')
70
-    {
71
-        $this->attention[] = new Notice(
72
-            Notice::ATTENTION,
73
-            $notice,
74
-            $dismissible,
75
-            $file,
76
-            $func,
77
-            $line
78
-        );
79
-    }
80
-
81
-    // phpcs:disable PEAR.Functions.ValidDefaultValue.NotAtEnd
82
-    /**
83
-     * @param string $notice
84
-     * @param bool   $dismissible
85
-     * @param string $file
86
-     * @param string $func
87
-     * @param string $line
88
-     * @throws InvalidDataTypeException
89
-     */
90
-    public function addError($notice, $dismissible = true, $file = '', $func = '', $line = '')
91
-    {
92
-        $this->error[] = new Notice(
93
-            Notice::ERROR,
94
-            $notice,
95
-            $dismissible,
96
-            $file,
97
-            $func,
98
-            $line
99
-        );
100
-    }
101
-
102
-
103
-    /**
104
-     * @param string $notice
105
-     * @param bool   $dismissible
106
-     * @param string $file
107
-     * @param string $func
108
-     * @param string $line
109
-     * @throws InvalidDataTypeException
110
-     */
111
-    public function addSuccess($notice, $dismissible = true, $file = '', $func = '', $line = '')
112
-    {
113
-        $this->success[] = new Notice(
114
-            Notice::SUCCESS,
115
-            $notice,
116
-            $dismissible,
117
-            $file,
118
-            $func,
119
-            $line
120
-        );
121
-    }
122
-
123
-
124
-    /**
125
-     * @return boolean
126
-     */
127
-    public function hasInformation()
128
-    {
129
-        return ! empty($this->information);
130
-    }
131
-
132
-
133
-    /**
134
-     * @return boolean
135
-     */
136
-    public function hasAttention()
137
-    {
138
-        return ! empty($this->attention);
139
-    }
140
-
141
-
142
-    /**
143
-     * @return boolean
144
-     */
145
-    public function hasError()
146
-    {
147
-        return ! empty($this->error);
148
-    }
149
-
150
-
151
-    /**
152
-     * @return boolean
153
-     */
154
-    public function hasSuccess()
155
-    {
156
-        return ! empty($this->success);
157
-    }
158
-
159
-
160
-    /**
161
-     * @return int
162
-     */
163
-    public function countInformation()
164
-    {
165
-        return count($this->information);
166
-    }
167
-
168
-
169
-    /**
170
-     * @return int
171
-     */
172
-    public function countAttention()
173
-    {
174
-        return count($this->attention);
175
-    }
176
-
177
-
178
-    /**
179
-     * @return int
180
-     */
181
-    public function countError()
182
-    {
183
-        return count($this->error);
184
-    }
185
-
186
-
187
-    /**
188
-     * @return int
189
-     */
190
-    public function countSuccess()
191
-    {
192
-        return count($this->success);
193
-    }
194
-
195
-
196
-    /**
197
-     * @return NoticeInterface[]
198
-     */
199
-    public function getInformation()
200
-    {
201
-        return $this->information;
202
-    }
203
-
204
-
205
-    /**
206
-     * @return NoticeInterface[]
207
-     */
208
-    public function getAttention()
209
-    {
210
-        return $this->attention;
211
-    }
212
-
213
-
214
-    /**
215
-     * @return NoticeInterface[]
216
-     */
217
-    public function getError()
218
-    {
219
-        return $this->error;
220
-    }
221
-
222
-
223
-    /**
224
-     * @return NoticeInterface[]
225
-     */
226
-    public function getSuccess()
227
-    {
228
-        return $this->success;
229
-    }
16
+	/**
17
+	 * @var NoticeInterface[] $information
18
+	 */
19
+	private $information = array();
20
+
21
+
22
+	/**
23
+	 * @var NoticeInterface[] $attention
24
+	 */
25
+	private $attention = array();
26
+
27
+
28
+	/**
29
+	 * @var NoticeInterface[] $error
30
+	 */
31
+	private $error = array();
32
+
33
+
34
+	/**
35
+	 * @var NoticeInterface[] $success
36
+	 */
37
+	private $success = array();
38
+
39
+
40
+	/**
41
+	 * @param string $notice
42
+	 * @param bool   $dismissible
43
+	 * @param string $file
44
+	 * @param string $func
45
+	 * @param string $line
46
+	 * @throws InvalidDataTypeException
47
+	 */
48
+	public function addInformation($notice, $dismissible = true, $file = '', $func = '', $line = '')
49
+	{
50
+		$this->information[] = new Notice(
51
+			Notice::INFORMATION,
52
+			$notice,
53
+			$dismissible,
54
+			$file,
55
+			$func,
56
+			$line
57
+		);
58
+	}
59
+
60
+
61
+	/**
62
+	 * @param string $notice
63
+	 * @param bool   $dismissible
64
+	 * @param string $file
65
+	 * @param string $func
66
+	 * @param string $line
67
+	 * @throws InvalidDataTypeException
68
+	 */
69
+	public function addAttention($notice, $dismissible = true, $file = '', $func = '', $line = '')
70
+	{
71
+		$this->attention[] = new Notice(
72
+			Notice::ATTENTION,
73
+			$notice,
74
+			$dismissible,
75
+			$file,
76
+			$func,
77
+			$line
78
+		);
79
+	}
80
+
81
+	// phpcs:disable PEAR.Functions.ValidDefaultValue.NotAtEnd
82
+	/**
83
+	 * @param string $notice
84
+	 * @param bool   $dismissible
85
+	 * @param string $file
86
+	 * @param string $func
87
+	 * @param string $line
88
+	 * @throws InvalidDataTypeException
89
+	 */
90
+	public function addError($notice, $dismissible = true, $file = '', $func = '', $line = '')
91
+	{
92
+		$this->error[] = new Notice(
93
+			Notice::ERROR,
94
+			$notice,
95
+			$dismissible,
96
+			$file,
97
+			$func,
98
+			$line
99
+		);
100
+	}
101
+
102
+
103
+	/**
104
+	 * @param string $notice
105
+	 * @param bool   $dismissible
106
+	 * @param string $file
107
+	 * @param string $func
108
+	 * @param string $line
109
+	 * @throws InvalidDataTypeException
110
+	 */
111
+	public function addSuccess($notice, $dismissible = true, $file = '', $func = '', $line = '')
112
+	{
113
+		$this->success[] = new Notice(
114
+			Notice::SUCCESS,
115
+			$notice,
116
+			$dismissible,
117
+			$file,
118
+			$func,
119
+			$line
120
+		);
121
+	}
122
+
123
+
124
+	/**
125
+	 * @return boolean
126
+	 */
127
+	public function hasInformation()
128
+	{
129
+		return ! empty($this->information);
130
+	}
131
+
132
+
133
+	/**
134
+	 * @return boolean
135
+	 */
136
+	public function hasAttention()
137
+	{
138
+		return ! empty($this->attention);
139
+	}
140
+
141
+
142
+	/**
143
+	 * @return boolean
144
+	 */
145
+	public function hasError()
146
+	{
147
+		return ! empty($this->error);
148
+	}
149
+
150
+
151
+	/**
152
+	 * @return boolean
153
+	 */
154
+	public function hasSuccess()
155
+	{
156
+		return ! empty($this->success);
157
+	}
158
+
159
+
160
+	/**
161
+	 * @return int
162
+	 */
163
+	public function countInformation()
164
+	{
165
+		return count($this->information);
166
+	}
167
+
168
+
169
+	/**
170
+	 * @return int
171
+	 */
172
+	public function countAttention()
173
+	{
174
+		return count($this->attention);
175
+	}
176
+
177
+
178
+	/**
179
+	 * @return int
180
+	 */
181
+	public function countError()
182
+	{
183
+		return count($this->error);
184
+	}
185
+
186
+
187
+	/**
188
+	 * @return int
189
+	 */
190
+	public function countSuccess()
191
+	{
192
+		return count($this->success);
193
+	}
194
+
195
+
196
+	/**
197
+	 * @return NoticeInterface[]
198
+	 */
199
+	public function getInformation()
200
+	{
201
+		return $this->information;
202
+	}
203
+
204
+
205
+	/**
206
+	 * @return NoticeInterface[]
207
+	 */
208
+	public function getAttention()
209
+	{
210
+		return $this->attention;
211
+	}
212
+
213
+
214
+	/**
215
+	 * @return NoticeInterface[]
216
+	 */
217
+	public function getError()
218
+	{
219
+		return $this->error;
220
+	}
221
+
222
+
223
+	/**
224
+	 * @return NoticeInterface[]
225
+	 */
226
+	public function getSuccess()
227
+	{
228
+		return $this->success;
229
+	}
230 230
 }
Please login to merge, or discard this patch.
core/services/notices/NoticesContainerInterface.php 1 patch
Indentation   +81 added lines, -81 removed lines patch added patch discarded remove patch
@@ -12,129 +12,129 @@
 block discarded – undo
12 12
  */
13 13
 interface NoticesContainerInterface
14 14
 {
15
-    /**
16
-     * @param string $notice
17
-     * @param bool   $dismissible
18
-     * @param string $file
19
-     * @param string $func
20
-     * @param string $line
21
-     */
22
-    public function addInformation($notice, $dismissible = true, $file = '', $func = '', $line = '');
15
+	/**
16
+	 * @param string $notice
17
+	 * @param bool   $dismissible
18
+	 * @param string $file
19
+	 * @param string $func
20
+	 * @param string $line
21
+	 */
22
+	public function addInformation($notice, $dismissible = true, $file = '', $func = '', $line = '');
23 23
 
24 24
 
25
-    /**
26
-     * @param string $notice
27
-     * @param bool   $dismissible
28
-     * @param string $file
29
-     * @param string $func
30
-     * @param string $line
31
-     * @return
32
-     */
33
-    public function addAttention($notice, $dismissible = true, $file = '', $func = '', $line = '');
25
+	/**
26
+	 * @param string $notice
27
+	 * @param bool   $dismissible
28
+	 * @param string $file
29
+	 * @param string $func
30
+	 * @param string $line
31
+	 * @return
32
+	 */
33
+	public function addAttention($notice, $dismissible = true, $file = '', $func = '', $line = '');
34 34
 
35 35
 
36 36
 
37
-    /**
38
-     * @param string $notice
39
-     * @param bool   $dismissible
40
-     * @param string $file
41
-     * @param string $func
42
-     * @param string $line
43
-     */
44
-    public function addError($notice, $dismissible = true, $file = '', $func = '', $line = '');
37
+	/**
38
+	 * @param string $notice
39
+	 * @param bool   $dismissible
40
+	 * @param string $file
41
+	 * @param string $func
42
+	 * @param string $line
43
+	 */
44
+	public function addError($notice, $dismissible = true, $file = '', $func = '', $line = '');
45 45
 
46 46
 
47 47
 
48
-    /**
49
-     * @param string $notice
50
-     * @param bool   $dismissible
51
-     * @param string $file
52
-     * @param string $func
53
-     * @param string $line
54
-     */
55
-    public function addSuccess($notice, $dismissible = true, $file = '', $func = '', $line = '');
48
+	/**
49
+	 * @param string $notice
50
+	 * @param bool   $dismissible
51
+	 * @param string $file
52
+	 * @param string $func
53
+	 * @param string $line
54
+	 */
55
+	public function addSuccess($notice, $dismissible = true, $file = '', $func = '', $line = '');
56 56
 
57 57
 
58 58
 
59
-    /**
60
-     * @return boolean
61
-     */
62
-    public function hasInformation();
59
+	/**
60
+	 * @return boolean
61
+	 */
62
+	public function hasInformation();
63 63
 
64 64
 
65 65
 
66
-    /**
67
-     * @return boolean
68
-     */
69
-    public function hasAttention();
66
+	/**
67
+	 * @return boolean
68
+	 */
69
+	public function hasAttention();
70 70
 
71 71
 
72 72
 
73
-    /**
74
-     * @return boolean
75
-     */
76
-    public function hasError();
73
+	/**
74
+	 * @return boolean
75
+	 */
76
+	public function hasError();
77 77
 
78 78
 
79 79
 
80
-    /**
81
-     * @return boolean
82
-     */
83
-    public function hasSuccess();
80
+	/**
81
+	 * @return boolean
82
+	 */
83
+	public function hasSuccess();
84 84
 
85 85
 
86 86
 
87
-    /**
88
-     * @return int
89
-     */
90
-    public function countInformation();
87
+	/**
88
+	 * @return int
89
+	 */
90
+	public function countInformation();
91 91
 
92 92
 
93 93
 
94
-    /**
95
-     * @return int
96
-     */
97
-    public function countAttention();
94
+	/**
95
+	 * @return int
96
+	 */
97
+	public function countAttention();
98 98
 
99 99
 
100 100
 
101
-    /**
102
-     * @return int
103
-     */
104
-    public function countError();
101
+	/**
102
+	 * @return int
103
+	 */
104
+	public function countError();
105 105
 
106 106
 
107 107
 
108
-    /**
109
-     * @return int
110
-     */
111
-    public function countSuccess();
108
+	/**
109
+	 * @return int
110
+	 */
111
+	public function countSuccess();
112 112
 
113 113
 
114 114
 
115
-    /**
116
-     * @return NoticeInterface[]
117
-     */
118
-    public function getInformation();
115
+	/**
116
+	 * @return NoticeInterface[]
117
+	 */
118
+	public function getInformation();
119 119
 
120 120
 
121 121
 
122
-    /**
123
-     * @return NoticeInterface[]
124
-     */
125
-    public function getAttention();
122
+	/**
123
+	 * @return NoticeInterface[]
124
+	 */
125
+	public function getAttention();
126 126
 
127 127
 
128 128
 
129
-    /**
130
-     * @return NoticeInterface[]
131
-     */
132
-    public function getError();
129
+	/**
130
+	 * @return NoticeInterface[]
131
+	 */
132
+	public function getError();
133 133
 
134 134
 
135 135
 
136
-    /**
137
-     * @return NoticeInterface[]
138
-     */
139
-    public function getSuccess();
136
+	/**
137
+	 * @return NoticeInterface[]
138
+	 */
139
+	public function getSuccess();
140 140
 }
Please login to merge, or discard this patch.
caffeinated/modules/recaptcha_invisible/EED_Recaptcha_Invisible.module.php 2 patches
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -154,7 +154,7 @@  discard block
 block discarded – undo
154 154
         $request = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\request\Request');
155 155
         // Invisible Recaptcha is ONLY ever required for the frontend and admin
156 156
         // so we don't need to load any JS assets for other types of requests (like AJAX or API).
157
-        if (! ($request->isAdmin() || $request->isFrontend())) {
157
+        if ( ! ($request->isAdmin() || $request->isFrontend())) {
158 158
             return;
159 159
         }
160 160
         wp_localize_script(
@@ -170,7 +170,7 @@  discard block
 block discarded – undo
170 170
      */
171 171
     public static function assetsUrl()
172 172
     {
173
-        return plugin_dir_url(__FILE__) . 'assets/';
173
+        return plugin_dir_url(__FILE__).'assets/';
174 174
     }
175 175
 
176 176
 
@@ -208,7 +208,7 @@  discard block
 block discarded – undo
208 208
     public static function spcoRegStepForm(EE_Form_Section_Proper $reg_form)
209 209
     {
210 210
         // do nothing if form isn't for a reg step or test has already been passed
211
-        if (! EED_Recaptcha_Invisible::processSpcoRegStepForm($reg_form)) {
211
+        if ( ! EED_Recaptcha_Invisible::processSpcoRegStepForm($reg_form)) {
212 212
             return;
213 213
         }
214 214
         $default_hidden_inputs = $reg_form->get_subsection('default_hidden_inputs');
@@ -247,12 +247,12 @@  discard block
 block discarded – undo
247 247
     public static function receiveSpcoRegStepForm($req_data, EE_Form_Section_Proper $reg_form)
248 248
     {
249 249
         // do nothing if form isn't for a reg step or test has already been passed
250
-        if (! EED_Recaptcha_Invisible::processSpcoRegStepForm($reg_form)) {
250
+        if ( ! EED_Recaptcha_Invisible::processSpcoRegStepForm($reg_form)) {
251 251
             return $req_data;
252 252
         }
253 253
         /** @var RequestInterface $request */
254 254
         $request = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\request\RequestInterface');
255
-        if (! EED_Recaptcha_Invisible::verifyToken($request)) {
255
+        if ( ! EED_Recaptcha_Invisible::verifyToken($request)) {
256 256
             if ($request->isAjax()) {
257 257
                 $json_response = new EE_SPCO_JSON_Response();
258 258
                 $json_response->echoAndExit();
@@ -310,7 +310,7 @@  discard block
 block discarded – undo
310 310
         }
311 311
         /** @var RequestInterface $request */
312 312
         $request = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\request\RequestInterface');
313
-        if (! EED_Recaptcha_Invisible::verifyToken($request)) {
313
+        if ( ! EED_Recaptcha_Invisible::verifyToken($request)) {
314 314
             $event_id = $request->getRequestParam('tkt-slctr-event-id', 0, 'int');
315 315
             $return_url = $request->requestParamIsSet("tkt-slctr-return-url-{$event_id}")
316 316
                 ? $request->getRequestParam("tkt-slctr-return-url-{$event_id}")
Please login to merge, or discard this patch.
Indentation   +328 added lines, -328 removed lines patch added patch discarded remove patch
@@ -17,332 +17,332 @@
 block discarded – undo
17 17
  */
18 18
 class EED_Recaptcha_Invisible extends EED_Module
19 19
 {
20
-    /**
21
-     * @var EE_Registration_Config $config
22
-     */
23
-    private static $config;
24
-
25
-
26
-    /**
27
-     * @return EED_Module|EED_Recaptcha
28
-     */
29
-    public static function instance()
30
-    {
31
-        return parent::get_instance(__CLASS__);
32
-    }
33
-
34
-
35
-    /**
36
-     * @return void
37
-     * @throws InvalidInterfaceException
38
-     * @throws InvalidDataTypeException
39
-     * @throws InvalidArgumentException
40
-     */
41
-    public static function set_hooks()
42
-    {
43
-        EED_Recaptcha_Invisible::setProperties();
44
-        if (EED_Recaptcha_Invisible::useInvisibleRecaptcha()) {
45
-            if (EED_Recaptcha_Invisible::protectForm('ticket_selector')) {
46
-                // ticket selection
47
-                add_filter(
48
-                    'FHEE__EE_Ticket_Selector__after_ticket_selector_submit',
49
-                    array('EED_Recaptcha_Invisible', 'ticketSelectorForm'),
50
-                    10,
51
-                    3
52
-                );
53
-                add_action(
54
-                    'EED_Ticket_Selector__process_ticket_selections__before',
55
-                    array('EED_Recaptcha_Invisible', 'processTicketSelectorForm')
56
-                );
57
-            }
58
-            if (EED_Recaptcha_Invisible::protectForm('registration_form')) {
59
-                // checkout
60
-                add_action(
61
-                    'AHEE__EE_SPCO_Reg_Step__display_reg_form__reg_form',
62
-                    array('EED_Recaptcha_Invisible', 'spcoRegStepForm')
63
-                );
64
-                add_filter(
65
-                    'FHEE__EE_Form_Section_Proper__receive_form_submission__req_data',
66
-                    array('EED_Recaptcha_Invisible', 'receiveSpcoRegStepForm'),
67
-                    10,
68
-                    2
69
-                );
70
-            }
71
-            add_action('loop_end', array('EED_Recaptcha_Invisible', 'localizeScriptVars'));
72
-        }
73
-    }
74
-
75
-
76
-    /**
77
-     * @return void
78
-     * @throws InvalidInterfaceException
79
-     * @throws InvalidDataTypeException
80
-     * @throws InvalidArgumentException
81
-     */
82
-    public static function set_hooks_admin()
83
-    {
84
-        EED_Recaptcha_Invisible::setProperties();
85
-        if (EED_Recaptcha_Invisible::protectForm('ticket_selector')) {
86
-            add_action(
87
-                'EED_Ticket_Selector__process_ticket_selections__before',
88
-                array('EED_Recaptcha_Invisible', 'processTicketSelectorForm')
89
-            );
90
-        }
91
-        if (EED_Recaptcha_Invisible::protectForm('registration_form')) {
92
-            add_filter(
93
-                'FHEE__EE_Form_Section_Proper__receive_form_submission__req_data',
94
-                array('EED_Recaptcha_Invisible', 'receiveSpcoRegStepForm'),
95
-                10,
96
-                2
97
-            );
98
-        }
99
-        // admin settings
100
-        add_action(
101
-            'AHEE__Extend_Registration_Form_Admin_Page___reg_form_settings_template',
102
-            array('EED_Recaptcha_Invisible', 'adminSettings')
103
-        );
104
-        add_filter(
105
-            'FHEE__Extend_Registration_Form_Admin_Page___update_reg_form_settings__CFG_registration',
106
-            array('EED_Recaptcha_Invisible', 'updateAdminSettings')
107
-        );
108
-    }
109
-
110
-
111
-    /**
112
-     * @return void
113
-     * @throws InvalidInterfaceException
114
-     * @throws InvalidDataTypeException
115
-     * @throws InvalidArgumentException
116
-     */
117
-    public static function setProperties()
118
-    {
119
-
120
-        EED_Recaptcha_Invisible::$config = EE_Registry::instance()->CFG->registration;
121
-    }
122
-
123
-
124
-    /**
125
-     * @return boolean
126
-     */
127
-    public static function useInvisibleRecaptcha()
128
-    {
129
-        return EED_Recaptcha_Invisible::$config->use_captcha
130
-               && EED_Recaptcha_Invisible::$config->recaptcha_theme === 'invisible';
131
-    }
132
-
133
-
134
-    /**
135
-     * @param string $form
136
-     * @return boolean
137
-     */
138
-    public static function protectForm($form)
139
-    {
140
-        return is_array(EED_Recaptcha_Invisible::$config->recaptcha_protected_forms)
141
-               && in_array($form, EED_Recaptcha_Invisible::$config->recaptcha_protected_forms, true);
142
-    }
143
-
144
-
145
-    /**
146
-     * @return void
147
-     * @throws InvalidInterfaceException
148
-     * @throws InvalidDataTypeException
149
-     * @throws InvalidArgumentException
150
-     */
151
-    public static function localizeScriptVars()
152
-    {
153
-        /** @var \EventEspresso\core\services\request\Request $request */
154
-        $request = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\request\Request');
155
-        // Invisible Recaptcha is ONLY ever required for the frontend and admin
156
-        // so we don't need to load any JS assets for other types of requests (like AJAX or API).
157
-        if (! ($request->isAdmin() || $request->isFrontend())) {
158
-            return;
159
-        }
160
-        wp_localize_script(
161
-            EE_Invisible_Recaptcha_Input::SCRIPT_HANDLE_ESPRESSO_INVISIBLE_RECAPTCHA,
162
-            'eeRecaptcha',
163
-            RecaptchaFactory::create()->getLocalizedVars()
164
-        );
165
-    }
166
-
167
-
168
-    /**
169
-     * @return string
170
-     */
171
-    public static function assetsUrl()
172
-    {
173
-        return plugin_dir_url(__FILE__) . 'assets/';
174
-    }
175
-
176
-
177
-    /**
178
-     * @param \WP $WP
179
-     */
180
-    public function run($WP)
181
-    {
182
-    }
183
-
184
-
185
-    /**
186
-     * @param RequestInterface $request
187
-     * @return bool
188
-     * @throws InvalidArgumentException
189
-     * @throws InvalidDataTypeException
190
-     * @throws InvalidInterfaceException
191
-     * @throws RuntimeException
192
-     */
193
-    public static function verifyToken(RequestInterface $request)
194
-    {
195
-        return RecaptchaFactory::create()->verifyToken($request);
196
-    }
197
-
198
-
199
-    /**
200
-     * @param EE_Form_Section_Proper $reg_form
201
-     * @return void
202
-     * @throws EE_Error
203
-     * @throws InvalidArgumentException
204
-     * @throws InvalidDataTypeException
205
-     * @throws InvalidInterfaceException
206
-     * @throws DomainException
207
-     */
208
-    public static function spcoRegStepForm(EE_Form_Section_Proper $reg_form)
209
-    {
210
-        // do nothing if form isn't for a reg step or test has already been passed
211
-        if (! EED_Recaptcha_Invisible::processSpcoRegStepForm($reg_form)) {
212
-            return;
213
-        }
214
-        $default_hidden_inputs = $reg_form->get_subsection('default_hidden_inputs');
215
-        if ($default_hidden_inputs instanceof EE_Form_Section_Proper) {
216
-            $invisible_recaptcha = RecaptchaFactory::create();
217
-            $invisible_recaptcha->addToFormSection($default_hidden_inputs);
218
-        }
219
-    }
220
-
221
-
222
-    /**
223
-     * @param EE_Form_Section_Proper $reg_form
224
-     * @return bool
225
-     * @throws InvalidDataTypeException
226
-     * @throws InvalidInterfaceException
227
-     * @throws EE_Error
228
-     * @throws InvalidArgumentException
229
-     */
230
-    public static function processSpcoRegStepForm(EE_Form_Section_Proper $reg_form)
231
-    {
232
-        return strpos($reg_form->name(), 'reg-step-form') !== false
233
-               && ! RecaptchaFactory::create()->recaptchaPassed();
234
-    }
235
-
236
-
237
-    /**
238
-     * @param array|null             $req_data
239
-     * @param EE_Form_Section_Proper $reg_form
240
-     * @return array
241
-     * @throws EE_Error
242
-     * @throws InvalidArgumentException
243
-     * @throws InvalidDataTypeException
244
-     * @throws InvalidInterfaceException
245
-     * @throws RuntimeException
246
-     */
247
-    public static function receiveSpcoRegStepForm($req_data, EE_Form_Section_Proper $reg_form)
248
-    {
249
-        // do nothing if form isn't for a reg step or test has already been passed
250
-        if (! EED_Recaptcha_Invisible::processSpcoRegStepForm($reg_form)) {
251
-            return $req_data;
252
-        }
253
-        /** @var RequestInterface $request */
254
-        $request = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\request\RequestInterface');
255
-        if (! EED_Recaptcha_Invisible::verifyToken($request)) {
256
-            if ($request->isAjax()) {
257
-                $json_response = new EE_SPCO_JSON_Response();
258
-                $json_response->echoAndExit();
259
-            }
260
-            EEH_URL::safeRedirectAndExit(
261
-                EE_Registry::instance()->CFG->core->reg_page_url()
262
-            );
263
-        }
264
-        return $req_data;
265
-    }
266
-
267
-
268
-    /**
269
-     * @param string   $html
270
-     * @param EE_Event $event
271
-     * @param bool     $iframe
272
-     * @return string
273
-     * @throws EE_Error
274
-     * @throws InvalidArgumentException
275
-     * @throws InvalidDataTypeException
276
-     * @throws InvalidInterfaceException
277
-     * @throws ReflectionException
278
-     * @throws DomainException
279
-     */
280
-    public static function ticketSelectorForm(string $html, EE_Event $event, $iframe = false)
281
-    {
282
-        $recaptcha = RecaptchaFactory::create();
283
-        // do nothing if test has  already  been passed
284
-        if ($recaptcha->recaptchaPassed()) {
285
-            return $html;
286
-        }
287
-        $html .= $recaptcha->getInputHtml(
288
-            array(
289
-                'recaptcha_id'   => $event->ID(),
290
-                'iframe'         => $iframe,
291
-                'localized_vars' => $recaptcha->getLocalizedVars(),
292
-            )
293
-        );
294
-        return $html;
295
-    }
296
-
297
-
298
-    /**
299
-     * @return void
300
-     * @throws InvalidArgumentException
301
-     * @throws InvalidInterfaceException
302
-     * @throws InvalidDataTypeException
303
-     * @throws RuntimeException
304
-     */
305
-    public static function processTicketSelectorForm()
306
-    {
307
-        // do nothing if test has  already  been passed
308
-        if (RecaptchaFactory::create()->recaptchaPassed()) {
309
-            return;
310
-        }
311
-        /** @var RequestInterface $request */
312
-        $request = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\request\RequestInterface');
313
-        if (! EED_Recaptcha_Invisible::verifyToken($request)) {
314
-            $event_id = $request->getRequestParam('tkt-slctr-event-id', 0, 'int');
315
-            $return_url = $request->requestParamIsSet("tkt-slctr-return-url-{$event_id}")
316
-                ? $request->getRequestParam("tkt-slctr-return-url-{$event_id}")
317
-                : get_permalink($event_id);
318
-            EEH_URL::safeRedirectAndExit($return_url);
319
-        }
320
-    }
321
-
322
-
323
-    /**
324
-     * @throws EE_Error
325
-     * @throws InvalidArgumentException
326
-     * @throws InvalidDataTypeException
327
-     * @throws InvalidInterfaceException
328
-     */
329
-    public static function adminSettings()
330
-    {
331
-        RecaptchaFactory::getAdminModule()->adminSettings();
332
-    }
333
-
334
-
335
-    /**
336
-     * @param EE_Registration_Config $EE_Registration_Config
337
-     * @return EE_Registration_Config
338
-     * @throws EE_Error
339
-     * @throws InvalidArgumentException
340
-     * @throws InvalidDataTypeException
341
-     * @throws InvalidInterfaceException
342
-     * @throws ReflectionException
343
-     */
344
-    public static function updateAdminSettings(EE_Registration_Config $EE_Registration_Config)
345
-    {
346
-        return RecaptchaFactory::getAdminModule()->updateAdminSettings($EE_Registration_Config);
347
-    }
20
+	/**
21
+	 * @var EE_Registration_Config $config
22
+	 */
23
+	private static $config;
24
+
25
+
26
+	/**
27
+	 * @return EED_Module|EED_Recaptcha
28
+	 */
29
+	public static function instance()
30
+	{
31
+		return parent::get_instance(__CLASS__);
32
+	}
33
+
34
+
35
+	/**
36
+	 * @return void
37
+	 * @throws InvalidInterfaceException
38
+	 * @throws InvalidDataTypeException
39
+	 * @throws InvalidArgumentException
40
+	 */
41
+	public static function set_hooks()
42
+	{
43
+		EED_Recaptcha_Invisible::setProperties();
44
+		if (EED_Recaptcha_Invisible::useInvisibleRecaptcha()) {
45
+			if (EED_Recaptcha_Invisible::protectForm('ticket_selector')) {
46
+				// ticket selection
47
+				add_filter(
48
+					'FHEE__EE_Ticket_Selector__after_ticket_selector_submit',
49
+					array('EED_Recaptcha_Invisible', 'ticketSelectorForm'),
50
+					10,
51
+					3
52
+				);
53
+				add_action(
54
+					'EED_Ticket_Selector__process_ticket_selections__before',
55
+					array('EED_Recaptcha_Invisible', 'processTicketSelectorForm')
56
+				);
57
+			}
58
+			if (EED_Recaptcha_Invisible::protectForm('registration_form')) {
59
+				// checkout
60
+				add_action(
61
+					'AHEE__EE_SPCO_Reg_Step__display_reg_form__reg_form',
62
+					array('EED_Recaptcha_Invisible', 'spcoRegStepForm')
63
+				);
64
+				add_filter(
65
+					'FHEE__EE_Form_Section_Proper__receive_form_submission__req_data',
66
+					array('EED_Recaptcha_Invisible', 'receiveSpcoRegStepForm'),
67
+					10,
68
+					2
69
+				);
70
+			}
71
+			add_action('loop_end', array('EED_Recaptcha_Invisible', 'localizeScriptVars'));
72
+		}
73
+	}
74
+
75
+
76
+	/**
77
+	 * @return void
78
+	 * @throws InvalidInterfaceException
79
+	 * @throws InvalidDataTypeException
80
+	 * @throws InvalidArgumentException
81
+	 */
82
+	public static function set_hooks_admin()
83
+	{
84
+		EED_Recaptcha_Invisible::setProperties();
85
+		if (EED_Recaptcha_Invisible::protectForm('ticket_selector')) {
86
+			add_action(
87
+				'EED_Ticket_Selector__process_ticket_selections__before',
88
+				array('EED_Recaptcha_Invisible', 'processTicketSelectorForm')
89
+			);
90
+		}
91
+		if (EED_Recaptcha_Invisible::protectForm('registration_form')) {
92
+			add_filter(
93
+				'FHEE__EE_Form_Section_Proper__receive_form_submission__req_data',
94
+				array('EED_Recaptcha_Invisible', 'receiveSpcoRegStepForm'),
95
+				10,
96
+				2
97
+			);
98
+		}
99
+		// admin settings
100
+		add_action(
101
+			'AHEE__Extend_Registration_Form_Admin_Page___reg_form_settings_template',
102
+			array('EED_Recaptcha_Invisible', 'adminSettings')
103
+		);
104
+		add_filter(
105
+			'FHEE__Extend_Registration_Form_Admin_Page___update_reg_form_settings__CFG_registration',
106
+			array('EED_Recaptcha_Invisible', 'updateAdminSettings')
107
+		);
108
+	}
109
+
110
+
111
+	/**
112
+	 * @return void
113
+	 * @throws InvalidInterfaceException
114
+	 * @throws InvalidDataTypeException
115
+	 * @throws InvalidArgumentException
116
+	 */
117
+	public static function setProperties()
118
+	{
119
+
120
+		EED_Recaptcha_Invisible::$config = EE_Registry::instance()->CFG->registration;
121
+	}
122
+
123
+
124
+	/**
125
+	 * @return boolean
126
+	 */
127
+	public static function useInvisibleRecaptcha()
128
+	{
129
+		return EED_Recaptcha_Invisible::$config->use_captcha
130
+			   && EED_Recaptcha_Invisible::$config->recaptcha_theme === 'invisible';
131
+	}
132
+
133
+
134
+	/**
135
+	 * @param string $form
136
+	 * @return boolean
137
+	 */
138
+	public static function protectForm($form)
139
+	{
140
+		return is_array(EED_Recaptcha_Invisible::$config->recaptcha_protected_forms)
141
+			   && in_array($form, EED_Recaptcha_Invisible::$config->recaptcha_protected_forms, true);
142
+	}
143
+
144
+
145
+	/**
146
+	 * @return void
147
+	 * @throws InvalidInterfaceException
148
+	 * @throws InvalidDataTypeException
149
+	 * @throws InvalidArgumentException
150
+	 */
151
+	public static function localizeScriptVars()
152
+	{
153
+		/** @var \EventEspresso\core\services\request\Request $request */
154
+		$request = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\request\Request');
155
+		// Invisible Recaptcha is ONLY ever required for the frontend and admin
156
+		// so we don't need to load any JS assets for other types of requests (like AJAX or API).
157
+		if (! ($request->isAdmin() || $request->isFrontend())) {
158
+			return;
159
+		}
160
+		wp_localize_script(
161
+			EE_Invisible_Recaptcha_Input::SCRIPT_HANDLE_ESPRESSO_INVISIBLE_RECAPTCHA,
162
+			'eeRecaptcha',
163
+			RecaptchaFactory::create()->getLocalizedVars()
164
+		);
165
+	}
166
+
167
+
168
+	/**
169
+	 * @return string
170
+	 */
171
+	public static function assetsUrl()
172
+	{
173
+		return plugin_dir_url(__FILE__) . 'assets/';
174
+	}
175
+
176
+
177
+	/**
178
+	 * @param \WP $WP
179
+	 */
180
+	public function run($WP)
181
+	{
182
+	}
183
+
184
+
185
+	/**
186
+	 * @param RequestInterface $request
187
+	 * @return bool
188
+	 * @throws InvalidArgumentException
189
+	 * @throws InvalidDataTypeException
190
+	 * @throws InvalidInterfaceException
191
+	 * @throws RuntimeException
192
+	 */
193
+	public static function verifyToken(RequestInterface $request)
194
+	{
195
+		return RecaptchaFactory::create()->verifyToken($request);
196
+	}
197
+
198
+
199
+	/**
200
+	 * @param EE_Form_Section_Proper $reg_form
201
+	 * @return void
202
+	 * @throws EE_Error
203
+	 * @throws InvalidArgumentException
204
+	 * @throws InvalidDataTypeException
205
+	 * @throws InvalidInterfaceException
206
+	 * @throws DomainException
207
+	 */
208
+	public static function spcoRegStepForm(EE_Form_Section_Proper $reg_form)
209
+	{
210
+		// do nothing if form isn't for a reg step or test has already been passed
211
+		if (! EED_Recaptcha_Invisible::processSpcoRegStepForm($reg_form)) {
212
+			return;
213
+		}
214
+		$default_hidden_inputs = $reg_form->get_subsection('default_hidden_inputs');
215
+		if ($default_hidden_inputs instanceof EE_Form_Section_Proper) {
216
+			$invisible_recaptcha = RecaptchaFactory::create();
217
+			$invisible_recaptcha->addToFormSection($default_hidden_inputs);
218
+		}
219
+	}
220
+
221
+
222
+	/**
223
+	 * @param EE_Form_Section_Proper $reg_form
224
+	 * @return bool
225
+	 * @throws InvalidDataTypeException
226
+	 * @throws InvalidInterfaceException
227
+	 * @throws EE_Error
228
+	 * @throws InvalidArgumentException
229
+	 */
230
+	public static function processSpcoRegStepForm(EE_Form_Section_Proper $reg_form)
231
+	{
232
+		return strpos($reg_form->name(), 'reg-step-form') !== false
233
+			   && ! RecaptchaFactory::create()->recaptchaPassed();
234
+	}
235
+
236
+
237
+	/**
238
+	 * @param array|null             $req_data
239
+	 * @param EE_Form_Section_Proper $reg_form
240
+	 * @return array
241
+	 * @throws EE_Error
242
+	 * @throws InvalidArgumentException
243
+	 * @throws InvalidDataTypeException
244
+	 * @throws InvalidInterfaceException
245
+	 * @throws RuntimeException
246
+	 */
247
+	public static function receiveSpcoRegStepForm($req_data, EE_Form_Section_Proper $reg_form)
248
+	{
249
+		// do nothing if form isn't for a reg step or test has already been passed
250
+		if (! EED_Recaptcha_Invisible::processSpcoRegStepForm($reg_form)) {
251
+			return $req_data;
252
+		}
253
+		/** @var RequestInterface $request */
254
+		$request = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\request\RequestInterface');
255
+		if (! EED_Recaptcha_Invisible::verifyToken($request)) {
256
+			if ($request->isAjax()) {
257
+				$json_response = new EE_SPCO_JSON_Response();
258
+				$json_response->echoAndExit();
259
+			}
260
+			EEH_URL::safeRedirectAndExit(
261
+				EE_Registry::instance()->CFG->core->reg_page_url()
262
+			);
263
+		}
264
+		return $req_data;
265
+	}
266
+
267
+
268
+	/**
269
+	 * @param string   $html
270
+	 * @param EE_Event $event
271
+	 * @param bool     $iframe
272
+	 * @return string
273
+	 * @throws EE_Error
274
+	 * @throws InvalidArgumentException
275
+	 * @throws InvalidDataTypeException
276
+	 * @throws InvalidInterfaceException
277
+	 * @throws ReflectionException
278
+	 * @throws DomainException
279
+	 */
280
+	public static function ticketSelectorForm(string $html, EE_Event $event, $iframe = false)
281
+	{
282
+		$recaptcha = RecaptchaFactory::create();
283
+		// do nothing if test has  already  been passed
284
+		if ($recaptcha->recaptchaPassed()) {
285
+			return $html;
286
+		}
287
+		$html .= $recaptcha->getInputHtml(
288
+			array(
289
+				'recaptcha_id'   => $event->ID(),
290
+				'iframe'         => $iframe,
291
+				'localized_vars' => $recaptcha->getLocalizedVars(),
292
+			)
293
+		);
294
+		return $html;
295
+	}
296
+
297
+
298
+	/**
299
+	 * @return void
300
+	 * @throws InvalidArgumentException
301
+	 * @throws InvalidInterfaceException
302
+	 * @throws InvalidDataTypeException
303
+	 * @throws RuntimeException
304
+	 */
305
+	public static function processTicketSelectorForm()
306
+	{
307
+		// do nothing if test has  already  been passed
308
+		if (RecaptchaFactory::create()->recaptchaPassed()) {
309
+			return;
310
+		}
311
+		/** @var RequestInterface $request */
312
+		$request = LoaderFactory::getLoader()->getShared('EventEspresso\core\services\request\RequestInterface');
313
+		if (! EED_Recaptcha_Invisible::verifyToken($request)) {
314
+			$event_id = $request->getRequestParam('tkt-slctr-event-id', 0, 'int');
315
+			$return_url = $request->requestParamIsSet("tkt-slctr-return-url-{$event_id}")
316
+				? $request->getRequestParam("tkt-slctr-return-url-{$event_id}")
317
+				: get_permalink($event_id);
318
+			EEH_URL::safeRedirectAndExit($return_url);
319
+		}
320
+	}
321
+
322
+
323
+	/**
324
+	 * @throws EE_Error
325
+	 * @throws InvalidArgumentException
326
+	 * @throws InvalidDataTypeException
327
+	 * @throws InvalidInterfaceException
328
+	 */
329
+	public static function adminSettings()
330
+	{
331
+		RecaptchaFactory::getAdminModule()->adminSettings();
332
+	}
333
+
334
+
335
+	/**
336
+	 * @param EE_Registration_Config $EE_Registration_Config
337
+	 * @return EE_Registration_Config
338
+	 * @throws EE_Error
339
+	 * @throws InvalidArgumentException
340
+	 * @throws InvalidDataTypeException
341
+	 * @throws InvalidInterfaceException
342
+	 * @throws ReflectionException
343
+	 */
344
+	public static function updateAdminSettings(EE_Registration_Config $EE_Registration_Config)
345
+	{
346
+		return RecaptchaFactory::getAdminModule()->updateAdminSettings($EE_Registration_Config);
347
+	}
348 348
 }
Please login to merge, or discard this patch.
domain/services/graphql/connection_resolvers/CountryConnectionResolver.php 1 patch
Indentation   +166 added lines, -166 removed lines patch added patch discarded remove patch
@@ -16,170 +16,170 @@
 block discarded – undo
16 16
  */
17 17
 class CountryConnectionResolver extends AbstractConnectionResolver
18 18
 {
19
-    // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
20
-    public function get_loader_name(): string
21
-    {
22
-        return 'espresso_country';
23
-    }
24
-
25
-    /**
26
-     * @return EEM_Country
27
-     * @throws EE_Error
28
-     * @throws InvalidArgumentException
29
-     * @throws InvalidDataTypeException
30
-     * @throws InvalidInterfaceException
31
-     * @throws ReflectionException
32
-     */
33
-    // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
34
-    public function get_query(): EEM_Country
35
-    {
36
-        return EEM_Country::instance();
37
-    }
38
-
39
-
40
-    /**
41
-     * Return an array of item IDs from the query
42
-     *
43
-     * @return array
44
-     */
45
-    // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
46
-    public function get_ids(): array
47
-    {
48
-        $results = $this->query->get_col($this->query_args);
49
-
50
-        return ! empty($results) ? $results : [];
51
-    }
52
-
53
-    /**
54
-     * Get_query_amount
55
-     *
56
-     * Returns the max between what was requested and what is defined as the $max_query_amount to
57
-     * ensure that queries don't exceed unwanted limits when querying data.
58
-     *
59
-     * @return int
60
-     * @throws Exception
61
-     */
62
-    // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
63
-    public function get_query_amount()
64
-    {
65
-        // Override the default limit (100) for countries
66
-        return 500;
67
-    }
68
-
69
-
70
-    /**
71
-     * Here, we map the args from the input, then we make sure that we're only querying
72
-     * for IDs. The IDs are then passed down the resolve tree, and deferred resolvers
73
-     * handle batch resolution of the posts.
74
-     *
75
-     * @return array
76
-     * @throws InvalidArgumentException
77
-     * @throws InvalidDataTypeException
78
-     * @throws InvalidInterfaceException
79
-     */
80
-    // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
81
-    public function get_query_args(): array
82
-    {
83
-        $where_params = [];
84
-        $query_args   = [];
85
-
86
-        $query_args['limit'] = $this->getLimit();
87
-
88
-        // Avoid multiple entries by join.
89
-        $query_args['group_by'] = 'CNT_ISO';
90
-
91
-        $query_args['default_where_conditions'] = 'minimum';
92
-
93
-        /**
94
-         * Collect the input_fields and sanitize them to prepare them for sending to the Query
95
-         */
96
-        $input_fields = [];
97
-        if (! empty($this->args['where'])) {
98
-            $input_fields = $this->sanitizeInputFields($this->args['where']);
99
-
100
-            // Since we do not have any falsy values in query params
101
-            // Lets get rid of empty values
102
-            $input_fields = array_filter($input_fields);
103
-
104
-            // Use the proper operator.
105
-            if (! empty($input_fields['CNT_ISO']) && is_array($input_fields['CNT_ISO'])) {
106
-                $input_fields['CNT_ISO'] = ['IN', $input_fields['CNT_ISO']];
107
-            }
108
-            if (! empty($input_fields['CNT_ISO3']) && is_array($input_fields['CNT_ISO3'])) {
109
-                $input_fields['CNT_ISO3'] = ['IN', $input_fields['CNT_ISO3']];
110
-            }
111
-        }
112
-
113
-        /**
114
-         * Merge the input_fields with the default query_args
115
-         */
116
-        if (! empty($input_fields)) {
117
-            $where_params = array_merge($where_params, $input_fields);
118
-        }
119
-
120
-        // limit to active countries by default.
121
-        if (!isset($this->args['where']['activeOnly']) || $this->args['where']['activeOnly']) {
122
-            $where_params['CNT_active'] = true;
123
-        }
124
-
125
-        [$query_args, $where_params] = $this->mapOrderbyInputArgs($query_args, $where_params, 'CNT_ISO');
126
-
127
-        if (empty($query_args['order_by'])) {
128
-            // set order_by to 'name' by default
129
-            $query_args['order_by'] = [
130
-                'CNT_name' => 'ASC',
131
-            ];
132
-        }
133
-
134
-        $search = $this->getSearchKeywords($this->args['where']);
135
-
136
-        if (! empty($search)) {
137
-            // use OR operator to search in any of the fields
138
-            $where_params['OR'] = array(
139
-                'CNT_name' => array('LIKE', '%' . $search . '%'),
140
-                'CNT_ISO'  => array('LIKE', '%' . $search . '%'),
141
-            );
142
-        }
143
-
144
-        $where_params = apply_filters(
145
-            'FHEE__EventEspresso_core_domain_services_graphql_connection_resolvers__country_where_params',
146
-            $where_params,
147
-            $this->source,
148
-            $this->args
149
-        );
150
-
151
-        $query_args[] = $where_params;
152
-
153
-        /**
154
-         * Return the $query_args
155
-         */
156
-        return apply_filters(
157
-            'FHEE__EventEspresso_core_domain_services_graphql_connection_resolvers__country_query_args',
158
-            $query_args,
159
-            $this->source,
160
-            $this->args
161
-        );
162
-    }
163
-
164
-
165
-    /**
166
-     * This sets up the "allowed" args, and translates the GraphQL-friendly keys to model
167
-     * friendly keys.
168
-     *
169
-     * @param array $where_args
170
-     * @return array
171
-     */
172
-    public function sanitizeInputFields(array $where_args): array
173
-    {
174
-        $arg_mapping = [
175
-            'isoIn'  => 'CNT_ISO',
176
-            'in'     => 'CNT_ISO',
177
-            'iso3In' => 'CNT_ISO3',
178
-        ];
179
-        return $this->sanitizeWhereArgsForInputFields(
180
-            $where_args,
181
-            $arg_mapping,
182
-            ['in']
183
-        );
184
-    }
19
+	// phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
20
+	public function get_loader_name(): string
21
+	{
22
+		return 'espresso_country';
23
+	}
24
+
25
+	/**
26
+	 * @return EEM_Country
27
+	 * @throws EE_Error
28
+	 * @throws InvalidArgumentException
29
+	 * @throws InvalidDataTypeException
30
+	 * @throws InvalidInterfaceException
31
+	 * @throws ReflectionException
32
+	 */
33
+	// phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
34
+	public function get_query(): EEM_Country
35
+	{
36
+		return EEM_Country::instance();
37
+	}
38
+
39
+
40
+	/**
41
+	 * Return an array of item IDs from the query
42
+	 *
43
+	 * @return array
44
+	 */
45
+	// phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
46
+	public function get_ids(): array
47
+	{
48
+		$results = $this->query->get_col($this->query_args);
49
+
50
+		return ! empty($results) ? $results : [];
51
+	}
52
+
53
+	/**
54
+	 * Get_query_amount
55
+	 *
56
+	 * Returns the max between what was requested and what is defined as the $max_query_amount to
57
+	 * ensure that queries don't exceed unwanted limits when querying data.
58
+	 *
59
+	 * @return int
60
+	 * @throws Exception
61
+	 */
62
+	// phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
63
+	public function get_query_amount()
64
+	{
65
+		// Override the default limit (100) for countries
66
+		return 500;
67
+	}
68
+
69
+
70
+	/**
71
+	 * Here, we map the args from the input, then we make sure that we're only querying
72
+	 * for IDs. The IDs are then passed down the resolve tree, and deferred resolvers
73
+	 * handle batch resolution of the posts.
74
+	 *
75
+	 * @return array
76
+	 * @throws InvalidArgumentException
77
+	 * @throws InvalidDataTypeException
78
+	 * @throws InvalidInterfaceException
79
+	 */
80
+	// phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
81
+	public function get_query_args(): array
82
+	{
83
+		$where_params = [];
84
+		$query_args   = [];
85
+
86
+		$query_args['limit'] = $this->getLimit();
87
+
88
+		// Avoid multiple entries by join.
89
+		$query_args['group_by'] = 'CNT_ISO';
90
+
91
+		$query_args['default_where_conditions'] = 'minimum';
92
+
93
+		/**
94
+		 * Collect the input_fields and sanitize them to prepare them for sending to the Query
95
+		 */
96
+		$input_fields = [];
97
+		if (! empty($this->args['where'])) {
98
+			$input_fields = $this->sanitizeInputFields($this->args['where']);
99
+
100
+			// Since we do not have any falsy values in query params
101
+			// Lets get rid of empty values
102
+			$input_fields = array_filter($input_fields);
103
+
104
+			// Use the proper operator.
105
+			if (! empty($input_fields['CNT_ISO']) && is_array($input_fields['CNT_ISO'])) {
106
+				$input_fields['CNT_ISO'] = ['IN', $input_fields['CNT_ISO']];
107
+			}
108
+			if (! empty($input_fields['CNT_ISO3']) && is_array($input_fields['CNT_ISO3'])) {
109
+				$input_fields['CNT_ISO3'] = ['IN', $input_fields['CNT_ISO3']];
110
+			}
111
+		}
112
+
113
+		/**
114
+		 * Merge the input_fields with the default query_args
115
+		 */
116
+		if (! empty($input_fields)) {
117
+			$where_params = array_merge($where_params, $input_fields);
118
+		}
119
+
120
+		// limit to active countries by default.
121
+		if (!isset($this->args['where']['activeOnly']) || $this->args['where']['activeOnly']) {
122
+			$where_params['CNT_active'] = true;
123
+		}
124
+
125
+		[$query_args, $where_params] = $this->mapOrderbyInputArgs($query_args, $where_params, 'CNT_ISO');
126
+
127
+		if (empty($query_args['order_by'])) {
128
+			// set order_by to 'name' by default
129
+			$query_args['order_by'] = [
130
+				'CNT_name' => 'ASC',
131
+			];
132
+		}
133
+
134
+		$search = $this->getSearchKeywords($this->args['where']);
135
+
136
+		if (! empty($search)) {
137
+			// use OR operator to search in any of the fields
138
+			$where_params['OR'] = array(
139
+				'CNT_name' => array('LIKE', '%' . $search . '%'),
140
+				'CNT_ISO'  => array('LIKE', '%' . $search . '%'),
141
+			);
142
+		}
143
+
144
+		$where_params = apply_filters(
145
+			'FHEE__EventEspresso_core_domain_services_graphql_connection_resolvers__country_where_params',
146
+			$where_params,
147
+			$this->source,
148
+			$this->args
149
+		);
150
+
151
+		$query_args[] = $where_params;
152
+
153
+		/**
154
+		 * Return the $query_args
155
+		 */
156
+		return apply_filters(
157
+			'FHEE__EventEspresso_core_domain_services_graphql_connection_resolvers__country_query_args',
158
+			$query_args,
159
+			$this->source,
160
+			$this->args
161
+		);
162
+	}
163
+
164
+
165
+	/**
166
+	 * This sets up the "allowed" args, and translates the GraphQL-friendly keys to model
167
+	 * friendly keys.
168
+	 *
169
+	 * @param array $where_args
170
+	 * @return array
171
+	 */
172
+	public function sanitizeInputFields(array $where_args): array
173
+	{
174
+		$arg_mapping = [
175
+			'isoIn'  => 'CNT_ISO',
176
+			'in'     => 'CNT_ISO',
177
+			'iso3In' => 'CNT_ISO3',
178
+		];
179
+		return $this->sanitizeWhereArgsForInputFields(
180
+			$where_args,
181
+			$arg_mapping,
182
+			['in']
183
+		);
184
+	}
185 185
 }
Please login to merge, or discard this patch.
core/db_models/fields/EE_Text_Field_Base.php 1 patch
Indentation   +46 added lines, -46 removed lines patch added patch discarded remove patch
@@ -6,52 +6,52 @@
 block discarded – undo
6 6
  */
7 7
 abstract class EE_Text_Field_Base extends EE_Model_Field_Base
8 8
 {
9
-    /**
10
-     * Gets the value in the format expected when being set.
11
-     * For display on the front-end, usually you would use prepare_for_pretty_echoing() instead.
12
-     * @param mixed $value_of_field_on_model_object
13
-     * @return mixed|string
14
-     */
15
-    public function prepare_for_get($value_of_field_on_model_object)
16
-    {
17
-        if (empty($value_of_field_on_model_object)) {
18
-            return $this->is_nullable() ? $value_of_field_on_model_object : '';
19
-        }
20
-        return $value_of_field_on_model_object;
21
-    }
9
+	/**
10
+	 * Gets the value in the format expected when being set.
11
+	 * For display on the front-end, usually you would use prepare_for_pretty_echoing() instead.
12
+	 * @param mixed $value_of_field_on_model_object
13
+	 * @return mixed|string
14
+	 */
15
+	public function prepare_for_get($value_of_field_on_model_object)
16
+	{
17
+		if (empty($value_of_field_on_model_object)) {
18
+			return $this->is_nullable() ? $value_of_field_on_model_object : '';
19
+		}
20
+		return $value_of_field_on_model_object;
21
+	}
22 22
 
23
-    /**
24
-     * Accepts schema of 'form_input' which formats the string for echoing in form input's value.
25
-     *
26
-     * @param string      $value_on_field_to_be_outputted
27
-     * @param string|null $schema
28
-     * @return string
29
-     */
30
-    public function prepare_for_pretty_echoing($value_on_field_to_be_outputted, $schema = null)
31
-    {
32
-        if ($schema === 'form_input') {
33
-            $value_on_field_to_be_outputted = (string) htmlentities(
34
-                $value_on_field_to_be_outputted,
35
-                ENT_QUOTES,
36
-                'UTF-8'
37
-            );
38
-        }
39
-        return parent::prepare_for_pretty_echoing($value_on_field_to_be_outputted);
40
-    }
23
+	/**
24
+	 * Accepts schema of 'form_input' which formats the string for echoing in form input's value.
25
+	 *
26
+	 * @param string      $value_on_field_to_be_outputted
27
+	 * @param string|null $schema
28
+	 * @return string
29
+	 */
30
+	public function prepare_for_pretty_echoing($value_on_field_to_be_outputted, $schema = null)
31
+	{
32
+		if ($schema === 'form_input') {
33
+			$value_on_field_to_be_outputted = (string) htmlentities(
34
+				$value_on_field_to_be_outputted,
35
+				ENT_QUOTES,
36
+				'UTF-8'
37
+			);
38
+		}
39
+		return parent::prepare_for_pretty_echoing($value_on_field_to_be_outputted);
40
+	}
41 41
 
42
-    /**
43
-     * Data received from the user should be exactly as they hope to save it in the DB, with the exception that
44
-     * quotes need to have slashes added to it. This method takes care of removing the slashes added by WP
45
-     * in magic-quotes fashion. We used to call html_entity_decode on the value here,
46
-     * because we called htmlentities when in EE_Text_Field_Base::prepare_for_pretty_echoing, but that's not necessary
47
-     * because web browsers always decode HTML entities in element attributes, like a form element's value attribute.
48
-     * So if we do it again here, we'll be removing HTML entities the user intended to have.)
49
-     *
50
-     * @param string $value_inputted_for_field_on_model_object
51
-     * @return string
52
-     */
53
-    public function prepare_for_set($value_inputted_for_field_on_model_object)
54
-    {
55
-        return stripslashes(parent::prepare_for_set($value_inputted_for_field_on_model_object));
56
-    }
42
+	/**
43
+	 * Data received from the user should be exactly as they hope to save it in the DB, with the exception that
44
+	 * quotes need to have slashes added to it. This method takes care of removing the slashes added by WP
45
+	 * in magic-quotes fashion. We used to call html_entity_decode on the value here,
46
+	 * because we called htmlentities when in EE_Text_Field_Base::prepare_for_pretty_echoing, but that's not necessary
47
+	 * because web browsers always decode HTML entities in element attributes, like a form element's value attribute.
48
+	 * So if we do it again here, we'll be removing HTML entities the user intended to have.)
49
+	 *
50
+	 * @param string $value_inputted_for_field_on_model_object
51
+	 * @return string
52
+	 */
53
+	public function prepare_for_set($value_inputted_for_field_on_model_object)
54
+	{
55
+		return stripslashes(parent::prepare_for_set($value_inputted_for_field_on_model_object));
56
+	}
57 57
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Event.class.php 1 patch
Indentation   +1593 added lines, -1593 removed lines patch added patch discarded remove patch
@@ -16,1600 +16,1600 @@
 block discarded – undo
16 16
  */
17 17
 class EE_Event extends EE_CPT_Base implements EEI_Line_Item_Object, EEI_Admin_Links, EEI_Has_Icon, EEI_Event
18 18
 {
19
-    /**
20
-     * cached value for the the logical active status for the event
21
-     *
22
-     * @see get_active_status()
23
-     * @var string
24
-     */
25
-    protected $_active_status = '';
26
-
27
-    /**
28
-     * This is just used for caching the Primary Datetime for the Event on initial retrieval
29
-     *
30
-     * @var EE_Datetime
31
-     */
32
-    protected $_Primary_Datetime;
33
-
34
-    /**
35
-     * @var EventSpacesCalculator $available_spaces_calculator
36
-     */
37
-    protected $available_spaces_calculator;
38
-
39
-
40
-    /**
41
-     * @param array  $props_n_values          incoming values
42
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
43
-     *                                        used.)
44
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
45
-     *                                        date_format and the second value is the time format
46
-     * @return EE_Event
47
-     * @throws EE_Error
48
-     * @throws ReflectionException
49
-     */
50
-    public static function new_instance($props_n_values = [], $timezone = null, $date_formats = []): EE_Event
51
-    {
52
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
53
-        return $has_object ?: new self($props_n_values, false, $timezone, $date_formats);
54
-    }
55
-
56
-
57
-    /**
58
-     * @param array  $props_n_values  incoming values from the database
59
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
60
-     *                                the website will be used.
61
-     * @return EE_Event
62
-     * @throws EE_Error
63
-     * @throws ReflectionException
64
-     */
65
-    public static function new_instance_from_db($props_n_values = [], $timezone = null): EE_Event
66
-    {
67
-        return new self($props_n_values, true, $timezone);
68
-    }
69
-
70
-
71
-    /**
72
-     * @return EventSpacesCalculator
73
-     * @throws EE_Error
74
-     * @throws ReflectionException
75
-     */
76
-    public function getAvailableSpacesCalculator(): EventSpacesCalculator
77
-    {
78
-        if (! $this->available_spaces_calculator instanceof EventSpacesCalculator) {
79
-            $this->available_spaces_calculator = new EventSpacesCalculator($this);
80
-        }
81
-        return $this->available_spaces_calculator;
82
-    }
83
-
84
-
85
-    /**
86
-     * Overrides parent set() method so that all calls to set( 'status', $status ) can be routed to internal methods
87
-     *
88
-     * @param string $field_name
89
-     * @param mixed  $field_value
90
-     * @param bool   $use_default
91
-     * @throws EE_Error
92
-     * @throws ReflectionException
93
-     */
94
-    public function set($field_name, $field_value, $use_default = false)
95
-    {
96
-        switch ($field_name) {
97
-            case 'status':
98
-                $this->set_status($field_value, $use_default);
99
-                break;
100
-            default:
101
-                parent::set($field_name, $field_value, $use_default);
102
-        }
103
-    }
104
-
105
-
106
-    /**
107
-     *    set_status
108
-     * Checks if event status is being changed to SOLD OUT
109
-     * and updates event meta data with previous event status
110
-     * so that we can revert things if/when the event is no longer sold out
111
-     *
112
-     * @param string $status
113
-     * @param bool   $use_default
114
-     * @return void
115
-     * @throws EE_Error
116
-     * @throws ReflectionException
117
-     */
118
-    public function set_status($status = '', $use_default = false)
119
-    {
120
-        // if nothing is set, and we aren't explicitly wanting to reset the status, then just leave
121
-        if (empty($status) && ! $use_default) {
122
-            return;
123
-        }
124
-        // get current Event status
125
-        $old_status = $this->status();
126
-        // if status has changed
127
-        if ($old_status !== $status) {
128
-            // TO sold_out
129
-            if ($status === EEM_Event::sold_out) {
130
-                // save the previous event status so that we can revert if the event is no longer sold out
131
-                $this->add_post_meta('_previous_event_status', $old_status);
132
-                do_action('AHEE__EE_Event__set_status__to_sold_out', $this, $old_status, $status);
133
-                // OR FROM  sold_out
134
-            } elseif ($old_status === EEM_Event::sold_out) {
135
-                $this->delete_post_meta('_previous_event_status');
136
-                do_action('AHEE__EE_Event__set_status__from_sold_out', $this, $old_status, $status);
137
-            }
138
-            // clear out the active status so that it gets reset the next time it is requested
139
-            $this->_active_status = null;
140
-            // update status
141
-            parent::set('status', $status, $use_default);
142
-            do_action('AHEE__EE_Event__set_status__after_update', $this);
143
-            return;
144
-        }
145
-        // even though the old value matches the new value, it's still good to
146
-        // allow the parent set method to have a say
147
-        parent::set('status', $status, $use_default);
148
-    }
149
-
150
-
151
-    /**
152
-     * Gets all the datetimes for this event
153
-     *
154
-     * @param array|null $query_params
155
-     * @return EE_Base_Class[]|EE_Datetime[]
156
-     * @throws EE_Error
157
-     * @throws ReflectionException
158
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
159
-     */
160
-    public function datetimes(?array $query_params = []): array
161
-    {
162
-        return $this->get_many_related('Datetime', $query_params);
163
-    }
164
-
165
-
166
-    /**
167
-     * Gets all the datetimes for this event that are currently ACTIVE,
168
-     * meaning the datetime has started and has not yet ended.
169
-     *
170
-     * @param int|null   $start_date   timestamp to use for event date start time, defaults to NOW unless set to 0
171
-     * @param array|null $query_params will recursively replace default values
172
-     * @throws EE_Error
173
-     * @throws ReflectionException
174
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
175
-     */
176
-    public function activeDatetimes(?int $start_date, ?array $query_params = []): array
177
-    {
178
-        // if start date is null, then use current time
179
-        $start_date = $start_date ?? time();
180
-        $where      = [];
181
-        if ($start_date) {
182
-            $where['DTT_EVT_start'] = ['<', $start_date];
183
-            $where['DTT_EVT_end']   = ['>', time()];
184
-        }
185
-        $query_params = array_replace_recursive(
186
-            [
187
-                $where,
188
-                'order_by' => ['DTT_EVT_start' => 'ASC'],
189
-            ],
190
-            $query_params
191
-        );
192
-        return $this->get_many_related('Datetime', $query_params);
193
-    }
194
-
195
-
196
-    /**
197
-     * Gets all the datetimes for this event, ordered by DTT_EVT_start in ascending order
198
-     *
199
-     * @return EE_Base_Class[]|EE_Datetime[]
200
-     * @throws EE_Error
201
-     * @throws ReflectionException
202
-     */
203
-    public function datetimes_in_chronological_order(): array
204
-    {
205
-        return $this->get_many_related('Datetime', ['order_by' => ['DTT_EVT_start' => 'ASC']]);
206
-    }
207
-
208
-
209
-    /**
210
-     * Gets all the datetimes for this event, ordered by the DTT_order on the datetime.
211
-     * @darren, we should probably UNSET timezone on the EEM_Datetime model
212
-     * after running our query, so that this timezone isn't set for EVERY query
213
-     * on EEM_Datetime for the rest of the request, no?
214
-     *
215
-     * @param bool     $show_expired whether or not to include expired events
216
-     * @param bool     $show_deleted whether or not to include deleted events
217
-     * @param int|null $limit
218
-     * @return EE_Datetime[]
219
-     * @throws EE_Error
220
-     * @throws ReflectionException
221
-     */
222
-    public function datetimes_ordered(bool $show_expired = true, bool $show_deleted = false, ?int $limit = null): array
223
-    {
224
-        return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_event_ordered_by_DTT_order(
225
-            $this->ID(),
226
-            $show_expired,
227
-            $show_deleted,
228
-            $limit
229
-        );
230
-    }
231
-
232
-
233
-    /**
234
-     * Returns one related datetime. Mostly only used by some legacy code.
235
-     *
236
-     * @return EE_Base_Class|EE_Datetime
237
-     * @throws EE_Error
238
-     * @throws ReflectionException
239
-     */
240
-    public function first_datetime(): EE_Datetime
241
-    {
242
-        return $this->get_first_related('Datetime');
243
-    }
244
-
245
-
246
-    /**
247
-     * Returns the 'primary' datetime for the event
248
-     *
249
-     * @param bool $try_to_exclude_expired
250
-     * @param bool $try_to_exclude_deleted
251
-     * @return EE_Datetime|null
252
-     * @throws EE_Error
253
-     * @throws ReflectionException
254
-     */
255
-    public function primary_datetime(
256
-        bool $try_to_exclude_expired = true,
257
-        bool $try_to_exclude_deleted = true
258
-    ): ?EE_Datetime {
259
-        if (! empty($this->_Primary_Datetime)) {
260
-            return $this->_Primary_Datetime;
261
-        }
262
-        $this->_Primary_Datetime = EEM_Datetime::instance($this->_timezone)->get_primary_datetime_for_event(
263
-            $this->ID(),
264
-            $try_to_exclude_expired,
265
-            $try_to_exclude_deleted
266
-        );
267
-        return $this->_Primary_Datetime;
268
-    }
269
-
270
-
271
-    /**
272
-     * Gets all the tickets available for purchase of this event
273
-     *
274
-     * @param array|null $query_params
275
-     * @return EE_Base_Class[]|EE_Ticket[]
276
-     * @throws EE_Error
277
-     * @throws ReflectionException
278
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
279
-     */
280
-    public function tickets(?array $query_params = []): array
281
-    {
282
-        // first get all datetimes
283
-        $datetimes = $this->datetimes_ordered();
284
-        if (! $datetimes) {
285
-            return [];
286
-        }
287
-        $datetime_ids = [];
288
-        foreach ($datetimes as $datetime) {
289
-            $datetime_ids[] = $datetime->ID();
290
-        }
291
-        $where_params = ['Datetime.DTT_ID' => ['IN', $datetime_ids]];
292
-        // if incoming $query_params has where conditions let's merge but not override existing.
293
-        if (is_array($query_params) && isset($query_params[0])) {
294
-            $where_params = array_merge($query_params[0], $where_params);
295
-            unset($query_params[0]);
296
-        }
297
-        // now add $where_params to $query_params
298
-        $query_params[0] = $where_params;
299
-        return EEM_Ticket::instance()->get_all($query_params);
300
-    }
301
-
302
-
303
-    /**
304
-     * get all unexpired not-trashed tickets
305
-     *
306
-     * @return EE_Ticket[]
307
-     * @throws EE_Error
308
-     * @throws ReflectionException
309
-     */
310
-    public function active_tickets(): array
311
-    {
312
-        return $this->tickets(
313
-            [
314
-                [
315
-                    'TKT_end_date' => ['>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')],
316
-                    'TKT_deleted'  => false,
317
-                ],
318
-            ]
319
-        );
320
-    }
321
-
322
-
323
-    /**
324
-     * @return int
325
-     * @throws EE_Error
326
-     * @throws ReflectionException
327
-     */
328
-    public function additional_limit(): int
329
-    {
330
-        return $this->get('EVT_additional_limit');
331
-    }
332
-
333
-
334
-    /**
335
-     * @return bool
336
-     * @throws EE_Error
337
-     * @throws ReflectionException
338
-     */
339
-    public function allow_overflow(): bool
340
-    {
341
-        return $this->get('EVT_allow_overflow');
342
-    }
343
-
344
-
345
-    /**
346
-     * @return string
347
-     * @throws EE_Error
348
-     * @throws ReflectionException
349
-     */
350
-    public function created(): string
351
-    {
352
-        return $this->get('EVT_created');
353
-    }
354
-
355
-
356
-    /**
357
-     * @return string
358
-     * @throws EE_Error
359
-     * @throws ReflectionException
360
-     */
361
-    public function description(): string
362
-    {
363
-        return $this->get('EVT_desc');
364
-    }
365
-
366
-
367
-    /**
368
-     * Runs do_shortcode and wpautop on the description
369
-     *
370
-     * @return string of html
371
-     * @throws EE_Error
372
-     * @throws ReflectionException
373
-     */
374
-    public function description_filtered(): string
375
-    {
376
-        return $this->get_pretty('EVT_desc');
377
-    }
378
-
379
-
380
-    /**
381
-     * @return bool
382
-     * @throws EE_Error
383
-     * @throws ReflectionException
384
-     */
385
-    public function display_description(): bool
386
-    {
387
-        return $this->get('EVT_display_desc');
388
-    }
389
-
390
-
391
-    /**
392
-     * @return bool
393
-     * @throws EE_Error
394
-     * @throws ReflectionException
395
-     */
396
-    public function display_ticket_selector(): bool
397
-    {
398
-        return (bool) $this->get('EVT_display_ticket_selector');
399
-    }
400
-
401
-
402
-    /**
403
-     * @return string
404
-     * @throws EE_Error
405
-     * @throws ReflectionException
406
-     */
407
-    public function external_url(): ?string
408
-    {
409
-        return $this->get('EVT_external_URL') ?? '';
410
-    }
411
-
412
-
413
-    /**
414
-     * @return bool
415
-     * @throws EE_Error
416
-     * @throws ReflectionException
417
-     */
418
-    public function member_only(): bool
419
-    {
420
-        return $this->get('EVT_member_only');
421
-    }
422
-
423
-
424
-    /**
425
-     * @return string
426
-     * @throws EE_Error
427
-     * @throws ReflectionException
428
-     */
429
-    public function phone(): string
430
-    {
431
-        return $this->get('EVT_phone');
432
-    }
433
-
434
-
435
-    /**
436
-     * @return string
437
-     * @throws EE_Error
438
-     * @throws ReflectionException
439
-     */
440
-    public function modified(): string
441
-    {
442
-        return $this->get('EVT_modified');
443
-    }
444
-
445
-
446
-    /**
447
-     * @return string
448
-     * @throws EE_Error
449
-     * @throws ReflectionException
450
-     */
451
-    public function name(): string
452
-    {
453
-        return $this->get('EVT_name');
454
-    }
455
-
456
-
457
-    /**
458
-     * @return int
459
-     * @throws EE_Error
460
-     * @throws ReflectionException
461
-     */
462
-    public function order(): int
463
-    {
464
-        return $this->get('EVT_order');
465
-    }
466
-
467
-
468
-    /**
469
-     * @return string
470
-     * @throws EE_Error
471
-     * @throws ReflectionException
472
-     */
473
-    public function default_registration_status(): string
474
-    {
475
-        $event_default_registration_status = $this->get('EVT_default_registration_status');
476
-        return ! empty($event_default_registration_status)
477
-            ? $event_default_registration_status
478
-            : EE_Registry::instance()->CFG->registration->default_STS_ID;
479
-    }
480
-
481
-
482
-    /**
483
-     * @param int|null    $num_words
484
-     * @param string|null $more
485
-     * @param bool        $not_full_desc
486
-     * @return string
487
-     * @throws EE_Error
488
-     * @throws ReflectionException
489
-     */
490
-    public function short_description(?int $num_words = 55, string $more = null, bool $not_full_desc = false): string
491
-    {
492
-        $short_desc = $this->get('EVT_short_desc');
493
-        if (! empty($short_desc) || $not_full_desc) {
494
-            return $short_desc;
495
-        }
496
-        $full_desc = $this->get('EVT_desc');
497
-        return wp_trim_words($full_desc, $num_words, $more);
498
-    }
499
-
500
-
501
-    /**
502
-     * @return string
503
-     * @throws EE_Error
504
-     * @throws ReflectionException
505
-     */
506
-    public function slug(): string
507
-    {
508
-        return $this->get('EVT_slug');
509
-    }
510
-
511
-
512
-    /**
513
-     * @return string
514
-     * @throws EE_Error
515
-     * @throws ReflectionException
516
-     */
517
-    public function timezone_string(): string
518
-    {
519
-        return $this->get('EVT_timezone_string');
520
-    }
521
-
522
-
523
-    /**
524
-     * @return string
525
-     * @throws EE_Error
526
-     * @throws ReflectionException
527
-     */
528
-    public function visible_on(): string
529
-    {
530
-        return $this->get('EVT_visible_on');
531
-    }
532
-
533
-
534
-    /**
535
-     * @return int
536
-     * @throws EE_Error
537
-     * @throws ReflectionException
538
-     */
539
-    public function wp_user(): int
540
-    {
541
-        return $this->get('EVT_wp_user');
542
-    }
543
-
544
-
545
-    /**
546
-     * @return bool
547
-     * @throws EE_Error
548
-     * @throws ReflectionException
549
-     */
550
-    public function donations(): bool
551
-    {
552
-        return $this->get('EVT_donations');
553
-    }
554
-
555
-
556
-    /**
557
-     * @param int $limit
558
-     * @throws EE_Error
559
-     * @throws ReflectionException
560
-     */
561
-    public function set_additional_limit(int $limit)
562
-    {
563
-        $this->set('EVT_additional_limit', $limit);
564
-    }
565
-
566
-
567
-    /**
568
-     * @param $created
569
-     * @throws EE_Error
570
-     * @throws ReflectionException
571
-     */
572
-    public function set_created($created)
573
-    {
574
-        $this->set('EVT_created', $created);
575
-    }
576
-
577
-
578
-    /**
579
-     * @param $desc
580
-     * @throws EE_Error
581
-     * @throws ReflectionException
582
-     */
583
-    public function set_description($desc)
584
-    {
585
-        $this->set('EVT_desc', $desc);
586
-    }
587
-
588
-
589
-    /**
590
-     * @param $display_desc
591
-     * @throws EE_Error
592
-     * @throws ReflectionException
593
-     */
594
-    public function set_display_description($display_desc)
595
-    {
596
-        $this->set('EVT_display_desc', $display_desc);
597
-    }
598
-
599
-
600
-    /**
601
-     * @param $display_ticket_selector
602
-     * @throws EE_Error
603
-     * @throws ReflectionException
604
-     */
605
-    public function set_display_ticket_selector($display_ticket_selector)
606
-    {
607
-        $this->set('EVT_display_ticket_selector', $display_ticket_selector);
608
-    }
609
-
610
-
611
-    /**
612
-     * @param $external_url
613
-     * @throws EE_Error
614
-     * @throws ReflectionException
615
-     */
616
-    public function set_external_url($external_url)
617
-    {
618
-        $this->set('EVT_external_URL', $external_url);
619
-    }
620
-
621
-
622
-    /**
623
-     * @param $member_only
624
-     * @throws EE_Error
625
-     * @throws ReflectionException
626
-     */
627
-    public function set_member_only($member_only)
628
-    {
629
-        $this->set('EVT_member_only', $member_only);
630
-    }
631
-
632
-
633
-    /**
634
-     * @param $event_phone
635
-     * @throws EE_Error
636
-     * @throws ReflectionException
637
-     */
638
-    public function set_event_phone($event_phone)
639
-    {
640
-        $this->set('EVT_phone', $event_phone);
641
-    }
642
-
643
-
644
-    /**
645
-     * @param $modified
646
-     * @throws EE_Error
647
-     * @throws ReflectionException
648
-     */
649
-    public function set_modified($modified)
650
-    {
651
-        $this->set('EVT_modified', $modified);
652
-    }
653
-
654
-
655
-    /**
656
-     * @param $name
657
-     * @throws EE_Error
658
-     * @throws ReflectionException
659
-     */
660
-    public function set_name($name)
661
-    {
662
-        $this->set('EVT_name', $name);
663
-    }
664
-
665
-
666
-    /**
667
-     * @param $order
668
-     * @throws EE_Error
669
-     * @throws ReflectionException
670
-     */
671
-    public function set_order($order)
672
-    {
673
-        $this->set('EVT_order', $order);
674
-    }
675
-
676
-
677
-    /**
678
-     * @param $short_desc
679
-     * @throws EE_Error
680
-     * @throws ReflectionException
681
-     */
682
-    public function set_short_description($short_desc)
683
-    {
684
-        $this->set('EVT_short_desc', $short_desc);
685
-    }
686
-
687
-
688
-    /**
689
-     * @param $slug
690
-     * @throws EE_Error
691
-     * @throws ReflectionException
692
-     */
693
-    public function set_slug($slug)
694
-    {
695
-        $this->set('EVT_slug', $slug);
696
-    }
697
-
698
-
699
-    /**
700
-     * @param $timezone_string
701
-     * @throws EE_Error
702
-     * @throws ReflectionException
703
-     */
704
-    public function set_timezone_string($timezone_string)
705
-    {
706
-        $this->set('EVT_timezone_string', $timezone_string);
707
-    }
708
-
709
-
710
-    /**
711
-     * @param $visible_on
712
-     * @throws EE_Error
713
-     * @throws ReflectionException
714
-     */
715
-    public function set_visible_on($visible_on)
716
-    {
717
-        $this->set('EVT_visible_on', $visible_on);
718
-    }
719
-
720
-
721
-    /**
722
-     * @param $wp_user
723
-     * @throws EE_Error
724
-     * @throws ReflectionException
725
-     */
726
-    public function set_wp_user($wp_user)
727
-    {
728
-        $this->set('EVT_wp_user', $wp_user);
729
-    }
730
-
731
-
732
-    /**
733
-     * @param $default_registration_status
734
-     * @throws EE_Error
735
-     * @throws ReflectionException
736
-     */
737
-    public function set_default_registration_status($default_registration_status)
738
-    {
739
-        $this->set('EVT_default_registration_status', $default_registration_status);
740
-    }
741
-
742
-
743
-    /**
744
-     * @param $donations
745
-     * @throws EE_Error
746
-     * @throws ReflectionException
747
-     */
748
-    public function set_donations($donations)
749
-    {
750
-        $this->set('EVT_donations', $donations);
751
-    }
752
-
753
-
754
-    /**
755
-     * Adds a venue to this event
756
-     *
757
-     * @param int|EE_Venue /int $venue_id_or_obj
758
-     * @return EE_Base_Class|EE_Venue
759
-     * @throws EE_Error
760
-     * @throws ReflectionException
761
-     */
762
-    public function add_venue($venue_id_or_obj): EE_Venue
763
-    {
764
-        return $this->_add_relation_to($venue_id_or_obj, 'Venue');
765
-    }
766
-
767
-
768
-    /**
769
-     * Removes a venue from the event
770
-     *
771
-     * @param EE_Venue /int $venue_id_or_obj
772
-     * @return EE_Base_Class|EE_Venue
773
-     * @throws EE_Error
774
-     * @throws ReflectionException
775
-     */
776
-    public function remove_venue($venue_id_or_obj): EE_Venue
777
-    {
778
-        $venue_id_or_obj = ! empty($venue_id_or_obj) ? $venue_id_or_obj : $this->venue();
779
-        return $this->_remove_relation_to($venue_id_or_obj, 'Venue');
780
-    }
781
-
782
-
783
-    /**
784
-     * Gets the venue related to the event. May provide additional $query_params if desired
785
-     *
786
-     * @param array $query_params
787
-     * @return int
788
-     * @throws EE_Error
789
-     * @throws ReflectionException
790
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
791
-     */
792
-    public function venue_ID(array $query_params = []): int
793
-    {
794
-        $venue = $this->get_first_related('Venue', $query_params);
795
-        return $venue instanceof EE_Venue ? $venue->ID() : 0;
796
-    }
797
-
798
-
799
-    /**
800
-     * Gets the venue related to the event. May provide additional $query_params if desired
801
-     *
802
-     * @param array $query_params
803
-     * @return EE_Base_Class|EE_Venue|null
804
-     * @throws EE_Error
805
-     * @throws ReflectionException
806
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
807
-     */
808
-    public function venue(array $query_params = []): ?EE_Venue
809
-    {
810
-        return $this->get_first_related('Venue', $query_params);
811
-    }
812
-
813
-
814
-    /**
815
-     * @param array $query_params
816
-     * @return EE_Base_Class[]|EE_Venue[]
817
-     * @throws EE_Error
818
-     * @throws ReflectionException
819
-     * @deprecated $VID:$
820
-     */
821
-    public function venues(array $query_params = []): array
822
-    {
823
-        return [$this->venue($query_params)];
824
-    }
825
-
826
-
827
-    /**
828
-     * check if event id is present and if event is published
829
-     *
830
-     * @return boolean true yes, false no
831
-     * @throws EE_Error
832
-     * @throws ReflectionException
833
-     */
834
-    private function _has_ID_and_is_published(): bool
835
-    {
836
-        // first check if event id is present and not NULL,
837
-        // then check if this event is published (or any of the equivalent "published" statuses)
838
-        return
839
-            $this->ID() && $this->ID() !== null
840
-            && (
841
-                $this->status() === 'publish'
842
-                || $this->status() === EEM_Event::sold_out
843
-                || $this->status() === EEM_Event::postponed
844
-                || $this->status() === EEM_Event::cancelled
845
-            );
846
-    }
847
-
848
-
849
-    /**
850
-     * This simply compares the internal dates with NOW and determines if the event is upcoming or not.
851
-     *
852
-     * @return boolean true yes, false no
853
-     * @throws EE_Error
854
-     * @throws ReflectionException
855
-     */
856
-    public function is_upcoming(): bool
857
-    {
858
-        // check if event id is present and if this event is published
859
-        if ($this->is_inactive()) {
860
-            return false;
861
-        }
862
-        // set initial value
863
-        $upcoming = false;
864
-        // next let's get all datetimes and loop through them
865
-        $datetimes = $this->datetimes_in_chronological_order();
866
-        foreach ($datetimes as $datetime) {
867
-            if ($datetime instanceof EE_Datetime) {
868
-                // if this dtt is expired then we continue cause one of the other datetimes might be upcoming.
869
-                if ($datetime->is_expired()) {
870
-                    continue;
871
-                }
872
-                // if this dtt is active then we return false.
873
-                if ($datetime->is_active()) {
874
-                    return false;
875
-                }
876
-                // otherwise let's check upcoming status
877
-                $upcoming = $datetime->is_upcoming();
878
-            }
879
-        }
880
-        return $upcoming;
881
-    }
882
-
883
-
884
-    /**
885
-     * @return bool
886
-     * @throws EE_Error
887
-     * @throws ReflectionException
888
-     */
889
-    public function is_active(): bool
890
-    {
891
-        // check if event id is present and if this event is published
892
-        if ($this->is_inactive()) {
893
-            return false;
894
-        }
895
-        // set initial value
896
-        $active = false;
897
-        // next let's get all datetimes and loop through them
898
-        $datetimes = $this->datetimes_in_chronological_order();
899
-        foreach ($datetimes as $datetime) {
900
-            if ($datetime instanceof EE_Datetime) {
901
-                // if this dtt is expired then we continue cause one of the other datetimes might be active.
902
-                if ($datetime->is_expired()) {
903
-                    continue;
904
-                }
905
-                // if this dtt is upcoming then we return false.
906
-                if ($datetime->is_upcoming()) {
907
-                    return false;
908
-                }
909
-                // otherwise let's check active status
910
-                $active = $datetime->is_active();
911
-            }
912
-        }
913
-        return $active;
914
-    }
915
-
916
-
917
-    /**
918
-     * @return bool
919
-     * @throws EE_Error
920
-     * @throws ReflectionException
921
-     */
922
-    public function is_expired(): bool
923
-    {
924
-        // check if event id is present and if this event is published
925
-        if ($this->is_inactive()) {
926
-            return false;
927
-        }
928
-        // set initial value
929
-        $expired = false;
930
-        // first let's get all datetimes and loop through them
931
-        $datetimes = $this->datetimes_in_chronological_order();
932
-        foreach ($datetimes as $datetime) {
933
-            if ($datetime instanceof EE_Datetime) {
934
-                // if this dtt is upcoming or active then we return false.
935
-                if ($datetime->is_upcoming() || $datetime->is_active()) {
936
-                    return false;
937
-                }
938
-                // otherwise let's check active status
939
-                $expired = $datetime->is_expired();
940
-            }
941
-        }
942
-        return $expired;
943
-    }
944
-
945
-
946
-    /**
947
-     * @return bool
948
-     * @throws EE_Error
949
-     * @throws ReflectionException
950
-     */
951
-    public function is_inactive(): bool
952
-    {
953
-        // check if event id is present and if this event is published
954
-        if ($this->_has_ID_and_is_published()) {
955
-            return false;
956
-        }
957
-        return true;
958
-    }
959
-
960
-
961
-    /**
962
-     * calculate spaces remaining based on "saleable" tickets
963
-     *
964
-     * @param array|null $tickets
965
-     * @param bool       $filtered
966
-     * @return int|float
967
-     * @throws EE_Error
968
-     * @throws DomainException
969
-     * @throws UnexpectedEntityException
970
-     * @throws ReflectionException
971
-     */
972
-    public function spaces_remaining(?array $tickets = [], ?bool $filtered = true)
973
-    {
974
-        $this->getAvailableSpacesCalculator()->setActiveTickets($tickets);
975
-        $spaces_remaining = $this->getAvailableSpacesCalculator()->spacesRemaining();
976
-        return $filtered
977
-            ? apply_filters(
978
-                'FHEE_EE_Event__spaces_remaining',
979
-                $spaces_remaining,
980
-                $this,
981
-                $tickets
982
-            )
983
-            : $spaces_remaining;
984
-    }
985
-
986
-
987
-    /**
988
-     *    perform_sold_out_status_check
989
-     *    checks all of this event's datetime  reg_limit - sold values to determine if ANY datetimes have spaces
990
-     *    available... if NOT, then the event status will get toggled to 'sold_out'
991
-     *
992
-     * @return bool    return the ACTUAL sold out state.
993
-     * @throws EE_Error
994
-     * @throws DomainException
995
-     * @throws UnexpectedEntityException
996
-     * @throws ReflectionException
997
-     */
998
-    public function perform_sold_out_status_check(): bool
999
-    {
1000
-        // get all tickets
1001
-        $tickets     = $this->tickets(
1002
-            [
1003
-                'default_where_conditions' => 'none',
1004
-                'order_by'                 => ['TKT_qty' => 'ASC'],
1005
-            ]
1006
-        );
1007
-        $all_expired = true;
1008
-        foreach ($tickets as $ticket) {
1009
-            if (! $ticket->is_expired()) {
1010
-                $all_expired = false;
1011
-                break;
1012
-            }
1013
-        }
1014
-        // if all the tickets are just expired, then don't update the event status to sold out
1015
-        if ($all_expired) {
1016
-            return true;
1017
-        }
1018
-        $spaces_remaining = $this->spaces_remaining($tickets);
1019
-        if ($spaces_remaining < 1) {
1020
-            if ($this->status() !== EEM_CPT_Base::post_status_private) {
1021
-                $this->set_status(EEM_Event::sold_out);
1022
-                $this->save();
1023
-            }
1024
-            $sold_out = true;
1025
-        } else {
1026
-            $sold_out = false;
1027
-            // was event previously marked as sold out ?
1028
-            if ($this->status() === EEM_Event::sold_out) {
1029
-                // revert status to previous value, if it was set
1030
-                $previous_event_status = $this->get_post_meta('_previous_event_status', true);
1031
-                if ($previous_event_status) {
1032
-                    $this->set_status($previous_event_status);
1033
-                    $this->save();
1034
-                }
1035
-            }
1036
-        }
1037
-        do_action('AHEE__EE_Event__perform_sold_out_status_check__end', $this, $sold_out, $spaces_remaining, $tickets);
1038
-        return $sold_out;
1039
-    }
1040
-
1041
-
1042
-    /**
1043
-     * This returns the total remaining spaces for sale on this event.
1044
-     *
1045
-     * @return int|float
1046
-     * @throws EE_Error
1047
-     * @throws DomainException
1048
-     * @throws UnexpectedEntityException
1049
-     * @throws ReflectionException
1050
-     * @uses EE_Event::total_available_spaces()
1051
-     */
1052
-    public function spaces_remaining_for_sale()
1053
-    {
1054
-        return $this->total_available_spaces(true);
1055
-    }
1056
-
1057
-
1058
-    /**
1059
-     * This returns the total spaces available for an event
1060
-     * while considering all the quantities on the tickets and the reg limits
1061
-     * on the datetimes attached to this event.
1062
-     *
1063
-     * @param bool $consider_sold   Whether to consider any tickets that have already sold in our calculation.
1064
-     *                              If this is false, then we return the most tickets that could ever be sold
1065
-     *                              for this event with the datetime and tickets setup on the event under optimal
1066
-     *                              selling conditions.  Otherwise we return a live calculation of spaces available
1067
-     *                              based on tickets sold.  Depending on setup and stage of sales, this
1068
-     *                              may appear to equal remaining tickets.  However, the more tickets are
1069
-     *                              sold out, the more accurate the "live" total is.
1070
-     * @return int|float
1071
-     * @throws EE_Error
1072
-     * @throws DomainException
1073
-     * @throws UnexpectedEntityException
1074
-     * @throws ReflectionException
1075
-     */
1076
-    public function total_available_spaces(bool $consider_sold = false)
1077
-    {
1078
-        $spaces_available = $consider_sold
1079
-            ? $this->getAvailableSpacesCalculator()->spacesRemaining()
1080
-            : $this->getAvailableSpacesCalculator()->totalSpacesAvailable();
1081
-        return apply_filters(
1082
-            'FHEE_EE_Event__total_available_spaces__spaces_available',
1083
-            $spaces_available,
1084
-            $this,
1085
-            $this->getAvailableSpacesCalculator()->getDatetimes(),
1086
-            $this->getAvailableSpacesCalculator()->getActiveTickets()
1087
-        );
1088
-    }
1089
-
1090
-
1091
-    /**
1092
-     * Checks if the event is set to sold out
1093
-     *
1094
-     * @param bool $actual  whether or not to perform calculations to not only figure the
1095
-     *                      actual status but also to flip the status if necessary to sold
1096
-     *                      out If false, we just check the existing status of the event
1097
-     * @return boolean
1098
-     * @throws EE_Error
1099
-     * @throws ReflectionException
1100
-     */
1101
-    public function is_sold_out(bool $actual = false): bool
1102
-    {
1103
-        if (! $actual) {
1104
-            return $this->status() === EEM_Event::sold_out;
1105
-        }
1106
-        return $this->perform_sold_out_status_check();
1107
-    }
1108
-
1109
-
1110
-    /**
1111
-     * Checks if the event is marked as postponed
1112
-     *
1113
-     * @return boolean
1114
-     */
1115
-    public function is_postponed(): bool
1116
-    {
1117
-        return $this->status() === EEM_Event::postponed;
1118
-    }
1119
-
1120
-
1121
-    /**
1122
-     * Checks if the event is marked as cancelled
1123
-     *
1124
-     * @return boolean
1125
-     */
1126
-    public function is_cancelled(): bool
1127
-    {
1128
-        return $this->status() === EEM_Event::cancelled;
1129
-    }
1130
-
1131
-
1132
-    /**
1133
-     * Get the logical active status in a hierarchical order for all the datetimes.  Note
1134
-     * Basically, we order the datetimes by EVT_start_date.  Then first test on whether the event is published.  If its
1135
-     * NOT published then we test for whether its expired or not.  IF it IS published then we test first on whether an
1136
-     * event has any active dates.  If no active dates then we check for any upcoming dates.  If no upcoming dates then
1137
-     * the event is considered expired.
1138
-     * NOTE: this method does NOT calculate whether the datetimes are sold out when event is published.  Sold Out is a
1139
-     * status set on the EVENT when it is not published and thus is done
1140
-     *
1141
-     * @param bool $reset
1142
-     * @return bool | string - based on EE_Datetime active constants or FALSE if error.
1143
-     * @throws EE_Error
1144
-     * @throws ReflectionException
1145
-     */
1146
-    public function get_active_status(bool $reset = false)
1147
-    {
1148
-        // if the active status has already been set, then just use that value (unless we are resetting it)
1149
-        if (! empty($this->_active_status) && ! $reset) {
1150
-            return $this->_active_status;
1151
-        }
1152
-        // first check if event id is present on this object
1153
-        if (! $this->ID()) {
1154
-            return false;
1155
-        }
1156
-        $where_params_for_event = [['EVT_ID' => $this->ID()]];
1157
-        // if event is published:
1158
-        if (
1159
-            $this->status() === EEM_CPT_Base::post_status_publish
1160
-            || $this->status() === EEM_CPT_Base::post_status_private
1161
-        ) {
1162
-            // active?
1163
-            if (
1164
-                EEM_Datetime::instance()->get_datetime_count_for_status(
1165
-                    EE_Datetime::active,
1166
-                    $where_params_for_event
1167
-                ) > 0
1168
-            ) {
1169
-                $this->_active_status = EE_Datetime::active;
1170
-            } else {
1171
-                // upcoming?
1172
-                if (
1173
-                    EEM_Datetime::instance()->get_datetime_count_for_status(
1174
-                        EE_Datetime::upcoming,
1175
-                        $where_params_for_event
1176
-                    ) > 0
1177
-                ) {
1178
-                    $this->_active_status = EE_Datetime::upcoming;
1179
-                } else {
1180
-                    // expired?
1181
-                    if (
1182
-                        EEM_Datetime::instance()->get_datetime_count_for_status(
1183
-                            EE_Datetime::expired,
1184
-                            $where_params_for_event
1185
-                        ) > 0
1186
-                    ) {
1187
-                        $this->_active_status = EE_Datetime::expired;
1188
-                    } else {
1189
-                        // it would be odd if things make it this far
1190
-                        // because it basically means there are no datetimes attached to the event.
1191
-                        // So in this case it will just be considered inactive.
1192
-                        $this->_active_status = EE_Datetime::inactive;
1193
-                    }
1194
-                }
1195
-            }
1196
-        } else {
1197
-            // the event is not published, so let's just set it's active status according to its' post status
1198
-            switch ($this->status()) {
1199
-                case EEM_Event::sold_out:
1200
-                    $this->_active_status = EE_Datetime::sold_out;
1201
-                    break;
1202
-                case EEM_Event::cancelled:
1203
-                    $this->_active_status = EE_Datetime::cancelled;
1204
-                    break;
1205
-                case EEM_Event::postponed:
1206
-                    $this->_active_status = EE_Datetime::postponed;
1207
-                    break;
1208
-                default:
1209
-                    $this->_active_status = EE_Datetime::inactive;
1210
-            }
1211
-        }
1212
-        return $this->_active_status;
1213
-    }
1214
-
1215
-
1216
-    /**
1217
-     *    pretty_active_status
1218
-     *
1219
-     * @param boolean $echo whether to return (FALSE), or echo out the result (TRUE)
1220
-     * @return string
1221
-     * @throws EE_Error
1222
-     * @throws ReflectionException
1223
-     */
1224
-    public function pretty_active_status(bool $echo = true): string
1225
-    {
1226
-        $active_status = $this->get_active_status();
1227
-        $status        = "
19
+	/**
20
+	 * cached value for the the logical active status for the event
21
+	 *
22
+	 * @see get_active_status()
23
+	 * @var string
24
+	 */
25
+	protected $_active_status = '';
26
+
27
+	/**
28
+	 * This is just used for caching the Primary Datetime for the Event on initial retrieval
29
+	 *
30
+	 * @var EE_Datetime
31
+	 */
32
+	protected $_Primary_Datetime;
33
+
34
+	/**
35
+	 * @var EventSpacesCalculator $available_spaces_calculator
36
+	 */
37
+	protected $available_spaces_calculator;
38
+
39
+
40
+	/**
41
+	 * @param array  $props_n_values          incoming values
42
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
43
+	 *                                        used.)
44
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
45
+	 *                                        date_format and the second value is the time format
46
+	 * @return EE_Event
47
+	 * @throws EE_Error
48
+	 * @throws ReflectionException
49
+	 */
50
+	public static function new_instance($props_n_values = [], $timezone = null, $date_formats = []): EE_Event
51
+	{
52
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
53
+		return $has_object ?: new self($props_n_values, false, $timezone, $date_formats);
54
+	}
55
+
56
+
57
+	/**
58
+	 * @param array  $props_n_values  incoming values from the database
59
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
60
+	 *                                the website will be used.
61
+	 * @return EE_Event
62
+	 * @throws EE_Error
63
+	 * @throws ReflectionException
64
+	 */
65
+	public static function new_instance_from_db($props_n_values = [], $timezone = null): EE_Event
66
+	{
67
+		return new self($props_n_values, true, $timezone);
68
+	}
69
+
70
+
71
+	/**
72
+	 * @return EventSpacesCalculator
73
+	 * @throws EE_Error
74
+	 * @throws ReflectionException
75
+	 */
76
+	public function getAvailableSpacesCalculator(): EventSpacesCalculator
77
+	{
78
+		if (! $this->available_spaces_calculator instanceof EventSpacesCalculator) {
79
+			$this->available_spaces_calculator = new EventSpacesCalculator($this);
80
+		}
81
+		return $this->available_spaces_calculator;
82
+	}
83
+
84
+
85
+	/**
86
+	 * Overrides parent set() method so that all calls to set( 'status', $status ) can be routed to internal methods
87
+	 *
88
+	 * @param string $field_name
89
+	 * @param mixed  $field_value
90
+	 * @param bool   $use_default
91
+	 * @throws EE_Error
92
+	 * @throws ReflectionException
93
+	 */
94
+	public function set($field_name, $field_value, $use_default = false)
95
+	{
96
+		switch ($field_name) {
97
+			case 'status':
98
+				$this->set_status($field_value, $use_default);
99
+				break;
100
+			default:
101
+				parent::set($field_name, $field_value, $use_default);
102
+		}
103
+	}
104
+
105
+
106
+	/**
107
+	 *    set_status
108
+	 * Checks if event status is being changed to SOLD OUT
109
+	 * and updates event meta data with previous event status
110
+	 * so that we can revert things if/when the event is no longer sold out
111
+	 *
112
+	 * @param string $status
113
+	 * @param bool   $use_default
114
+	 * @return void
115
+	 * @throws EE_Error
116
+	 * @throws ReflectionException
117
+	 */
118
+	public function set_status($status = '', $use_default = false)
119
+	{
120
+		// if nothing is set, and we aren't explicitly wanting to reset the status, then just leave
121
+		if (empty($status) && ! $use_default) {
122
+			return;
123
+		}
124
+		// get current Event status
125
+		$old_status = $this->status();
126
+		// if status has changed
127
+		if ($old_status !== $status) {
128
+			// TO sold_out
129
+			if ($status === EEM_Event::sold_out) {
130
+				// save the previous event status so that we can revert if the event is no longer sold out
131
+				$this->add_post_meta('_previous_event_status', $old_status);
132
+				do_action('AHEE__EE_Event__set_status__to_sold_out', $this, $old_status, $status);
133
+				// OR FROM  sold_out
134
+			} elseif ($old_status === EEM_Event::sold_out) {
135
+				$this->delete_post_meta('_previous_event_status');
136
+				do_action('AHEE__EE_Event__set_status__from_sold_out', $this, $old_status, $status);
137
+			}
138
+			// clear out the active status so that it gets reset the next time it is requested
139
+			$this->_active_status = null;
140
+			// update status
141
+			parent::set('status', $status, $use_default);
142
+			do_action('AHEE__EE_Event__set_status__after_update', $this);
143
+			return;
144
+		}
145
+		// even though the old value matches the new value, it's still good to
146
+		// allow the parent set method to have a say
147
+		parent::set('status', $status, $use_default);
148
+	}
149
+
150
+
151
+	/**
152
+	 * Gets all the datetimes for this event
153
+	 *
154
+	 * @param array|null $query_params
155
+	 * @return EE_Base_Class[]|EE_Datetime[]
156
+	 * @throws EE_Error
157
+	 * @throws ReflectionException
158
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
159
+	 */
160
+	public function datetimes(?array $query_params = []): array
161
+	{
162
+		return $this->get_many_related('Datetime', $query_params);
163
+	}
164
+
165
+
166
+	/**
167
+	 * Gets all the datetimes for this event that are currently ACTIVE,
168
+	 * meaning the datetime has started and has not yet ended.
169
+	 *
170
+	 * @param int|null   $start_date   timestamp to use for event date start time, defaults to NOW unless set to 0
171
+	 * @param array|null $query_params will recursively replace default values
172
+	 * @throws EE_Error
173
+	 * @throws ReflectionException
174
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
175
+	 */
176
+	public function activeDatetimes(?int $start_date, ?array $query_params = []): array
177
+	{
178
+		// if start date is null, then use current time
179
+		$start_date = $start_date ?? time();
180
+		$where      = [];
181
+		if ($start_date) {
182
+			$where['DTT_EVT_start'] = ['<', $start_date];
183
+			$where['DTT_EVT_end']   = ['>', time()];
184
+		}
185
+		$query_params = array_replace_recursive(
186
+			[
187
+				$where,
188
+				'order_by' => ['DTT_EVT_start' => 'ASC'],
189
+			],
190
+			$query_params
191
+		);
192
+		return $this->get_many_related('Datetime', $query_params);
193
+	}
194
+
195
+
196
+	/**
197
+	 * Gets all the datetimes for this event, ordered by DTT_EVT_start in ascending order
198
+	 *
199
+	 * @return EE_Base_Class[]|EE_Datetime[]
200
+	 * @throws EE_Error
201
+	 * @throws ReflectionException
202
+	 */
203
+	public function datetimes_in_chronological_order(): array
204
+	{
205
+		return $this->get_many_related('Datetime', ['order_by' => ['DTT_EVT_start' => 'ASC']]);
206
+	}
207
+
208
+
209
+	/**
210
+	 * Gets all the datetimes for this event, ordered by the DTT_order on the datetime.
211
+	 * @darren, we should probably UNSET timezone on the EEM_Datetime model
212
+	 * after running our query, so that this timezone isn't set for EVERY query
213
+	 * on EEM_Datetime for the rest of the request, no?
214
+	 *
215
+	 * @param bool     $show_expired whether or not to include expired events
216
+	 * @param bool     $show_deleted whether or not to include deleted events
217
+	 * @param int|null $limit
218
+	 * @return EE_Datetime[]
219
+	 * @throws EE_Error
220
+	 * @throws ReflectionException
221
+	 */
222
+	public function datetimes_ordered(bool $show_expired = true, bool $show_deleted = false, ?int $limit = null): array
223
+	{
224
+		return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_event_ordered_by_DTT_order(
225
+			$this->ID(),
226
+			$show_expired,
227
+			$show_deleted,
228
+			$limit
229
+		);
230
+	}
231
+
232
+
233
+	/**
234
+	 * Returns one related datetime. Mostly only used by some legacy code.
235
+	 *
236
+	 * @return EE_Base_Class|EE_Datetime
237
+	 * @throws EE_Error
238
+	 * @throws ReflectionException
239
+	 */
240
+	public function first_datetime(): EE_Datetime
241
+	{
242
+		return $this->get_first_related('Datetime');
243
+	}
244
+
245
+
246
+	/**
247
+	 * Returns the 'primary' datetime for the event
248
+	 *
249
+	 * @param bool $try_to_exclude_expired
250
+	 * @param bool $try_to_exclude_deleted
251
+	 * @return EE_Datetime|null
252
+	 * @throws EE_Error
253
+	 * @throws ReflectionException
254
+	 */
255
+	public function primary_datetime(
256
+		bool $try_to_exclude_expired = true,
257
+		bool $try_to_exclude_deleted = true
258
+	): ?EE_Datetime {
259
+		if (! empty($this->_Primary_Datetime)) {
260
+			return $this->_Primary_Datetime;
261
+		}
262
+		$this->_Primary_Datetime = EEM_Datetime::instance($this->_timezone)->get_primary_datetime_for_event(
263
+			$this->ID(),
264
+			$try_to_exclude_expired,
265
+			$try_to_exclude_deleted
266
+		);
267
+		return $this->_Primary_Datetime;
268
+	}
269
+
270
+
271
+	/**
272
+	 * Gets all the tickets available for purchase of this event
273
+	 *
274
+	 * @param array|null $query_params
275
+	 * @return EE_Base_Class[]|EE_Ticket[]
276
+	 * @throws EE_Error
277
+	 * @throws ReflectionException
278
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
279
+	 */
280
+	public function tickets(?array $query_params = []): array
281
+	{
282
+		// first get all datetimes
283
+		$datetimes = $this->datetimes_ordered();
284
+		if (! $datetimes) {
285
+			return [];
286
+		}
287
+		$datetime_ids = [];
288
+		foreach ($datetimes as $datetime) {
289
+			$datetime_ids[] = $datetime->ID();
290
+		}
291
+		$where_params = ['Datetime.DTT_ID' => ['IN', $datetime_ids]];
292
+		// if incoming $query_params has where conditions let's merge but not override existing.
293
+		if (is_array($query_params) && isset($query_params[0])) {
294
+			$where_params = array_merge($query_params[0], $where_params);
295
+			unset($query_params[0]);
296
+		}
297
+		// now add $where_params to $query_params
298
+		$query_params[0] = $where_params;
299
+		return EEM_Ticket::instance()->get_all($query_params);
300
+	}
301
+
302
+
303
+	/**
304
+	 * get all unexpired not-trashed tickets
305
+	 *
306
+	 * @return EE_Ticket[]
307
+	 * @throws EE_Error
308
+	 * @throws ReflectionException
309
+	 */
310
+	public function active_tickets(): array
311
+	{
312
+		return $this->tickets(
313
+			[
314
+				[
315
+					'TKT_end_date' => ['>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')],
316
+					'TKT_deleted'  => false,
317
+				],
318
+			]
319
+		);
320
+	}
321
+
322
+
323
+	/**
324
+	 * @return int
325
+	 * @throws EE_Error
326
+	 * @throws ReflectionException
327
+	 */
328
+	public function additional_limit(): int
329
+	{
330
+		return $this->get('EVT_additional_limit');
331
+	}
332
+
333
+
334
+	/**
335
+	 * @return bool
336
+	 * @throws EE_Error
337
+	 * @throws ReflectionException
338
+	 */
339
+	public function allow_overflow(): bool
340
+	{
341
+		return $this->get('EVT_allow_overflow');
342
+	}
343
+
344
+
345
+	/**
346
+	 * @return string
347
+	 * @throws EE_Error
348
+	 * @throws ReflectionException
349
+	 */
350
+	public function created(): string
351
+	{
352
+		return $this->get('EVT_created');
353
+	}
354
+
355
+
356
+	/**
357
+	 * @return string
358
+	 * @throws EE_Error
359
+	 * @throws ReflectionException
360
+	 */
361
+	public function description(): string
362
+	{
363
+		return $this->get('EVT_desc');
364
+	}
365
+
366
+
367
+	/**
368
+	 * Runs do_shortcode and wpautop on the description
369
+	 *
370
+	 * @return string of html
371
+	 * @throws EE_Error
372
+	 * @throws ReflectionException
373
+	 */
374
+	public function description_filtered(): string
375
+	{
376
+		return $this->get_pretty('EVT_desc');
377
+	}
378
+
379
+
380
+	/**
381
+	 * @return bool
382
+	 * @throws EE_Error
383
+	 * @throws ReflectionException
384
+	 */
385
+	public function display_description(): bool
386
+	{
387
+		return $this->get('EVT_display_desc');
388
+	}
389
+
390
+
391
+	/**
392
+	 * @return bool
393
+	 * @throws EE_Error
394
+	 * @throws ReflectionException
395
+	 */
396
+	public function display_ticket_selector(): bool
397
+	{
398
+		return (bool) $this->get('EVT_display_ticket_selector');
399
+	}
400
+
401
+
402
+	/**
403
+	 * @return string
404
+	 * @throws EE_Error
405
+	 * @throws ReflectionException
406
+	 */
407
+	public function external_url(): ?string
408
+	{
409
+		return $this->get('EVT_external_URL') ?? '';
410
+	}
411
+
412
+
413
+	/**
414
+	 * @return bool
415
+	 * @throws EE_Error
416
+	 * @throws ReflectionException
417
+	 */
418
+	public function member_only(): bool
419
+	{
420
+		return $this->get('EVT_member_only');
421
+	}
422
+
423
+
424
+	/**
425
+	 * @return string
426
+	 * @throws EE_Error
427
+	 * @throws ReflectionException
428
+	 */
429
+	public function phone(): string
430
+	{
431
+		return $this->get('EVT_phone');
432
+	}
433
+
434
+
435
+	/**
436
+	 * @return string
437
+	 * @throws EE_Error
438
+	 * @throws ReflectionException
439
+	 */
440
+	public function modified(): string
441
+	{
442
+		return $this->get('EVT_modified');
443
+	}
444
+
445
+
446
+	/**
447
+	 * @return string
448
+	 * @throws EE_Error
449
+	 * @throws ReflectionException
450
+	 */
451
+	public function name(): string
452
+	{
453
+		return $this->get('EVT_name');
454
+	}
455
+
456
+
457
+	/**
458
+	 * @return int
459
+	 * @throws EE_Error
460
+	 * @throws ReflectionException
461
+	 */
462
+	public function order(): int
463
+	{
464
+		return $this->get('EVT_order');
465
+	}
466
+
467
+
468
+	/**
469
+	 * @return string
470
+	 * @throws EE_Error
471
+	 * @throws ReflectionException
472
+	 */
473
+	public function default_registration_status(): string
474
+	{
475
+		$event_default_registration_status = $this->get('EVT_default_registration_status');
476
+		return ! empty($event_default_registration_status)
477
+			? $event_default_registration_status
478
+			: EE_Registry::instance()->CFG->registration->default_STS_ID;
479
+	}
480
+
481
+
482
+	/**
483
+	 * @param int|null    $num_words
484
+	 * @param string|null $more
485
+	 * @param bool        $not_full_desc
486
+	 * @return string
487
+	 * @throws EE_Error
488
+	 * @throws ReflectionException
489
+	 */
490
+	public function short_description(?int $num_words = 55, string $more = null, bool $not_full_desc = false): string
491
+	{
492
+		$short_desc = $this->get('EVT_short_desc');
493
+		if (! empty($short_desc) || $not_full_desc) {
494
+			return $short_desc;
495
+		}
496
+		$full_desc = $this->get('EVT_desc');
497
+		return wp_trim_words($full_desc, $num_words, $more);
498
+	}
499
+
500
+
501
+	/**
502
+	 * @return string
503
+	 * @throws EE_Error
504
+	 * @throws ReflectionException
505
+	 */
506
+	public function slug(): string
507
+	{
508
+		return $this->get('EVT_slug');
509
+	}
510
+
511
+
512
+	/**
513
+	 * @return string
514
+	 * @throws EE_Error
515
+	 * @throws ReflectionException
516
+	 */
517
+	public function timezone_string(): string
518
+	{
519
+		return $this->get('EVT_timezone_string');
520
+	}
521
+
522
+
523
+	/**
524
+	 * @return string
525
+	 * @throws EE_Error
526
+	 * @throws ReflectionException
527
+	 */
528
+	public function visible_on(): string
529
+	{
530
+		return $this->get('EVT_visible_on');
531
+	}
532
+
533
+
534
+	/**
535
+	 * @return int
536
+	 * @throws EE_Error
537
+	 * @throws ReflectionException
538
+	 */
539
+	public function wp_user(): int
540
+	{
541
+		return $this->get('EVT_wp_user');
542
+	}
543
+
544
+
545
+	/**
546
+	 * @return bool
547
+	 * @throws EE_Error
548
+	 * @throws ReflectionException
549
+	 */
550
+	public function donations(): bool
551
+	{
552
+		return $this->get('EVT_donations');
553
+	}
554
+
555
+
556
+	/**
557
+	 * @param int $limit
558
+	 * @throws EE_Error
559
+	 * @throws ReflectionException
560
+	 */
561
+	public function set_additional_limit(int $limit)
562
+	{
563
+		$this->set('EVT_additional_limit', $limit);
564
+	}
565
+
566
+
567
+	/**
568
+	 * @param $created
569
+	 * @throws EE_Error
570
+	 * @throws ReflectionException
571
+	 */
572
+	public function set_created($created)
573
+	{
574
+		$this->set('EVT_created', $created);
575
+	}
576
+
577
+
578
+	/**
579
+	 * @param $desc
580
+	 * @throws EE_Error
581
+	 * @throws ReflectionException
582
+	 */
583
+	public function set_description($desc)
584
+	{
585
+		$this->set('EVT_desc', $desc);
586
+	}
587
+
588
+
589
+	/**
590
+	 * @param $display_desc
591
+	 * @throws EE_Error
592
+	 * @throws ReflectionException
593
+	 */
594
+	public function set_display_description($display_desc)
595
+	{
596
+		$this->set('EVT_display_desc', $display_desc);
597
+	}
598
+
599
+
600
+	/**
601
+	 * @param $display_ticket_selector
602
+	 * @throws EE_Error
603
+	 * @throws ReflectionException
604
+	 */
605
+	public function set_display_ticket_selector($display_ticket_selector)
606
+	{
607
+		$this->set('EVT_display_ticket_selector', $display_ticket_selector);
608
+	}
609
+
610
+
611
+	/**
612
+	 * @param $external_url
613
+	 * @throws EE_Error
614
+	 * @throws ReflectionException
615
+	 */
616
+	public function set_external_url($external_url)
617
+	{
618
+		$this->set('EVT_external_URL', $external_url);
619
+	}
620
+
621
+
622
+	/**
623
+	 * @param $member_only
624
+	 * @throws EE_Error
625
+	 * @throws ReflectionException
626
+	 */
627
+	public function set_member_only($member_only)
628
+	{
629
+		$this->set('EVT_member_only', $member_only);
630
+	}
631
+
632
+
633
+	/**
634
+	 * @param $event_phone
635
+	 * @throws EE_Error
636
+	 * @throws ReflectionException
637
+	 */
638
+	public function set_event_phone($event_phone)
639
+	{
640
+		$this->set('EVT_phone', $event_phone);
641
+	}
642
+
643
+
644
+	/**
645
+	 * @param $modified
646
+	 * @throws EE_Error
647
+	 * @throws ReflectionException
648
+	 */
649
+	public function set_modified($modified)
650
+	{
651
+		$this->set('EVT_modified', $modified);
652
+	}
653
+
654
+
655
+	/**
656
+	 * @param $name
657
+	 * @throws EE_Error
658
+	 * @throws ReflectionException
659
+	 */
660
+	public function set_name($name)
661
+	{
662
+		$this->set('EVT_name', $name);
663
+	}
664
+
665
+
666
+	/**
667
+	 * @param $order
668
+	 * @throws EE_Error
669
+	 * @throws ReflectionException
670
+	 */
671
+	public function set_order($order)
672
+	{
673
+		$this->set('EVT_order', $order);
674
+	}
675
+
676
+
677
+	/**
678
+	 * @param $short_desc
679
+	 * @throws EE_Error
680
+	 * @throws ReflectionException
681
+	 */
682
+	public function set_short_description($short_desc)
683
+	{
684
+		$this->set('EVT_short_desc', $short_desc);
685
+	}
686
+
687
+
688
+	/**
689
+	 * @param $slug
690
+	 * @throws EE_Error
691
+	 * @throws ReflectionException
692
+	 */
693
+	public function set_slug($slug)
694
+	{
695
+		$this->set('EVT_slug', $slug);
696
+	}
697
+
698
+
699
+	/**
700
+	 * @param $timezone_string
701
+	 * @throws EE_Error
702
+	 * @throws ReflectionException
703
+	 */
704
+	public function set_timezone_string($timezone_string)
705
+	{
706
+		$this->set('EVT_timezone_string', $timezone_string);
707
+	}
708
+
709
+
710
+	/**
711
+	 * @param $visible_on
712
+	 * @throws EE_Error
713
+	 * @throws ReflectionException
714
+	 */
715
+	public function set_visible_on($visible_on)
716
+	{
717
+		$this->set('EVT_visible_on', $visible_on);
718
+	}
719
+
720
+
721
+	/**
722
+	 * @param $wp_user
723
+	 * @throws EE_Error
724
+	 * @throws ReflectionException
725
+	 */
726
+	public function set_wp_user($wp_user)
727
+	{
728
+		$this->set('EVT_wp_user', $wp_user);
729
+	}
730
+
731
+
732
+	/**
733
+	 * @param $default_registration_status
734
+	 * @throws EE_Error
735
+	 * @throws ReflectionException
736
+	 */
737
+	public function set_default_registration_status($default_registration_status)
738
+	{
739
+		$this->set('EVT_default_registration_status', $default_registration_status);
740
+	}
741
+
742
+
743
+	/**
744
+	 * @param $donations
745
+	 * @throws EE_Error
746
+	 * @throws ReflectionException
747
+	 */
748
+	public function set_donations($donations)
749
+	{
750
+		$this->set('EVT_donations', $donations);
751
+	}
752
+
753
+
754
+	/**
755
+	 * Adds a venue to this event
756
+	 *
757
+	 * @param int|EE_Venue /int $venue_id_or_obj
758
+	 * @return EE_Base_Class|EE_Venue
759
+	 * @throws EE_Error
760
+	 * @throws ReflectionException
761
+	 */
762
+	public function add_venue($venue_id_or_obj): EE_Venue
763
+	{
764
+		return $this->_add_relation_to($venue_id_or_obj, 'Venue');
765
+	}
766
+
767
+
768
+	/**
769
+	 * Removes a venue from the event
770
+	 *
771
+	 * @param EE_Venue /int $venue_id_or_obj
772
+	 * @return EE_Base_Class|EE_Venue
773
+	 * @throws EE_Error
774
+	 * @throws ReflectionException
775
+	 */
776
+	public function remove_venue($venue_id_or_obj): EE_Venue
777
+	{
778
+		$venue_id_or_obj = ! empty($venue_id_or_obj) ? $venue_id_or_obj : $this->venue();
779
+		return $this->_remove_relation_to($venue_id_or_obj, 'Venue');
780
+	}
781
+
782
+
783
+	/**
784
+	 * Gets the venue related to the event. May provide additional $query_params if desired
785
+	 *
786
+	 * @param array $query_params
787
+	 * @return int
788
+	 * @throws EE_Error
789
+	 * @throws ReflectionException
790
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
791
+	 */
792
+	public function venue_ID(array $query_params = []): int
793
+	{
794
+		$venue = $this->get_first_related('Venue', $query_params);
795
+		return $venue instanceof EE_Venue ? $venue->ID() : 0;
796
+	}
797
+
798
+
799
+	/**
800
+	 * Gets the venue related to the event. May provide additional $query_params if desired
801
+	 *
802
+	 * @param array $query_params
803
+	 * @return EE_Base_Class|EE_Venue|null
804
+	 * @throws EE_Error
805
+	 * @throws ReflectionException
806
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
807
+	 */
808
+	public function venue(array $query_params = []): ?EE_Venue
809
+	{
810
+		return $this->get_first_related('Venue', $query_params);
811
+	}
812
+
813
+
814
+	/**
815
+	 * @param array $query_params
816
+	 * @return EE_Base_Class[]|EE_Venue[]
817
+	 * @throws EE_Error
818
+	 * @throws ReflectionException
819
+	 * @deprecated $VID:$
820
+	 */
821
+	public function venues(array $query_params = []): array
822
+	{
823
+		return [$this->venue($query_params)];
824
+	}
825
+
826
+
827
+	/**
828
+	 * check if event id is present and if event is published
829
+	 *
830
+	 * @return boolean true yes, false no
831
+	 * @throws EE_Error
832
+	 * @throws ReflectionException
833
+	 */
834
+	private function _has_ID_and_is_published(): bool
835
+	{
836
+		// first check if event id is present and not NULL,
837
+		// then check if this event is published (or any of the equivalent "published" statuses)
838
+		return
839
+			$this->ID() && $this->ID() !== null
840
+			&& (
841
+				$this->status() === 'publish'
842
+				|| $this->status() === EEM_Event::sold_out
843
+				|| $this->status() === EEM_Event::postponed
844
+				|| $this->status() === EEM_Event::cancelled
845
+			);
846
+	}
847
+
848
+
849
+	/**
850
+	 * This simply compares the internal dates with NOW and determines if the event is upcoming or not.
851
+	 *
852
+	 * @return boolean true yes, false no
853
+	 * @throws EE_Error
854
+	 * @throws ReflectionException
855
+	 */
856
+	public function is_upcoming(): bool
857
+	{
858
+		// check if event id is present and if this event is published
859
+		if ($this->is_inactive()) {
860
+			return false;
861
+		}
862
+		// set initial value
863
+		$upcoming = false;
864
+		// next let's get all datetimes and loop through them
865
+		$datetimes = $this->datetimes_in_chronological_order();
866
+		foreach ($datetimes as $datetime) {
867
+			if ($datetime instanceof EE_Datetime) {
868
+				// if this dtt is expired then we continue cause one of the other datetimes might be upcoming.
869
+				if ($datetime->is_expired()) {
870
+					continue;
871
+				}
872
+				// if this dtt is active then we return false.
873
+				if ($datetime->is_active()) {
874
+					return false;
875
+				}
876
+				// otherwise let's check upcoming status
877
+				$upcoming = $datetime->is_upcoming();
878
+			}
879
+		}
880
+		return $upcoming;
881
+	}
882
+
883
+
884
+	/**
885
+	 * @return bool
886
+	 * @throws EE_Error
887
+	 * @throws ReflectionException
888
+	 */
889
+	public function is_active(): bool
890
+	{
891
+		// check if event id is present and if this event is published
892
+		if ($this->is_inactive()) {
893
+			return false;
894
+		}
895
+		// set initial value
896
+		$active = false;
897
+		// next let's get all datetimes and loop through them
898
+		$datetimes = $this->datetimes_in_chronological_order();
899
+		foreach ($datetimes as $datetime) {
900
+			if ($datetime instanceof EE_Datetime) {
901
+				// if this dtt is expired then we continue cause one of the other datetimes might be active.
902
+				if ($datetime->is_expired()) {
903
+					continue;
904
+				}
905
+				// if this dtt is upcoming then we return false.
906
+				if ($datetime->is_upcoming()) {
907
+					return false;
908
+				}
909
+				// otherwise let's check active status
910
+				$active = $datetime->is_active();
911
+			}
912
+		}
913
+		return $active;
914
+	}
915
+
916
+
917
+	/**
918
+	 * @return bool
919
+	 * @throws EE_Error
920
+	 * @throws ReflectionException
921
+	 */
922
+	public function is_expired(): bool
923
+	{
924
+		// check if event id is present and if this event is published
925
+		if ($this->is_inactive()) {
926
+			return false;
927
+		}
928
+		// set initial value
929
+		$expired = false;
930
+		// first let's get all datetimes and loop through them
931
+		$datetimes = $this->datetimes_in_chronological_order();
932
+		foreach ($datetimes as $datetime) {
933
+			if ($datetime instanceof EE_Datetime) {
934
+				// if this dtt is upcoming or active then we return false.
935
+				if ($datetime->is_upcoming() || $datetime->is_active()) {
936
+					return false;
937
+				}
938
+				// otherwise let's check active status
939
+				$expired = $datetime->is_expired();
940
+			}
941
+		}
942
+		return $expired;
943
+	}
944
+
945
+
946
+	/**
947
+	 * @return bool
948
+	 * @throws EE_Error
949
+	 * @throws ReflectionException
950
+	 */
951
+	public function is_inactive(): bool
952
+	{
953
+		// check if event id is present and if this event is published
954
+		if ($this->_has_ID_and_is_published()) {
955
+			return false;
956
+		}
957
+		return true;
958
+	}
959
+
960
+
961
+	/**
962
+	 * calculate spaces remaining based on "saleable" tickets
963
+	 *
964
+	 * @param array|null $tickets
965
+	 * @param bool       $filtered
966
+	 * @return int|float
967
+	 * @throws EE_Error
968
+	 * @throws DomainException
969
+	 * @throws UnexpectedEntityException
970
+	 * @throws ReflectionException
971
+	 */
972
+	public function spaces_remaining(?array $tickets = [], ?bool $filtered = true)
973
+	{
974
+		$this->getAvailableSpacesCalculator()->setActiveTickets($tickets);
975
+		$spaces_remaining = $this->getAvailableSpacesCalculator()->spacesRemaining();
976
+		return $filtered
977
+			? apply_filters(
978
+				'FHEE_EE_Event__spaces_remaining',
979
+				$spaces_remaining,
980
+				$this,
981
+				$tickets
982
+			)
983
+			: $spaces_remaining;
984
+	}
985
+
986
+
987
+	/**
988
+	 *    perform_sold_out_status_check
989
+	 *    checks all of this event's datetime  reg_limit - sold values to determine if ANY datetimes have spaces
990
+	 *    available... if NOT, then the event status will get toggled to 'sold_out'
991
+	 *
992
+	 * @return bool    return the ACTUAL sold out state.
993
+	 * @throws EE_Error
994
+	 * @throws DomainException
995
+	 * @throws UnexpectedEntityException
996
+	 * @throws ReflectionException
997
+	 */
998
+	public function perform_sold_out_status_check(): bool
999
+	{
1000
+		// get all tickets
1001
+		$tickets     = $this->tickets(
1002
+			[
1003
+				'default_where_conditions' => 'none',
1004
+				'order_by'                 => ['TKT_qty' => 'ASC'],
1005
+			]
1006
+		);
1007
+		$all_expired = true;
1008
+		foreach ($tickets as $ticket) {
1009
+			if (! $ticket->is_expired()) {
1010
+				$all_expired = false;
1011
+				break;
1012
+			}
1013
+		}
1014
+		// if all the tickets are just expired, then don't update the event status to sold out
1015
+		if ($all_expired) {
1016
+			return true;
1017
+		}
1018
+		$spaces_remaining = $this->spaces_remaining($tickets);
1019
+		if ($spaces_remaining < 1) {
1020
+			if ($this->status() !== EEM_CPT_Base::post_status_private) {
1021
+				$this->set_status(EEM_Event::sold_out);
1022
+				$this->save();
1023
+			}
1024
+			$sold_out = true;
1025
+		} else {
1026
+			$sold_out = false;
1027
+			// was event previously marked as sold out ?
1028
+			if ($this->status() === EEM_Event::sold_out) {
1029
+				// revert status to previous value, if it was set
1030
+				$previous_event_status = $this->get_post_meta('_previous_event_status', true);
1031
+				if ($previous_event_status) {
1032
+					$this->set_status($previous_event_status);
1033
+					$this->save();
1034
+				}
1035
+			}
1036
+		}
1037
+		do_action('AHEE__EE_Event__perform_sold_out_status_check__end', $this, $sold_out, $spaces_remaining, $tickets);
1038
+		return $sold_out;
1039
+	}
1040
+
1041
+
1042
+	/**
1043
+	 * This returns the total remaining spaces for sale on this event.
1044
+	 *
1045
+	 * @return int|float
1046
+	 * @throws EE_Error
1047
+	 * @throws DomainException
1048
+	 * @throws UnexpectedEntityException
1049
+	 * @throws ReflectionException
1050
+	 * @uses EE_Event::total_available_spaces()
1051
+	 */
1052
+	public function spaces_remaining_for_sale()
1053
+	{
1054
+		return $this->total_available_spaces(true);
1055
+	}
1056
+
1057
+
1058
+	/**
1059
+	 * This returns the total spaces available for an event
1060
+	 * while considering all the quantities on the tickets and the reg limits
1061
+	 * on the datetimes attached to this event.
1062
+	 *
1063
+	 * @param bool $consider_sold   Whether to consider any tickets that have already sold in our calculation.
1064
+	 *                              If this is false, then we return the most tickets that could ever be sold
1065
+	 *                              for this event with the datetime and tickets setup on the event under optimal
1066
+	 *                              selling conditions.  Otherwise we return a live calculation of spaces available
1067
+	 *                              based on tickets sold.  Depending on setup and stage of sales, this
1068
+	 *                              may appear to equal remaining tickets.  However, the more tickets are
1069
+	 *                              sold out, the more accurate the "live" total is.
1070
+	 * @return int|float
1071
+	 * @throws EE_Error
1072
+	 * @throws DomainException
1073
+	 * @throws UnexpectedEntityException
1074
+	 * @throws ReflectionException
1075
+	 */
1076
+	public function total_available_spaces(bool $consider_sold = false)
1077
+	{
1078
+		$spaces_available = $consider_sold
1079
+			? $this->getAvailableSpacesCalculator()->spacesRemaining()
1080
+			: $this->getAvailableSpacesCalculator()->totalSpacesAvailable();
1081
+		return apply_filters(
1082
+			'FHEE_EE_Event__total_available_spaces__spaces_available',
1083
+			$spaces_available,
1084
+			$this,
1085
+			$this->getAvailableSpacesCalculator()->getDatetimes(),
1086
+			$this->getAvailableSpacesCalculator()->getActiveTickets()
1087
+		);
1088
+	}
1089
+
1090
+
1091
+	/**
1092
+	 * Checks if the event is set to sold out
1093
+	 *
1094
+	 * @param bool $actual  whether or not to perform calculations to not only figure the
1095
+	 *                      actual status but also to flip the status if necessary to sold
1096
+	 *                      out If false, we just check the existing status of the event
1097
+	 * @return boolean
1098
+	 * @throws EE_Error
1099
+	 * @throws ReflectionException
1100
+	 */
1101
+	public function is_sold_out(bool $actual = false): bool
1102
+	{
1103
+		if (! $actual) {
1104
+			return $this->status() === EEM_Event::sold_out;
1105
+		}
1106
+		return $this->perform_sold_out_status_check();
1107
+	}
1108
+
1109
+
1110
+	/**
1111
+	 * Checks if the event is marked as postponed
1112
+	 *
1113
+	 * @return boolean
1114
+	 */
1115
+	public function is_postponed(): bool
1116
+	{
1117
+		return $this->status() === EEM_Event::postponed;
1118
+	}
1119
+
1120
+
1121
+	/**
1122
+	 * Checks if the event is marked as cancelled
1123
+	 *
1124
+	 * @return boolean
1125
+	 */
1126
+	public function is_cancelled(): bool
1127
+	{
1128
+		return $this->status() === EEM_Event::cancelled;
1129
+	}
1130
+
1131
+
1132
+	/**
1133
+	 * Get the logical active status in a hierarchical order for all the datetimes.  Note
1134
+	 * Basically, we order the datetimes by EVT_start_date.  Then first test on whether the event is published.  If its
1135
+	 * NOT published then we test for whether its expired or not.  IF it IS published then we test first on whether an
1136
+	 * event has any active dates.  If no active dates then we check for any upcoming dates.  If no upcoming dates then
1137
+	 * the event is considered expired.
1138
+	 * NOTE: this method does NOT calculate whether the datetimes are sold out when event is published.  Sold Out is a
1139
+	 * status set on the EVENT when it is not published and thus is done
1140
+	 *
1141
+	 * @param bool $reset
1142
+	 * @return bool | string - based on EE_Datetime active constants or FALSE if error.
1143
+	 * @throws EE_Error
1144
+	 * @throws ReflectionException
1145
+	 */
1146
+	public function get_active_status(bool $reset = false)
1147
+	{
1148
+		// if the active status has already been set, then just use that value (unless we are resetting it)
1149
+		if (! empty($this->_active_status) && ! $reset) {
1150
+			return $this->_active_status;
1151
+		}
1152
+		// first check if event id is present on this object
1153
+		if (! $this->ID()) {
1154
+			return false;
1155
+		}
1156
+		$where_params_for_event = [['EVT_ID' => $this->ID()]];
1157
+		// if event is published:
1158
+		if (
1159
+			$this->status() === EEM_CPT_Base::post_status_publish
1160
+			|| $this->status() === EEM_CPT_Base::post_status_private
1161
+		) {
1162
+			// active?
1163
+			if (
1164
+				EEM_Datetime::instance()->get_datetime_count_for_status(
1165
+					EE_Datetime::active,
1166
+					$where_params_for_event
1167
+				) > 0
1168
+			) {
1169
+				$this->_active_status = EE_Datetime::active;
1170
+			} else {
1171
+				// upcoming?
1172
+				if (
1173
+					EEM_Datetime::instance()->get_datetime_count_for_status(
1174
+						EE_Datetime::upcoming,
1175
+						$where_params_for_event
1176
+					) > 0
1177
+				) {
1178
+					$this->_active_status = EE_Datetime::upcoming;
1179
+				} else {
1180
+					// expired?
1181
+					if (
1182
+						EEM_Datetime::instance()->get_datetime_count_for_status(
1183
+							EE_Datetime::expired,
1184
+							$where_params_for_event
1185
+						) > 0
1186
+					) {
1187
+						$this->_active_status = EE_Datetime::expired;
1188
+					} else {
1189
+						// it would be odd if things make it this far
1190
+						// because it basically means there are no datetimes attached to the event.
1191
+						// So in this case it will just be considered inactive.
1192
+						$this->_active_status = EE_Datetime::inactive;
1193
+					}
1194
+				}
1195
+			}
1196
+		} else {
1197
+			// the event is not published, so let's just set it's active status according to its' post status
1198
+			switch ($this->status()) {
1199
+				case EEM_Event::sold_out:
1200
+					$this->_active_status = EE_Datetime::sold_out;
1201
+					break;
1202
+				case EEM_Event::cancelled:
1203
+					$this->_active_status = EE_Datetime::cancelled;
1204
+					break;
1205
+				case EEM_Event::postponed:
1206
+					$this->_active_status = EE_Datetime::postponed;
1207
+					break;
1208
+				default:
1209
+					$this->_active_status = EE_Datetime::inactive;
1210
+			}
1211
+		}
1212
+		return $this->_active_status;
1213
+	}
1214
+
1215
+
1216
+	/**
1217
+	 *    pretty_active_status
1218
+	 *
1219
+	 * @param boolean $echo whether to return (FALSE), or echo out the result (TRUE)
1220
+	 * @return string
1221
+	 * @throws EE_Error
1222
+	 * @throws ReflectionException
1223
+	 */
1224
+	public function pretty_active_status(bool $echo = true): string
1225
+	{
1226
+		$active_status = $this->get_active_status();
1227
+		$status        = "
1228 1228
         <span class='ee-status ee-status-bg--$active_status event-active-status-$active_status'>
1229 1229
             " . EEH_Template::pretty_status($active_status, false, 'sentence') . "
1230 1230
         </span >";
1231
-        if ($echo) {
1232
-            echo wp_kses($status, AllowedTags::getAllowedTags());
1233
-            return '';
1234
-        }
1235
-        return $status;
1236
-    }
1237
-
1238
-
1239
-    /**
1240
-     * @return bool|int
1241
-     * @throws EE_Error
1242
-     * @throws ReflectionException
1243
-     */
1244
-    public function get_number_of_tickets_sold()
1245
-    {
1246
-        $tkt_sold = 0;
1247
-        if (! $this->ID()) {
1248
-            return 0;
1249
-        }
1250
-        $datetimes = $this->datetimes();
1251
-        foreach ($datetimes as $datetime) {
1252
-            if ($datetime instanceof EE_Datetime) {
1253
-                $tkt_sold += $datetime->sold();
1254
-            }
1255
-        }
1256
-        return $tkt_sold;
1257
-    }
1258
-
1259
-
1260
-    /**
1261
-     * This just returns a count of all the registrations for this event
1262
-     *
1263
-     * @return int
1264
-     * @throws EE_Error
1265
-     * @throws ReflectionException
1266
-     */
1267
-    public function get_count_of_all_registrations(): int
1268
-    {
1269
-        return EEM_Event::instance()->count_related($this, 'Registration');
1270
-    }
1271
-
1272
-
1273
-    /**
1274
-     * This returns the ticket with the earliest start time that is
1275
-     * available for this event (across all datetimes attached to the event)
1276
-     *
1277
-     * @return EE_Base_Class|EE_Ticket|null
1278
-     * @throws EE_Error
1279
-     * @throws ReflectionException
1280
-     */
1281
-    public function get_ticket_with_earliest_start_time()
1282
-    {
1283
-        $where['Datetime.EVT_ID'] = $this->ID();
1284
-        $query_params             = [$where, 'order_by' => ['TKT_start_date' => 'ASC']];
1285
-        return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1286
-    }
1287
-
1288
-
1289
-    /**
1290
-     * This returns the ticket with the latest end time that is available
1291
-     * for this event (across all datetimes attached to the event)
1292
-     *
1293
-     * @return EE_Base_Class|EE_Ticket|null
1294
-     * @throws EE_Error
1295
-     * @throws ReflectionException
1296
-     */
1297
-    public function get_ticket_with_latest_end_time()
1298
-    {
1299
-        $where['Datetime.EVT_ID'] = $this->ID();
1300
-        $query_params             = [$where, 'order_by' => ['TKT_end_date' => 'DESC']];
1301
-        return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1302
-    }
1303
-
1304
-
1305
-    /**
1306
-     * This returns the number of different ticket types currently on sale for this event.
1307
-     *
1308
-     * @return int
1309
-     * @throws EE_Error
1310
-     * @throws ReflectionException
1311
-     */
1312
-    public function countTicketsOnSale(): int
1313
-    {
1314
-        $where = [
1315
-            'Datetime.EVT_ID' => $this->ID(),
1316
-            'TKT_start_date'  => ['<', time()],
1317
-            'TKT_end_date'    => ['>', time()],
1318
-        ];
1319
-        return EEM_Ticket::instance()->count([$where]);
1320
-    }
1321
-
1322
-
1323
-    /**
1324
-     * This returns whether there are any tickets on sale for this event.
1325
-     *
1326
-     * @return bool true = YES tickets on sale.
1327
-     * @throws EE_Error
1328
-     * @throws ReflectionException
1329
-     */
1330
-    public function tickets_on_sale(): bool
1331
-    {
1332
-        return $this->countTicketsOnSale() > 0;
1333
-    }
1334
-
1335
-
1336
-    /**
1337
-     * Gets the URL for viewing this event on the front-end. Overrides parent
1338
-     * to check for an external URL first
1339
-     *
1340
-     * @return string
1341
-     * @throws EE_Error
1342
-     * @throws ReflectionException
1343
-     */
1344
-    public function get_permalink(): string
1345
-    {
1346
-        if ($this->external_url()) {
1347
-            return $this->external_url();
1348
-        }
1349
-        return parent::get_permalink();
1350
-    }
1351
-
1352
-
1353
-    /**
1354
-     * Gets the first term for 'espresso_event_categories' we can find
1355
-     *
1356
-     * @param array $query_params
1357
-     * @return EE_Base_Class|EE_Term|null
1358
-     * @throws EE_Error
1359
-     * @throws ReflectionException
1360
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1361
-     */
1362
-    public function first_event_category(array $query_params = []): ?EE_Term
1363
-    {
1364
-        $query_params[0]['Term_Taxonomy.taxonomy']     = 'espresso_event_categories';
1365
-        $query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1366
-        return EEM_Term::instance()->get_one($query_params);
1367
-    }
1368
-
1369
-
1370
-    /**
1371
-     * Gets all terms for 'espresso_event_categories' we can find
1372
-     *
1373
-     * @param array $query_params
1374
-     * @return EE_Base_Class[]|EE_Term[]
1375
-     * @throws EE_Error
1376
-     * @throws ReflectionException
1377
-     */
1378
-    public function get_all_event_categories(array $query_params = []): array
1379
-    {
1380
-        $query_params[0]['Term_Taxonomy.taxonomy']     = 'espresso_event_categories';
1381
-        $query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1382
-        return EEM_Term::instance()->get_all($query_params);
1383
-    }
1384
-
1385
-
1386
-    /**
1387
-     * Adds a question group to this event
1388
-     *
1389
-     * @param EE_Question_Group|int $question_group_id_or_obj
1390
-     * @param bool                  $for_primary if true, the question group will be added for the primary
1391
-     *                                           registrant, if false will be added for others. default: false
1392
-     * @return EE_Base_Class|EE_Question_Group
1393
-     * @throws EE_Error
1394
-     * @throws InvalidArgumentException
1395
-     * @throws InvalidDataTypeException
1396
-     * @throws InvalidInterfaceException
1397
-     * @throws ReflectionException
1398
-     */
1399
-    public function add_question_group($question_group_id_or_obj, bool $for_primary = false): EE_Question_Group
1400
-    {
1401
-        // If the row already exists, it will be updated. If it doesn't, it will be inserted.
1402
-        // That's in EE_HABTM_Relation::add_relation_to().
1403
-        return $this->_add_relation_to(
1404
-            $question_group_id_or_obj,
1405
-            'Question_Group',
1406
-            [
1407
-                EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary) => true,
1408
-            ]
1409
-        );
1410
-    }
1411
-
1412
-
1413
-    /**
1414
-     * Removes a question group from the event
1415
-     *
1416
-     * @param EE_Question_Group|int $question_group_id_or_obj
1417
-     * @param bool                  $for_primary if true, the question group will be removed from the primary
1418
-     *                                           registrant, if false will be removed from others. default: false
1419
-     * @return EE_Base_Class|EE_Question_Group|int
1420
-     * @throws EE_Error
1421
-     * @throws InvalidArgumentException
1422
-     * @throws ReflectionException
1423
-     * @throws InvalidDataTypeException
1424
-     * @throws InvalidInterfaceException
1425
-     */
1426
-    public function remove_question_group($question_group_id_or_obj, bool $for_primary = false)
1427
-    {
1428
-        // If the question group is used for the other type (primary or additional)
1429
-        // then just update it. If not, delete it outright.
1430
-        $existing_relation = $this->get_first_related(
1431
-            'Event_Question_Group',
1432
-            [
1433
-                [
1434
-                    'QSG_ID' => EEM_Question_Group::instance()->ensure_is_ID($question_group_id_or_obj),
1435
-                ],
1436
-            ]
1437
-        );
1438
-        $field_to_update   = EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary);
1439
-        $other_field       = EEM_Event_Question_Group::instance()->fieldNameForContext(! $for_primary);
1440
-        if ($existing_relation->get($other_field) === false) {
1441
-            // Delete it. It's now no longer for primary or additional question groups.
1442
-            return $this->_remove_relation_to($question_group_id_or_obj, 'Question_Group');
1443
-        }
1444
-        // Just update it. They'll still use this question group for the other category
1445
-        $existing_relation->save(
1446
-            [
1447
-                $field_to_update => false,
1448
-            ]
1449
-        );
1450
-        return $question_group_id_or_obj;
1451
-    }
1452
-
1453
-
1454
-    /**
1455
-     * Gets all the question groups, ordering them by QSG_order ascending
1456
-     *
1457
-     * @param array $query_params
1458
-     * @return EE_Base_Class[]|EE_Question_Group[]
1459
-     * @throws EE_Error
1460
-     * @throws ReflectionException
1461
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1462
-     */
1463
-    public function question_groups(array $query_params = []): array
1464
-    {
1465
-        $query_params = ! empty($query_params) ? $query_params : ['order_by' => ['QSG_order' => 'ASC']];
1466
-        return $this->get_many_related('Question_Group', $query_params);
1467
-    }
1468
-
1469
-
1470
-    /**
1471
-     * Implementation for EEI_Has_Icon interface method.
1472
-     *
1473
-     * @return string
1474
-     * @see EEI_Visual_Representation for comments
1475
-     */
1476
-    public function get_icon(): string
1477
-    {
1478
-        return '<span class="dashicons dashicons-flag"></span>';
1479
-    }
1480
-
1481
-
1482
-    /**
1483
-     * Implementation for EEI_Admin_Links interface method.
1484
-     *
1485
-     * @return string
1486
-     * @throws EE_Error
1487
-     * @throws ReflectionException
1488
-     * @see EEI_Admin_Links for comments
1489
-     */
1490
-    public function get_admin_details_link(): string
1491
-    {
1492
-        return $this->get_admin_edit_link();
1493
-    }
1494
-
1495
-
1496
-    /**
1497
-     * Implementation for EEI_Admin_Links interface method.
1498
-     *
1499
-     * @return string
1500
-     * @throws EE_Error
1501
-     * @throws ReflectionException
1502
-     * @see EEI_Admin_Links for comments
1503
-     */
1504
-    public function get_admin_edit_link(): string
1505
-    {
1506
-        return EEH_URL::add_query_args_and_nonce(
1507
-            [
1508
-                'page'   => 'espresso_events',
1509
-                'action' => 'edit',
1510
-                'post'   => $this->ID(),
1511
-            ],
1512
-            admin_url('admin.php')
1513
-        );
1514
-    }
1515
-
1516
-
1517
-    /**
1518
-     * Implementation for EEI_Admin_Links interface method.
1519
-     *
1520
-     * @return string
1521
-     * @see EEI_Admin_Links for comments
1522
-     */
1523
-    public function get_admin_settings_link(): string
1524
-    {
1525
-        return EEH_URL::add_query_args_and_nonce(
1526
-            [
1527
-                'page'   => 'espresso_events',
1528
-                'action' => 'default_event_settings',
1529
-            ],
1530
-            admin_url('admin.php')
1531
-        );
1532
-    }
1533
-
1534
-
1535
-    /**
1536
-     * Implementation for EEI_Admin_Links interface method.
1537
-     *
1538
-     * @return string
1539
-     * @see EEI_Admin_Links for comments
1540
-     */
1541
-    public function get_admin_overview_link(): string
1542
-    {
1543
-        return EEH_URL::add_query_args_and_nonce(
1544
-            [
1545
-                'page'   => 'espresso_events',
1546
-                'action' => 'default',
1547
-            ],
1548
-            admin_url('admin.php')
1549
-        );
1550
-    }
1551
-
1552
-
1553
-    /**
1554
-     * @return string|null
1555
-     * @throws EE_Error
1556
-     * @throws ReflectionException
1557
-     */
1558
-    public function registrationFormUuid(): ?string
1559
-    {
1560
-        return $this->get('FSC_UUID') ?? '';
1561
-    }
1562
-
1563
-
1564
-    /**
1565
-     * Gets all the form sections for this event
1566
-     *
1567
-     * @return EE_Base_Class[]|EE_Form_Section[]
1568
-     * @throws EE_Error
1569
-     * @throws ReflectionException
1570
-     */
1571
-    public function registrationForm(): array
1572
-    {
1573
-        $FSC_UUID = $this->registrationFormUuid();
1574
-
1575
-        if (empty($FSC_UUID)) {
1576
-            return [];
1577
-        }
1578
-
1579
-        return EEM_Form_Section::instance()->get_all(
1580
-            [
1581
-                [
1582
-                    'OR' => [
1583
-                        'FSC_UUID'      => $FSC_UUID, // top level form
1584
-                        'FSC_belongsTo' => $FSC_UUID, // child form sections
1585
-                    ],
1586
-                ],
1587
-                'order_by' => ['FSC_order' => 'ASC'],
1588
-            ]
1589
-        );
1590
-    }
1591
-
1592
-
1593
-    /**
1594
-     * @param string $UUID
1595
-     * @throws EE_Error
1596
-     * @throws ReflectionException
1597
-     */
1598
-    public function setRegistrationFormUuid(string $UUID): void
1599
-    {
1600
-        if (! Cuid::isCuid($UUID)) {
1601
-            throw new InvalidArgumentException(
1602
-                sprintf(
1603
-                /* translators: 1: UUID value, 2: UUID generator function. */
1604
-                    esc_html__(
1605
-                        'The supplied UUID "%1$s" is invalid or missing. Please use %2$s to generate a valid one.',
1606
-                        'event_espresso'
1607
-                    ),
1608
-                    $UUID,
1609
-                    '`Cuid::cuid()`'
1610
-                )
1611
-            );
1612
-        }
1613
-        $this->set('FSC_UUID', $UUID);
1614
-    }
1231
+		if ($echo) {
1232
+			echo wp_kses($status, AllowedTags::getAllowedTags());
1233
+			return '';
1234
+		}
1235
+		return $status;
1236
+	}
1237
+
1238
+
1239
+	/**
1240
+	 * @return bool|int
1241
+	 * @throws EE_Error
1242
+	 * @throws ReflectionException
1243
+	 */
1244
+	public function get_number_of_tickets_sold()
1245
+	{
1246
+		$tkt_sold = 0;
1247
+		if (! $this->ID()) {
1248
+			return 0;
1249
+		}
1250
+		$datetimes = $this->datetimes();
1251
+		foreach ($datetimes as $datetime) {
1252
+			if ($datetime instanceof EE_Datetime) {
1253
+				$tkt_sold += $datetime->sold();
1254
+			}
1255
+		}
1256
+		return $tkt_sold;
1257
+	}
1258
+
1259
+
1260
+	/**
1261
+	 * This just returns a count of all the registrations for this event
1262
+	 *
1263
+	 * @return int
1264
+	 * @throws EE_Error
1265
+	 * @throws ReflectionException
1266
+	 */
1267
+	public function get_count_of_all_registrations(): int
1268
+	{
1269
+		return EEM_Event::instance()->count_related($this, 'Registration');
1270
+	}
1271
+
1272
+
1273
+	/**
1274
+	 * This returns the ticket with the earliest start time that is
1275
+	 * available for this event (across all datetimes attached to the event)
1276
+	 *
1277
+	 * @return EE_Base_Class|EE_Ticket|null
1278
+	 * @throws EE_Error
1279
+	 * @throws ReflectionException
1280
+	 */
1281
+	public function get_ticket_with_earliest_start_time()
1282
+	{
1283
+		$where['Datetime.EVT_ID'] = $this->ID();
1284
+		$query_params             = [$where, 'order_by' => ['TKT_start_date' => 'ASC']];
1285
+		return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1286
+	}
1287
+
1288
+
1289
+	/**
1290
+	 * This returns the ticket with the latest end time that is available
1291
+	 * for this event (across all datetimes attached to the event)
1292
+	 *
1293
+	 * @return EE_Base_Class|EE_Ticket|null
1294
+	 * @throws EE_Error
1295
+	 * @throws ReflectionException
1296
+	 */
1297
+	public function get_ticket_with_latest_end_time()
1298
+	{
1299
+		$where['Datetime.EVT_ID'] = $this->ID();
1300
+		$query_params             = [$where, 'order_by' => ['TKT_end_date' => 'DESC']];
1301
+		return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1302
+	}
1303
+
1304
+
1305
+	/**
1306
+	 * This returns the number of different ticket types currently on sale for this event.
1307
+	 *
1308
+	 * @return int
1309
+	 * @throws EE_Error
1310
+	 * @throws ReflectionException
1311
+	 */
1312
+	public function countTicketsOnSale(): int
1313
+	{
1314
+		$where = [
1315
+			'Datetime.EVT_ID' => $this->ID(),
1316
+			'TKT_start_date'  => ['<', time()],
1317
+			'TKT_end_date'    => ['>', time()],
1318
+		];
1319
+		return EEM_Ticket::instance()->count([$where]);
1320
+	}
1321
+
1322
+
1323
+	/**
1324
+	 * This returns whether there are any tickets on sale for this event.
1325
+	 *
1326
+	 * @return bool true = YES tickets on sale.
1327
+	 * @throws EE_Error
1328
+	 * @throws ReflectionException
1329
+	 */
1330
+	public function tickets_on_sale(): bool
1331
+	{
1332
+		return $this->countTicketsOnSale() > 0;
1333
+	}
1334
+
1335
+
1336
+	/**
1337
+	 * Gets the URL for viewing this event on the front-end. Overrides parent
1338
+	 * to check for an external URL first
1339
+	 *
1340
+	 * @return string
1341
+	 * @throws EE_Error
1342
+	 * @throws ReflectionException
1343
+	 */
1344
+	public function get_permalink(): string
1345
+	{
1346
+		if ($this->external_url()) {
1347
+			return $this->external_url();
1348
+		}
1349
+		return parent::get_permalink();
1350
+	}
1351
+
1352
+
1353
+	/**
1354
+	 * Gets the first term for 'espresso_event_categories' we can find
1355
+	 *
1356
+	 * @param array $query_params
1357
+	 * @return EE_Base_Class|EE_Term|null
1358
+	 * @throws EE_Error
1359
+	 * @throws ReflectionException
1360
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1361
+	 */
1362
+	public function first_event_category(array $query_params = []): ?EE_Term
1363
+	{
1364
+		$query_params[0]['Term_Taxonomy.taxonomy']     = 'espresso_event_categories';
1365
+		$query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1366
+		return EEM_Term::instance()->get_one($query_params);
1367
+	}
1368
+
1369
+
1370
+	/**
1371
+	 * Gets all terms for 'espresso_event_categories' we can find
1372
+	 *
1373
+	 * @param array $query_params
1374
+	 * @return EE_Base_Class[]|EE_Term[]
1375
+	 * @throws EE_Error
1376
+	 * @throws ReflectionException
1377
+	 */
1378
+	public function get_all_event_categories(array $query_params = []): array
1379
+	{
1380
+		$query_params[0]['Term_Taxonomy.taxonomy']     = 'espresso_event_categories';
1381
+		$query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1382
+		return EEM_Term::instance()->get_all($query_params);
1383
+	}
1384
+
1385
+
1386
+	/**
1387
+	 * Adds a question group to this event
1388
+	 *
1389
+	 * @param EE_Question_Group|int $question_group_id_or_obj
1390
+	 * @param bool                  $for_primary if true, the question group will be added for the primary
1391
+	 *                                           registrant, if false will be added for others. default: false
1392
+	 * @return EE_Base_Class|EE_Question_Group
1393
+	 * @throws EE_Error
1394
+	 * @throws InvalidArgumentException
1395
+	 * @throws InvalidDataTypeException
1396
+	 * @throws InvalidInterfaceException
1397
+	 * @throws ReflectionException
1398
+	 */
1399
+	public function add_question_group($question_group_id_or_obj, bool $for_primary = false): EE_Question_Group
1400
+	{
1401
+		// If the row already exists, it will be updated. If it doesn't, it will be inserted.
1402
+		// That's in EE_HABTM_Relation::add_relation_to().
1403
+		return $this->_add_relation_to(
1404
+			$question_group_id_or_obj,
1405
+			'Question_Group',
1406
+			[
1407
+				EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary) => true,
1408
+			]
1409
+		);
1410
+	}
1411
+
1412
+
1413
+	/**
1414
+	 * Removes a question group from the event
1415
+	 *
1416
+	 * @param EE_Question_Group|int $question_group_id_or_obj
1417
+	 * @param bool                  $for_primary if true, the question group will be removed from the primary
1418
+	 *                                           registrant, if false will be removed from others. default: false
1419
+	 * @return EE_Base_Class|EE_Question_Group|int
1420
+	 * @throws EE_Error
1421
+	 * @throws InvalidArgumentException
1422
+	 * @throws ReflectionException
1423
+	 * @throws InvalidDataTypeException
1424
+	 * @throws InvalidInterfaceException
1425
+	 */
1426
+	public function remove_question_group($question_group_id_or_obj, bool $for_primary = false)
1427
+	{
1428
+		// If the question group is used for the other type (primary or additional)
1429
+		// then just update it. If not, delete it outright.
1430
+		$existing_relation = $this->get_first_related(
1431
+			'Event_Question_Group',
1432
+			[
1433
+				[
1434
+					'QSG_ID' => EEM_Question_Group::instance()->ensure_is_ID($question_group_id_or_obj),
1435
+				],
1436
+			]
1437
+		);
1438
+		$field_to_update   = EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary);
1439
+		$other_field       = EEM_Event_Question_Group::instance()->fieldNameForContext(! $for_primary);
1440
+		if ($existing_relation->get($other_field) === false) {
1441
+			// Delete it. It's now no longer for primary or additional question groups.
1442
+			return $this->_remove_relation_to($question_group_id_or_obj, 'Question_Group');
1443
+		}
1444
+		// Just update it. They'll still use this question group for the other category
1445
+		$existing_relation->save(
1446
+			[
1447
+				$field_to_update => false,
1448
+			]
1449
+		);
1450
+		return $question_group_id_or_obj;
1451
+	}
1452
+
1453
+
1454
+	/**
1455
+	 * Gets all the question groups, ordering them by QSG_order ascending
1456
+	 *
1457
+	 * @param array $query_params
1458
+	 * @return EE_Base_Class[]|EE_Question_Group[]
1459
+	 * @throws EE_Error
1460
+	 * @throws ReflectionException
1461
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1462
+	 */
1463
+	public function question_groups(array $query_params = []): array
1464
+	{
1465
+		$query_params = ! empty($query_params) ? $query_params : ['order_by' => ['QSG_order' => 'ASC']];
1466
+		return $this->get_many_related('Question_Group', $query_params);
1467
+	}
1468
+
1469
+
1470
+	/**
1471
+	 * Implementation for EEI_Has_Icon interface method.
1472
+	 *
1473
+	 * @return string
1474
+	 * @see EEI_Visual_Representation for comments
1475
+	 */
1476
+	public function get_icon(): string
1477
+	{
1478
+		return '<span class="dashicons dashicons-flag"></span>';
1479
+	}
1480
+
1481
+
1482
+	/**
1483
+	 * Implementation for EEI_Admin_Links interface method.
1484
+	 *
1485
+	 * @return string
1486
+	 * @throws EE_Error
1487
+	 * @throws ReflectionException
1488
+	 * @see EEI_Admin_Links for comments
1489
+	 */
1490
+	public function get_admin_details_link(): string
1491
+	{
1492
+		return $this->get_admin_edit_link();
1493
+	}
1494
+
1495
+
1496
+	/**
1497
+	 * Implementation for EEI_Admin_Links interface method.
1498
+	 *
1499
+	 * @return string
1500
+	 * @throws EE_Error
1501
+	 * @throws ReflectionException
1502
+	 * @see EEI_Admin_Links for comments
1503
+	 */
1504
+	public function get_admin_edit_link(): string
1505
+	{
1506
+		return EEH_URL::add_query_args_and_nonce(
1507
+			[
1508
+				'page'   => 'espresso_events',
1509
+				'action' => 'edit',
1510
+				'post'   => $this->ID(),
1511
+			],
1512
+			admin_url('admin.php')
1513
+		);
1514
+	}
1515
+
1516
+
1517
+	/**
1518
+	 * Implementation for EEI_Admin_Links interface method.
1519
+	 *
1520
+	 * @return string
1521
+	 * @see EEI_Admin_Links for comments
1522
+	 */
1523
+	public function get_admin_settings_link(): string
1524
+	{
1525
+		return EEH_URL::add_query_args_and_nonce(
1526
+			[
1527
+				'page'   => 'espresso_events',
1528
+				'action' => 'default_event_settings',
1529
+			],
1530
+			admin_url('admin.php')
1531
+		);
1532
+	}
1533
+
1534
+
1535
+	/**
1536
+	 * Implementation for EEI_Admin_Links interface method.
1537
+	 *
1538
+	 * @return string
1539
+	 * @see EEI_Admin_Links for comments
1540
+	 */
1541
+	public function get_admin_overview_link(): string
1542
+	{
1543
+		return EEH_URL::add_query_args_and_nonce(
1544
+			[
1545
+				'page'   => 'espresso_events',
1546
+				'action' => 'default',
1547
+			],
1548
+			admin_url('admin.php')
1549
+		);
1550
+	}
1551
+
1552
+
1553
+	/**
1554
+	 * @return string|null
1555
+	 * @throws EE_Error
1556
+	 * @throws ReflectionException
1557
+	 */
1558
+	public function registrationFormUuid(): ?string
1559
+	{
1560
+		return $this->get('FSC_UUID') ?? '';
1561
+	}
1562
+
1563
+
1564
+	/**
1565
+	 * Gets all the form sections for this event
1566
+	 *
1567
+	 * @return EE_Base_Class[]|EE_Form_Section[]
1568
+	 * @throws EE_Error
1569
+	 * @throws ReflectionException
1570
+	 */
1571
+	public function registrationForm(): array
1572
+	{
1573
+		$FSC_UUID = $this->registrationFormUuid();
1574
+
1575
+		if (empty($FSC_UUID)) {
1576
+			return [];
1577
+		}
1578
+
1579
+		return EEM_Form_Section::instance()->get_all(
1580
+			[
1581
+				[
1582
+					'OR' => [
1583
+						'FSC_UUID'      => $FSC_UUID, // top level form
1584
+						'FSC_belongsTo' => $FSC_UUID, // child form sections
1585
+					],
1586
+				],
1587
+				'order_by' => ['FSC_order' => 'ASC'],
1588
+			]
1589
+		);
1590
+	}
1591
+
1592
+
1593
+	/**
1594
+	 * @param string $UUID
1595
+	 * @throws EE_Error
1596
+	 * @throws ReflectionException
1597
+	 */
1598
+	public function setRegistrationFormUuid(string $UUID): void
1599
+	{
1600
+		if (! Cuid::isCuid($UUID)) {
1601
+			throw new InvalidArgumentException(
1602
+				sprintf(
1603
+				/* translators: 1: UUID value, 2: UUID generator function. */
1604
+					esc_html__(
1605
+						'The supplied UUID "%1$s" is invalid or missing. Please use %2$s to generate a valid one.',
1606
+						'event_espresso'
1607
+					),
1608
+					$UUID,
1609
+					'`Cuid::cuid()`'
1610
+				)
1611
+			);
1612
+		}
1613
+		$this->set('FSC_UUID', $UUID);
1614
+	}
1615 1615
 }
Please login to merge, or discard this patch.
modules/messages/EED_Messages.module.php 1 patch
Indentation   +1340 added lines, -1340 removed lines patch added patch discarded remove patch
@@ -15,1353 +15,1353 @@
 block discarded – undo
15 15
  */
16 16
 class EED_Messages extends EED_Module
17 17
 {
18
-    /**
19
-     * This holds the EE_messages controller
20
-     *
21
-     * @deprecated 4.9.0
22
-     * @var EE_messages $_EEMSG
23
-     */
24
-    protected static $_EEMSG;
25
-
26
-    /**
27
-     * @type EE_Message_Resource_Manager $_message_resource_manager
28
-     */
29
-    protected static $_message_resource_manager;
30
-
31
-    /**
32
-     * This holds the EE_Messages_Processor business class.
33
-     *
34
-     * @type EE_Messages_Processor
35
-     */
36
-    protected static $_MSG_PROCESSOR;
37
-
38
-    /**
39
-     * holds all the paths for various messages components.
40
-     * Utilized by autoloader registry
41
-     *
42
-     * @var array
43
-     */
44
-    protected static $_MSG_PATHS;
45
-
46
-
47
-    /**
48
-     * This will hold an array of messages template packs that are registered in the messages system.
49
-     * Format is:
50
-     * array(
51
-     *    'template_pack_dbref' => EE_Messages_Template_Pack (instance)
52
-     * )
53
-     *
54
-     * @var EE_Messages_Template_Pack[]
55
-     */
56
-    protected static $_TMP_PACKS = [];
57
-
58
-
59
-    /**
60
-     * @return EED_Messages|EED_Module
61
-     * @throws EE_Error
62
-     * @throws ReflectionException
63
-     */
64
-    public static function instance()
65
-    {
66
-        return parent::get_instance(__CLASS__);
67
-    }
68
-
69
-
70
-    /**
71
-     *  set_hooks - for hooking into EE Core, other modules, etc
72
-     *
73
-     * @return    void
74
-     * @since 4.5.0
75
-     */
76
-    public static function set_hooks()
77
-    {
78
-        // actions
79
-        add_action('AHEE__EE_Payment_Processor__update_txn_based_on_payment', ['EED_Messages', 'payment'], 10, 2);
80
-        add_action(
81
-            'AHEE__EE_Registration_Processor__trigger_registration_update_notifications',
82
-            ['EED_Messages', 'maybe_registration'],
83
-            10,
84
-            2
85
-        );
86
-        // filters
87
-        add_filter(
88
-            'FHEE__EE_Registration__receipt_url__receipt_url',
89
-            ['EED_Messages', 'registration_message_trigger_url'],
90
-            10,
91
-            4
92
-        );
93
-        add_filter(
94
-            'FHEE__EE_Registration__invoice_url__invoice_url',
95
-            ['EED_Messages', 'registration_message_trigger_url'],
96
-            10,
97
-            4
98
-        );
99
-        // register routes
100
-        self::_register_routes();
101
-    }
102
-
103
-
104
-    /**
105
-     *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
106
-     *
107
-     * @access    public
108
-     * @return    void
109
-     */
110
-    public static function set_hooks_admin()
111
-    {
112
-        // actions
113
-        add_action('AHEE__EE_Payment_Processor__update_txn_based_on_payment', ['EED_Messages', 'payment'], 10, 2);
114
-        add_action(
115
-            'AHEE__Transactions_Admin_Page___send_payment_reminder__process_admin_payment_reminder',
116
-            ['EED_Messages', 'payment_reminder'],
117
-            10
118
-        );
119
-        add_action(
120
-            'AHEE__EE_Registration_Processor__trigger_registration_update_notifications',
121
-            ['EED_Messages', 'maybe_registration'],
122
-            10,
123
-            3
124
-        );
125
-        add_action(
126
-            'AHEE__Extend_Registrations_Admin_Page___newsletter_selected_send__with_registrations',
127
-            ['EED_Messages', 'send_newsletter_message'],
128
-            10,
129
-            2
130
-        );
131
-        add_action(
132
-            'AHEE__EES_Espresso_Cancelled__process_shortcode__transaction',
133
-            ['EED_Messages', 'cancelled_registration'],
134
-            10
135
-        );
136
-        add_action(
137
-            'AHEE__EE_Admin_Page___process_admin_payment_notification',
138
-            ['EED_Messages', 'process_admin_payment'],
139
-            10,
140
-            1
141
-        );
142
-        // filters
143
-        add_filter(
144
-            'FHEE__EE_Admin_Page___process_resend_registration__success',
145
-            ['EED_Messages', 'process_resend'],
146
-            10,
147
-            2
148
-        );
149
-        add_filter(
150
-            'FHEE__EE_Registration__receipt_url__receipt_url',
151
-            ['EED_Messages', 'registration_message_trigger_url'],
152
-            10,
153
-            4
154
-        );
155
-        add_filter(
156
-            'FHEE__EE_Registration__invoice_url__invoice_url',
157
-            ['EED_Messages', 'registration_message_trigger_url'],
158
-            10,
159
-            4
160
-        );
161
-    }
162
-
163
-
164
-    /**
165
-     * All the message triggers done by route go in here.
166
-     *
167
-     * @return void
168
-     * @since 4.5.0
169
-     */
170
-    protected static function _register_routes()
171
-    {
172
-        EE_Config::register_route('msg_url_trigger', 'Messages', 'run');
173
-        EE_Config::register_route('msg_cron_trigger', 'Messages', 'execute_batch_request');
174
-        EE_Config::register_route('msg_browser_trigger', 'Messages', 'browser_trigger');
175
-        EE_Config::register_route('msg_browser_error_trigger', 'Messages', 'browser_error_trigger');
176
-        do_action('AHEE__EED_Messages___register_routes');
177
-    }
178
-
179
-
180
-    /**
181
-     * This is called when a browser display trigger is executed.
182
-     * The browser display trigger is typically used when a already generated message is displayed directly in the
183
-     * browser.
184
-     *
185
-     * @param WP $WP
186
-     * @throws EE_Error
187
-     * @throws InvalidArgumentException
188
-     * @throws ReflectionException
189
-     * @throws InvalidDataTypeException
190
-     * @throws InvalidInterfaceException
191
-     * @since 4.9.0
192
-     */
193
-    public function browser_trigger($WP)
194
-    {
195
-        // ensure controller is loaded
196
-        self::_load_controller();
197
-        $token = self::getRequest()->getRequestParam('token');
198
-        try {
199
-            $mtg = new EE_Message_Generated_From_Token($token, 'html', self::$_message_resource_manager);
200
-            self::$_MSG_PROCESSOR->generate_and_send_now($mtg);
201
-        } catch (EE_Error $e) {
202
-            $error_msg = esc_html__(
203
-                'Please note that a system message failed to send due to a technical issue.',
204
-                'event_espresso'
205
-            );
206
-            // add specific message for developers if WP_DEBUG in on
207
-            $error_msg .= '||' . $e->getMessage();
208
-            EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
209
-        }
210
-    }
211
-
212
-
213
-    /**
214
-     * This is called when a browser error trigger is executed.
215
-     * When triggered this will grab the EE_Message matching the token in the request and use that to get the error
216
-     * message and display it.
217
-     *
218
-     * @param $WP
219
-     * @throws EE_Error
220
-     * @throws InvalidArgumentException
221
-     * @throws InvalidDataTypeException
222
-     * @throws InvalidInterfaceException
223
-     * @since 4.9.0
224
-     */
225
-    public function browser_error_trigger($WP)
226
-    {
227
-        $token = self::getRequest()->getRequestParam('token');
228
-        if ($token) {
229
-            $message = EEM_Message::instance()->get_one_by_token($token);
230
-            if ($message instanceof EE_Message) {
231
-                header('HTTP/1.1 200 OK');
232
-                $error_msg = nl2br($message->error_message());
233
-                ?>
18
+	/**
19
+	 * This holds the EE_messages controller
20
+	 *
21
+	 * @deprecated 4.9.0
22
+	 * @var EE_messages $_EEMSG
23
+	 */
24
+	protected static $_EEMSG;
25
+
26
+	/**
27
+	 * @type EE_Message_Resource_Manager $_message_resource_manager
28
+	 */
29
+	protected static $_message_resource_manager;
30
+
31
+	/**
32
+	 * This holds the EE_Messages_Processor business class.
33
+	 *
34
+	 * @type EE_Messages_Processor
35
+	 */
36
+	protected static $_MSG_PROCESSOR;
37
+
38
+	/**
39
+	 * holds all the paths for various messages components.
40
+	 * Utilized by autoloader registry
41
+	 *
42
+	 * @var array
43
+	 */
44
+	protected static $_MSG_PATHS;
45
+
46
+
47
+	/**
48
+	 * This will hold an array of messages template packs that are registered in the messages system.
49
+	 * Format is:
50
+	 * array(
51
+	 *    'template_pack_dbref' => EE_Messages_Template_Pack (instance)
52
+	 * )
53
+	 *
54
+	 * @var EE_Messages_Template_Pack[]
55
+	 */
56
+	protected static $_TMP_PACKS = [];
57
+
58
+
59
+	/**
60
+	 * @return EED_Messages|EED_Module
61
+	 * @throws EE_Error
62
+	 * @throws ReflectionException
63
+	 */
64
+	public static function instance()
65
+	{
66
+		return parent::get_instance(__CLASS__);
67
+	}
68
+
69
+
70
+	/**
71
+	 *  set_hooks - for hooking into EE Core, other modules, etc
72
+	 *
73
+	 * @return    void
74
+	 * @since 4.5.0
75
+	 */
76
+	public static function set_hooks()
77
+	{
78
+		// actions
79
+		add_action('AHEE__EE_Payment_Processor__update_txn_based_on_payment', ['EED_Messages', 'payment'], 10, 2);
80
+		add_action(
81
+			'AHEE__EE_Registration_Processor__trigger_registration_update_notifications',
82
+			['EED_Messages', 'maybe_registration'],
83
+			10,
84
+			2
85
+		);
86
+		// filters
87
+		add_filter(
88
+			'FHEE__EE_Registration__receipt_url__receipt_url',
89
+			['EED_Messages', 'registration_message_trigger_url'],
90
+			10,
91
+			4
92
+		);
93
+		add_filter(
94
+			'FHEE__EE_Registration__invoice_url__invoice_url',
95
+			['EED_Messages', 'registration_message_trigger_url'],
96
+			10,
97
+			4
98
+		);
99
+		// register routes
100
+		self::_register_routes();
101
+	}
102
+
103
+
104
+	/**
105
+	 *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
106
+	 *
107
+	 * @access    public
108
+	 * @return    void
109
+	 */
110
+	public static function set_hooks_admin()
111
+	{
112
+		// actions
113
+		add_action('AHEE__EE_Payment_Processor__update_txn_based_on_payment', ['EED_Messages', 'payment'], 10, 2);
114
+		add_action(
115
+			'AHEE__Transactions_Admin_Page___send_payment_reminder__process_admin_payment_reminder',
116
+			['EED_Messages', 'payment_reminder'],
117
+			10
118
+		);
119
+		add_action(
120
+			'AHEE__EE_Registration_Processor__trigger_registration_update_notifications',
121
+			['EED_Messages', 'maybe_registration'],
122
+			10,
123
+			3
124
+		);
125
+		add_action(
126
+			'AHEE__Extend_Registrations_Admin_Page___newsletter_selected_send__with_registrations',
127
+			['EED_Messages', 'send_newsletter_message'],
128
+			10,
129
+			2
130
+		);
131
+		add_action(
132
+			'AHEE__EES_Espresso_Cancelled__process_shortcode__transaction',
133
+			['EED_Messages', 'cancelled_registration'],
134
+			10
135
+		);
136
+		add_action(
137
+			'AHEE__EE_Admin_Page___process_admin_payment_notification',
138
+			['EED_Messages', 'process_admin_payment'],
139
+			10,
140
+			1
141
+		);
142
+		// filters
143
+		add_filter(
144
+			'FHEE__EE_Admin_Page___process_resend_registration__success',
145
+			['EED_Messages', 'process_resend'],
146
+			10,
147
+			2
148
+		);
149
+		add_filter(
150
+			'FHEE__EE_Registration__receipt_url__receipt_url',
151
+			['EED_Messages', 'registration_message_trigger_url'],
152
+			10,
153
+			4
154
+		);
155
+		add_filter(
156
+			'FHEE__EE_Registration__invoice_url__invoice_url',
157
+			['EED_Messages', 'registration_message_trigger_url'],
158
+			10,
159
+			4
160
+		);
161
+	}
162
+
163
+
164
+	/**
165
+	 * All the message triggers done by route go in here.
166
+	 *
167
+	 * @return void
168
+	 * @since 4.5.0
169
+	 */
170
+	protected static function _register_routes()
171
+	{
172
+		EE_Config::register_route('msg_url_trigger', 'Messages', 'run');
173
+		EE_Config::register_route('msg_cron_trigger', 'Messages', 'execute_batch_request');
174
+		EE_Config::register_route('msg_browser_trigger', 'Messages', 'browser_trigger');
175
+		EE_Config::register_route('msg_browser_error_trigger', 'Messages', 'browser_error_trigger');
176
+		do_action('AHEE__EED_Messages___register_routes');
177
+	}
178
+
179
+
180
+	/**
181
+	 * This is called when a browser display trigger is executed.
182
+	 * The browser display trigger is typically used when a already generated message is displayed directly in the
183
+	 * browser.
184
+	 *
185
+	 * @param WP $WP
186
+	 * @throws EE_Error
187
+	 * @throws InvalidArgumentException
188
+	 * @throws ReflectionException
189
+	 * @throws InvalidDataTypeException
190
+	 * @throws InvalidInterfaceException
191
+	 * @since 4.9.0
192
+	 */
193
+	public function browser_trigger($WP)
194
+	{
195
+		// ensure controller is loaded
196
+		self::_load_controller();
197
+		$token = self::getRequest()->getRequestParam('token');
198
+		try {
199
+			$mtg = new EE_Message_Generated_From_Token($token, 'html', self::$_message_resource_manager);
200
+			self::$_MSG_PROCESSOR->generate_and_send_now($mtg);
201
+		} catch (EE_Error $e) {
202
+			$error_msg = esc_html__(
203
+				'Please note that a system message failed to send due to a technical issue.',
204
+				'event_espresso'
205
+			);
206
+			// add specific message for developers if WP_DEBUG in on
207
+			$error_msg .= '||' . $e->getMessage();
208
+			EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
209
+		}
210
+	}
211
+
212
+
213
+	/**
214
+	 * This is called when a browser error trigger is executed.
215
+	 * When triggered this will grab the EE_Message matching the token in the request and use that to get the error
216
+	 * message and display it.
217
+	 *
218
+	 * @param $WP
219
+	 * @throws EE_Error
220
+	 * @throws InvalidArgumentException
221
+	 * @throws InvalidDataTypeException
222
+	 * @throws InvalidInterfaceException
223
+	 * @since 4.9.0
224
+	 */
225
+	public function browser_error_trigger($WP)
226
+	{
227
+		$token = self::getRequest()->getRequestParam('token');
228
+		if ($token) {
229
+			$message = EEM_Message::instance()->get_one_by_token($token);
230
+			if ($message instanceof EE_Message) {
231
+				header('HTTP/1.1 200 OK');
232
+				$error_msg = nl2br($message->error_message());
233
+				?>
234 234
                 <!DOCTYPE html>
235 235
                 <html>
236 236
                 <head></head>
237 237
                 <body>
238 238
                 <?php echo empty($error_msg)
239
-                    ? esc_html__(
240
-                        'Unfortunately, we were unable to capture the error message for this message.',
241
-                        'event_espresso'
242
-                    )
243
-                    : wp_kses(
244
-                        $error_msg,
245
-                        [
246
-                            'a'      => [
247
-                                'href'  => [],
248
-                                'title' => [],
249
-                            ],
250
-                            'span'   => [],
251
-                            'div'    => [],
252
-                            'p'      => [],
253
-                            'strong' => [],
254
-                            'em'     => [],
255
-                            'br'     => [],
256
-                        ]
257
-                    ); ?>
239
+					? esc_html__(
240
+						'Unfortunately, we were unable to capture the error message for this message.',
241
+						'event_espresso'
242
+					)
243
+					: wp_kses(
244
+						$error_msg,
245
+						[
246
+							'a'      => [
247
+								'href'  => [],
248
+								'title' => [],
249
+							],
250
+							'span'   => [],
251
+							'div'    => [],
252
+							'p'      => [],
253
+							'strong' => [],
254
+							'em'     => [],
255
+							'br'     => [],
256
+						]
257
+					); ?>
258 258
                 </body>
259 259
                 </html>
260 260
                 <?php
261
-                exit;
262
-            }
263
-        }
264
-    }
265
-
266
-
267
-    /**
268
-     *  This runs when the msg_url_trigger route has initiated.
269
-     *
270
-     * @param WP $WP
271
-     * @throws EE_Error
272
-     * @throws InvalidArgumentException
273
-     * @throws ReflectionException
274
-     * @throws InvalidDataTypeException
275
-     * @throws InvalidInterfaceException
276
-     * @since 4.5.0
277
-     */
278
-    public function run($WP)
279
-    {
280
-        // ensure controller is loaded
281
-        self::_load_controller();
282
-        // attempt to process message
283
-        try {
284
-            /** @type EE_Message_To_Generate_From_Request $message_to_generate */
285
-            $message_to_generate = EE_Registry::instance()->load_lib('Message_To_Generate_From_Request');
286
-            self::$_MSG_PROCESSOR->generate_and_send_now($message_to_generate);
287
-        } catch (EE_Error $e) {
288
-            $error_msg = esc_html__(
289
-                'Please note that a system message failed to send due to a technical issue.',
290
-                'event_espresso'
291
-            );
292
-            // add specific message for developers if WP_DEBUG in on
293
-            $error_msg .= '||' . $e->getMessage();
294
-            EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
295
-        }
296
-    }
297
-
298
-
299
-    /**
300
-     * This is triggered by the 'msg_cron_trigger' route.
301
-     *
302
-     * @param WP $WP
303
-     */
304
-    public function execute_batch_request($WP)
305
-    {
306
-        $this->run_cron();
307
-        header('HTTP/1.1 200 OK');
308
-        exit();
309
-    }
310
-
311
-
312
-    /**
313
-     * This gets executed on wp_cron jobs or when a batch request is initiated on its own separate non regular wp
314
-     * request.
315
-     */
316
-    public function run_cron()
317
-    {
318
-        self::_load_controller();
319
-        $request = self::getRequest();
320
-        // get required vars
321
-        $cron_type     = $request->getRequestParam('type');
322
-        $transient_key = $request->getRequestParam('key');
323
-
324
-        // now let's verify transient, if not valid exit immediately
325
-        if (! get_transient($transient_key)) {
326
-            /**
327
-             * trigger error so this gets in the error logs.  This is important because it happens on a non-user
328
-             * request.
329
-             */
330
-            trigger_error(esc_attr__('Invalid Request (Transient does not exist)', 'event_espresso'));
331
-        }
332
-
333
-        // if made it here, lets' delete the transient to keep the db clean
334
-        delete_transient($transient_key);
335
-
336
-        if (apply_filters('FHEE__EED_Messages__run_cron__use_wp_cron', true)) {
337
-            $method = 'batch_' . $cron_type . '_from_queue';
338
-            if (method_exists(self::$_MSG_PROCESSOR, $method)) {
339
-                self::$_MSG_PROCESSOR->$method();
340
-            } else {
341
-                // no matching task
342
-                /**
343
-                 * trigger error so this gets in the error logs.  This is important because it happens on a non user
344
-                 * request.
345
-                 */
346
-                trigger_error(
347
-                    esc_attr(
348
-                        sprintf(
349
-                            esc_html__('There is no task corresponding to this route %s', 'event_espresso'),
350
-                            $cron_type
351
-                        )
352
-                    )
353
-                );
354
-            }
355
-        }
356
-
357
-        do_action('FHEE__EED_Messages__run_cron__end');
358
-    }
359
-
360
-
361
-    /**
362
-     * This is used to retrieve the template pack for the given name.
363
-     * Retrieved packs are cached on the static $_TMP_PACKS array.  If there is no class matching the given name then
364
-     * the default template pack is returned.
365
-     *
366
-     * @param string $template_pack_name This should correspond to the dbref of the template pack (which is also used
367
-     *                                   in generating the Pack class name).
368
-     * @return EE_Messages_Template_Pack
369
-     * @throws EE_Error
370
-     * @throws InvalidArgumentException
371
-     * @throws ReflectionException
372
-     * @throws InvalidDataTypeException
373
-     * @throws InvalidInterfaceException
374
-     * @deprecated 4.9.0  @see EEH_MSG_Template::get_template_pack()
375
-     */
376
-    public static function get_template_pack($template_pack_name)
377
-    {
378
-        EE_Registry::instance()->load_helper('MSG_Template');
379
-        return EEH_MSG_Template::get_template_pack($template_pack_name);
380
-    }
381
-
382
-
383
-    /**
384
-     * Retrieves an array of all template packs.
385
-     * Array is in the format array( 'dbref' => EE_Messages_Template_Pack )
386
-     *
387
-     * @return EE_Messages_Template_Pack[]
388
-     * @throws EE_Error
389
-     * @throws InvalidArgumentException
390
-     * @throws ReflectionException
391
-     * @throws InvalidDataTypeException
392
-     * @throws InvalidInterfaceException
393
-     * @deprecated 4.9.0  @see EEH_MSG_Template_Pack::get_template_pack_collection
394
-     */
395
-    public static function get_template_packs()
396
-    {
397
-        EE_Registry::instance()->load_helper('MSG_Template');
398
-
399
-        // for backward compat, let's make sure this returns in the same format as originally.
400
-        $template_pack_collection = EEH_MSG_Template::get_template_pack_collection();
401
-        $template_pack_collection->rewind();
402
-        $template_packs = [];
403
-        while ($template_pack_collection->valid()) {
404
-            $template_packs[ $template_pack_collection->current()->dbref ] = $template_pack_collection->current();
405
-            $template_pack_collection->next();
406
-        }
407
-        return $template_packs;
408
-    }
409
-
410
-
411
-    /**
412
-     * This simply makes sure the autoloaders are registered for the EE_messages system.
413
-     *
414
-     * @return void
415
-     * @throws EE_Error
416
-     * @since 4.5.0
417
-     */
418
-    public static function set_autoloaders()
419
-    {
420
-        if (empty(self::$_MSG_PATHS)) {
421
-            self::_set_messages_paths();
422
-            foreach (self::$_MSG_PATHS as $path) {
423
-                EEH_Autoloader::register_autoloaders_for_each_file_in_folder($path);
424
-            }
425
-            // add aliases
426
-            EEH_Autoloader::add_alias('EE_messages', 'EE_messages');
427
-            EEH_Autoloader::add_alias('EE_messenger', 'EE_messenger');
428
-        }
429
-    }
430
-
431
-
432
-    /**
433
-     * Take care of adding all the paths for the messages components to the $_MSG_PATHS property
434
-     * for use by the Messages Autoloaders
435
-     *
436
-     * @return void.
437
-     * @since 4.5.0
438
-     */
439
-    protected static function _set_messages_paths()
440
-    {
441
-        self::$_MSG_PATHS = apply_filters(
442
-            'FHEE__EED_Messages___set_messages_paths___MSG_PATHS',
443
-            [
444
-                EE_LIBRARIES . 'messages/message_type',
445
-                EE_LIBRARIES . 'messages/messenger',
446
-                EE_LIBRARIES . 'messages/defaults',
447
-                EE_LIBRARIES . 'messages/defaults/email',
448
-                EE_LIBRARIES . 'messages/data_class',
449
-                EE_LIBRARIES . 'messages/validators',
450
-                EE_LIBRARIES . 'messages/validators/email',
451
-                EE_LIBRARIES . 'messages/validators/html',
452
-                EE_LIBRARIES . 'shortcodes',
453
-            ]
454
-        );
455
-    }
456
-
457
-
458
-    /**
459
-     * Takes care of loading dependencies
460
-     *
461
-     * @return void
462
-     * @throws EE_Error
463
-     * @throws InvalidArgumentException
464
-     * @throws ReflectionException
465
-     * @throws InvalidDataTypeException
466
-     * @throws InvalidInterfaceException
467
-     * @since 4.5.0
468
-     */
469
-    protected static function _load_controller()
470
-    {
471
-        if (! self::$_MSG_PROCESSOR instanceof EE_Messages_Processor) {
472
-            EE_Registry::instance()->load_core('Request_Handler');
473
-            self::set_autoloaders();
474
-            self::$_EEMSG                    = EE_Registry::instance()->load_lib('messages');
475
-            self::$_MSG_PROCESSOR            = EE_Registry::instance()->load_lib('Messages_Processor');
476
-            self::$_message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
477
-        }
478
-    }
479
-
480
-
481
-    /**
482
-     * @param EE_Transaction $transaction
483
-     * @throws EE_Error
484
-     * @throws InvalidArgumentException
485
-     * @throws InvalidDataTypeException
486
-     * @throws InvalidInterfaceException
487
-     * @throws ReflectionException
488
-     */
489
-    public static function payment_reminder(EE_Transaction $transaction)
490
-    {
491
-        self::_load_controller();
492
-        $data = [$transaction, null];
493
-        self::$_MSG_PROCESSOR->generate_for_all_active_messengers('payment_reminder', $data);
494
-    }
495
-
496
-
497
-    /**
498
-     * Any messages triggers for after successful gateway payments should go in here.
499
-     *
500
-     * @param EE_Transaction  $transaction object
501
-     * @param EE_Payment|null $payment     object
502
-     * @return void
503
-     * @throws EE_Error
504
-     * @throws InvalidArgumentException
505
-     * @throws ReflectionException
506
-     * @throws InvalidDataTypeException
507
-     * @throws InvalidInterfaceException
508
-     */
509
-    public static function payment(EE_Transaction $transaction, EE_Payment $payment = null)
510
-    {
511
-        // if there's no payment object, then we cannot do a payment type message!
512
-        if (! $payment instanceof EE_Payment) {
513
-            return;
514
-        }
515
-        self::_load_controller();
516
-        $data = [$transaction, $payment];
517
-        EE_Registry::instance()->load_helper('MSG_Template');
518
-        $message_type = EEH_MSG_Template::convert_payment_status_to_message_type($payment->STS_ID());
519
-        // if payment amount is less than 0 then switch to payment_refund message type.
520
-        $message_type = $payment->amount() < 0 ? 'payment_refund' : $message_type;
521
-        self::$_MSG_PROCESSOR->generate_for_all_active_messengers($message_type, $data);
522
-    }
523
-
524
-
525
-    /**
526
-     * @param EE_Transaction $transaction
527
-     * @throws EE_Error
528
-     * @throws InvalidArgumentException
529
-     * @throws InvalidDataTypeException
530
-     * @throws InvalidInterfaceException
531
-     * @throws ReflectionException
532
-     */
533
-    public static function cancelled_registration(EE_Transaction $transaction)
534
-    {
535
-        self::_load_controller();
536
-        $data = [$transaction, null];
537
-        self::$_MSG_PROCESSOR->generate_for_all_active_messengers('cancelled_registration', $data);
538
-    }
539
-
540
-
541
-    /**
542
-     * Trigger for Registration messages
543
-     * Note that what registration message type is sent depends on what the reg status is for the registrations on the
544
-     * incoming transaction.
545
-     *
546
-     * @param EE_Registration $registration
547
-     * @param array           $extra_details
548
-     * @return void
549
-     * @throws EE_Error
550
-     * @throws InvalidArgumentException
551
-     * @throws InvalidDataTypeException
552
-     * @throws InvalidInterfaceException
553
-     * @throws ReflectionException
554
-     * @throws EntityNotFoundException
555
-     */
556
-    public static function maybe_registration(EE_Registration $registration, $extra_details = [])
557
-    {
558
-
559
-        if (! self::_verify_registration_notification_send($registration, $extra_details)) {
560
-            // no messages please
561
-            return;
562
-        }
563
-
564
-        // get all non-trashed registrations so we make sure we send messages for the right status.
565
-        $all_registrations = $registration->transaction()->registrations(
566
-            [
567
-                ['REG_deleted' => false],
568
-                'order_by' => [
569
-                    'Event.EVT_name'     => 'ASC',
570
-                    'Attendee.ATT_lname' => 'ASC',
571
-                    'Attendee.ATT_fname' => 'ASC',
572
-                ],
573
-            ]
574
-        );
575
-        // cached array of statuses so we only trigger messages once per status.
576
-        $statuses_sent = [];
577
-        self::_load_controller();
578
-        $mtgs = [];
579
-
580
-        // loop through registrations and trigger messages once per status.
581
-        foreach ($all_registrations as $reg) {
582
-            // already triggered?
583
-            if (in_array($reg->status_ID(), $statuses_sent)) {
584
-                continue;
585
-            }
586
-
587
-            $message_type    = EEH_MSG_Template::convert_reg_status_to_message_type($reg->status_ID());
588
-            $mtgs            = array_merge(
589
-                $mtgs,
590
-                self::$_MSG_PROCESSOR->setup_mtgs_for_all_active_messengers(
591
-                    $message_type,
592
-                    [$registration->transaction(), null, $reg->status_ID()]
593
-                )
594
-            );
595
-            $statuses_sent[] = $reg->status_ID();
596
-        }
597
-
598
-        if (count($statuses_sent) > 1) {
599
-            $mtgs = array_merge(
600
-                $mtgs,
601
-                self::$_MSG_PROCESSOR->setup_mtgs_for_all_active_messengers(
602
-                    'registration_summary',
603
-                    [$registration->transaction(), null]
604
-                )
605
-            );
606
-        }
607
-
608
-        // batch queue and initiate request
609
-        self::$_MSG_PROCESSOR->batch_queue_for_generation_and_persist($mtgs);
610
-        self::$_MSG_PROCESSOR->get_queue()->initiate_request_by_priority();
611
-    }
612
-
613
-
614
-    /**
615
-     * This is a helper method used to very whether a registration notification should be sent or
616
-     * not.  Prevents duplicate notifications going out for registration context notifications.
617
-     *
618
-     * @param EE_Registration $registration  [description]
619
-     * @param array           $extra_details [description]
620
-     * @return bool          true = send away, false = nope halt the presses.
621
-     */
622
-    protected static function _verify_registration_notification_send(
623
-        EE_Registration $registration,
624
-        $extra_details = []
625
-    ) {
626
-        $request = self::getRequest();
627
-        if (
628
-            ! $request->getRequestParam('non_primary_reg_notification', 0, 'int')
629
-            && ! $registration->is_primary_registrant()
630
-        ) {
631
-            return false;
632
-        }
633
-        // first we check if we're in admin and not doing front ajax
634
-        if (
635
-            ($request->isAdmin() || $request->isAdminAjax())
636
-            && ! $request->isFrontAjax()
637
-        ) {
638
-            $status_change = $request->getRequestParam('txn_reg_status_change', [], 'int', true);
639
-            // make sure appropriate admin params are set for sending messages
640
-            if (
641
-                ! isset($status_change['send_notifications'])
642
-                || (isset($status_change['send_notifications']) && ! $status_change['send_notifications'])
643
-            ) {
644
-                // no messages sent please.
645
-                return false;
646
-            }
647
-        } else {
648
-            // frontend request (either regular or via AJAX)
649
-            // TXN is NOT finalized ?
650
-            if (! isset($extra_details['finalized']) || $extra_details['finalized'] === false) {
651
-                return false;
652
-            }
653
-            // return visit but nothing changed ???
654
-            if (
655
-                isset($extra_details['revisit'], $extra_details['status_updates'])
656
-                && $extra_details['revisit']
657
-                && ! $extra_details['status_updates']
658
-            ) {
659
-                return false;
660
-            }
661
-            // NOT sending messages && reg status is something other than "Not-Approved"
662
-            if (
663
-                ! apply_filters('FHEE__EED_Messages___maybe_registration__deliver_notifications', false)
664
-                && $registration->status_ID() !== EEM_Registration::status_id_not_approved
665
-            ) {
666
-                return false;
667
-            }
668
-        }
669
-        // release the kraken
670
-        return true;
671
-    }
672
-
673
-
674
-    /**
675
-     * Simply returns an array indexed by Registration Status ID and the related message_type name associated with that
676
-     * status id.
677
-     *
678
-     * @param string $reg_status
679
-     * @return array
680
-     * @throws EE_Error
681
-     * @throws InvalidArgumentException
682
-     * @throws ReflectionException
683
-     * @throws InvalidDataTypeException
684
-     * @throws InvalidInterfaceException
685
-     * @deprecated        4.9.0  Use EEH_MSG_Template::reg_status_to_message_type_array()
686
-     *                    or EEH_MSG_Template::convert_reg_status_to_message_type
687
-     */
688
-    protected static function _get_reg_status_array($reg_status = '')
689
-    {
690
-        EE_Registry::instance()->load_helper('MSG_Template');
691
-        return EEH_MSG_Template::convert_reg_status_to_message_type($reg_status)
692
-            ? EEH_MSG_Template::convert_reg_status_to_message_type($reg_status)
693
-            : EEH_MSG_Template::reg_status_to_message_type_array();
694
-    }
695
-
696
-
697
-    /**
698
-     * Simply returns the payment message type for the given payment status.
699
-     *
700
-     * @param string $payment_status The payment status being matched.
701
-     * @return bool|string The payment message type slug matching the status or false if no match.
702
-     * @throws EE_Error
703
-     * @throws InvalidArgumentException
704
-     * @throws ReflectionException
705
-     * @throws InvalidDataTypeException
706
-     * @throws InvalidInterfaceException
707
-     * @deprecated       4.9.0 Use EEH_MSG_Template::payment_status_to_message_type_array
708
-     *                   or EEH_MSG_Template::convert_payment_status_to_message_type
709
-     */
710
-    protected static function _get_payment_message_type($payment_status)
711
-    {
712
-        EE_Registry::instance()->load_helper('MSG_Template');
713
-        return EEH_MSG_Template::convert_payment_status_to_message_type($payment_status)
714
-            ? EEH_MSG_Template::convert_payment_status_to_message_type($payment_status)
715
-            : false;
716
-    }
717
-
718
-
719
-    /**
720
-     * Message triggers for a resending already sent message(s) (via EE_Message list table)
721
-     *
722
-     * @access public
723
-     * @param array $req_data This is the $_POST & $_GET data sent from EE_Admin Pages
724
-     * @return bool success/fail
725
-     * @throws EE_Error
726
-     * @throws InvalidArgumentException
727
-     * @throws InvalidDataTypeException
728
-     * @throws InvalidInterfaceException
729
-     * @throws ReflectionException
730
-     */
731
-    public static function process_resend(array $req_data = [])
732
-    {
733
-        self::_load_controller();
734
-        $request = self::getRequest();
735
-        // if $msgID in this request then skip to the new resend_message
736
-        if ($request->getRequestParam('MSG_ID')) {
737
-            return self::resend_message();
738
-        }
739
-
740
-        // make sure any incoming request data is set on the request so that it gets picked up later.
741
-        foreach ((array) $req_data as $request_key => $request_value) {
742
-            if (! $request->requestParamIsSet($request_key)) {
743
-                $request->setRequestParam($request_key, $request_value);
744
-            }
745
-        }
746
-
747
-        if (
748
-            ! $messages_to_send = self::$_MSG_PROCESSOR->setup_messages_to_generate_from_registration_ids_in_request()
749
-        ) {
750
-            return false;
751
-        }
752
-
753
-        try {
754
-            self::$_MSG_PROCESSOR->batch_queue_for_generation_and_persist($messages_to_send);
755
-            self::$_MSG_PROCESSOR->get_queue()->initiate_request_by_priority();
756
-        } catch (EE_Error $e) {
757
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
758
-            return false;
759
-        }
760
-        EE_Error::add_success(
761
-            esc_html__('Messages have been successfully queued for generation and sending.', 'event_espresso')
762
-        );
763
-        return true; // everything got queued.
764
-    }
765
-
766
-
767
-    /**
768
-     * Message triggers for a resending already sent message(s) (via EE_Message list table)
769
-     *
770
-     * @return bool
771
-     * @throws EE_Error
772
-     * @throws InvalidArgumentException
773
-     * @throws InvalidDataTypeException
774
-     * @throws InvalidInterfaceException
775
-     * @throws ReflectionException
776
-     */
777
-    public static function resend_message()
778
-    {
779
-        self::_load_controller();
780
-
781
-        $msgID = self::getRequest()->getRequestParam('MSG_ID', 0, 'int');
782
-        if (! $msgID) {
783
-            EE_Error::add_error(
784
-                esc_html__(
785
-                    'Something went wrong because there is no "MSG_ID" value in the request',
786
-                    'event_espresso'
787
-                ),
788
-                __FILE__,
789
-                __FUNCTION__,
790
-                __LINE__
791
-            );
792
-            return false;
793
-        }
794
-
795
-        self::$_MSG_PROCESSOR->setup_messages_from_ids_and_send((array) $msgID);
796
-
797
-        // setup success message.
798
-        $count_ready_for_resend = self::$_MSG_PROCESSOR->get_queue()->count_STS_in_queue(EEM_Message::status_resend);
799
-        EE_Error::add_success(
800
-            sprintf(
801
-                _n(
802
-                    'There was %d message queued for resending.',
803
-                    'There were %d messages queued for resending.',
804
-                    $count_ready_for_resend,
805
-                    'event_espresso'
806
-                ),
807
-                $count_ready_for_resend
808
-            )
809
-        );
810
-        return true;
811
-    }
812
-
813
-
814
-    /**
815
-     * Message triggers for manual payment applied by admin
816
-     *
817
-     * @param EE_Payment $payment EE_payment object
818
-     * @return bool success/fail
819
-     * @throws EE_Error
820
-     * @throws InvalidArgumentException
821
-     * @throws ReflectionException
822
-     * @throws InvalidDataTypeException
823
-     * @throws InvalidInterfaceException
824
-     */
825
-    public static function process_admin_payment(EE_Payment $payment)
826
-    {
827
-        EE_Registry::instance()->load_helper('MSG_Template');
828
-        // we need to get the transaction object
829
-        $transaction = $payment->transaction();
830
-        if ($transaction instanceof EE_Transaction) {
831
-            $data         = [$transaction, $payment];
832
-            $message_type = EEH_MSG_Template::convert_payment_status_to_message_type($payment->STS_ID());
833
-
834
-            // if payment amount is less than 0 then switch to payment_refund message type.
835
-            $message_type = $payment->amount() < 0 ? 'payment_refund' : $message_type;
836
-
837
-            // if payment_refund is selected, but the status is NOT accepted.  Then change message type to false so NO message notification goes out.
838
-            $message_type = $message_type == 'payment_refund' && $payment->STS_ID() != EEM_Payment::status_id_approved
839
-                ? false : $message_type;
840
-
841
-            self::_load_controller();
842
-
843
-            self::$_MSG_PROCESSOR->generate_for_all_active_messengers($message_type, $data);
844
-
845
-            // get count of queued for generation
846
-            $count_to_generate = self::$_MSG_PROCESSOR->get_queue()->count_STS_in_queue(
847
-                [
848
-                    EEM_Message::status_incomplete,
849
-                    EEM_Message::status_idle,
850
-                ]
851
-            );
852
-
853
-            if ($count_to_generate > 0 && self::$_MSG_PROCESSOR->get_queue()->get_message_repository()->count() !== 0) {
854
-                add_filter('FHEE__EE_Admin_Page___process_admin_payment_notification__success', '__return_true');
855
-                return true;
856
-            } else {
857
-                $count_failed = self::$_MSG_PROCESSOR->get_queue()->count_STS_in_queue(
858
-                    EEM_Message::instance()->stati_indicating_failed_sending()
859
-                );
860
-                /**
861
-                 * Verify that there are actually errors.  If not then we return a success message because the queue might have been emptied due to successful
862
-                 * IMMEDIATE generation.
863
-                 */
864
-                if ($count_failed > 0) {
865
-                    EE_Error::add_error(
866
-                        sprintf(
867
-                            _n(
868
-                                'The payment notification generation failed.',
869
-                                '%d payment notifications failed being sent.',
870
-                                $count_failed,
871
-                                'event_espresso'
872
-                            ),
873
-                            $count_failed
874
-                        ),
875
-                        __FILE__,
876
-                        __FUNCTION__,
877
-                        __LINE__
878
-                    );
879
-
880
-                    return false;
881
-                } else {
882
-                    add_filter('FHEE__EE_Admin_Page___process_admin_payment_notification__success', '__return_true');
883
-                    return true;
884
-                }
885
-            }
886
-        } else {
887
-            EE_Error::add_error(
888
-                'Unable to generate the payment notification because the given value for the transaction is invalid.',
889
-                'event_espresso'
890
-            );
891
-            return false;
892
-        }
893
-    }
894
-
895
-
896
-    /**
897
-     * Callback for AHEE__Extend_Registrations_Admin_Page___newsletter_selected_send_with_registrations trigger
898
-     *
899
-     * @param EE_Registration[] $registrations an array of EE_Registration objects
900
-     * @param int               $grp_id        a specific message template group id.
901
-     * @return void
902
-     * @throws EE_Error
903
-     * @throws InvalidArgumentException
904
-     * @throws InvalidDataTypeException
905
-     * @throws InvalidInterfaceException
906
-     * @throws ReflectionException
907
-     * @since   4.3.0
908
-     */
909
-    public static function send_newsletter_message($registrations, $grp_id)
910
-    {
911
-        // make sure mtp is id and set it in the request later messages setup.
912
-        self::getRequest()->setRequestParam('GRP_ID', (int) $grp_id);
913
-        self::_load_controller();
914
-        self::$_MSG_PROCESSOR->generate_for_all_active_messengers('newsletter', $registrations);
915
-    }
916
-
917
-
918
-    /**
919
-     * Callback for FHEE__EE_Registration__invoice_url__invoice_url or FHEE__EE_Registration__receipt_url__receipt_url
920
-     *
921
-     * @param string          $registration_message_trigger_url
922
-     * @param EE_Registration $registration
923
-     * @param string          $messenger
924
-     * @param string          $message_type
925
-     * @return string
926
-     * @throws EE_Error
927
-     * @throws InvalidArgumentException
928
-     * @throws InvalidDataTypeException
929
-     * @throws InvalidInterfaceException
930
-     * @since   4.3.0
931
-     */
932
-    public static function registration_message_trigger_url(
933
-        $registration_message_trigger_url,
934
-        EE_Registration $registration,
935
-        $messenger = 'html',
936
-        $message_type = 'invoice'
937
-    ) {
938
-        // whitelist $messenger
939
-        switch ($messenger) {
940
-            case 'pdf':
941
-                $sending_messenger    = 'pdf';
942
-                $generating_messenger = 'html';
943
-                break;
944
-            case 'html':
945
-            default:
946
-                $sending_messenger    = 'html';
947
-                $generating_messenger = 'html';
948
-                break;
949
-        }
950
-        // whitelist $message_type
951
-        switch ($message_type) {
952
-            case 'receipt':
953
-                $message_type = 'receipt';
954
-                break;
955
-            case 'invoice':
956
-            default:
957
-                $message_type = 'invoice';
958
-                break;
959
-        }
960
-        // verify that both the messenger AND the message type are active
961
-        if (
962
-            EEH_MSG_Template::is_messenger_active($sending_messenger)
963
-            && EEH_MSG_Template::is_mt_active($message_type)
964
-        ) {
965
-            // need to get the correct message template group for this (i.e. is there a custom invoice for the event this registration is registered for?)
966
-            $template_query_params = [
967
-                'MTP_is_active'    => true,
968
-                'MTP_messenger'    => $generating_messenger,
969
-                'MTP_message_type' => $message_type,
970
-                'Event.EVT_ID'     => $registration->event_ID(),
971
-            ];
972
-            // get the message template group.
973
-            $msg_template_group = EEM_Message_Template_Group::instance()->get_one([$template_query_params]);
974
-            // if we don't have an EE_Message_Template_Group then return
975
-            if (! $msg_template_group instanceof EE_Message_Template_Group) {
976
-                // remove EVT_ID from query params so that global templates get picked up
977
-                unset($template_query_params['Event.EVT_ID']);
978
-                // get global template as the fallback
979
-                $msg_template_group = EEM_Message_Template_Group::instance()->get_one([$template_query_params]);
980
-            }
981
-            // if we don't have an EE_Message_Template_Group then return
982
-            if (! $msg_template_group instanceof EE_Message_Template_Group) {
983
-                return '';
984
-            }
985
-            // generate the URL
986
-            $registration_message_trigger_url = EEH_MSG_Template::generate_url_trigger(
987
-                $sending_messenger,
988
-                $generating_messenger,
989
-                'purchaser',
990
-                $message_type,
991
-                $registration,
992
-                $msg_template_group->ID(),
993
-                $registration->transaction_ID()
994
-            );
995
-        }
996
-        return $registration_message_trigger_url;
997
-    }
998
-
999
-
1000
-    /**
1001
-     * Use to generate and return a message preview!
1002
-     *
1003
-     * @param string $type       This should correspond with a valid message type
1004
-     * @param string $context    This should correspond with a valid context for the message type
1005
-     * @param string $messenger  This should correspond with a valid messenger.
1006
-     * @param bool   $send       true we will do a test send using the messenger delivery, false we just do a regular
1007
-     *                           preview
1008
-     * @return bool|string The body of the message or if send is requested, sends.
1009
-     * @throws EE_Error
1010
-     * @throws InvalidArgumentException
1011
-     * @throws InvalidDataTypeException
1012
-     * @throws InvalidInterfaceException
1013
-     * @throws ReflectionException
1014
-     */
1015
-    public static function preview_message($type, $context, $messenger, $send = false)
1016
-    {
1017
-        self::_load_controller();
1018
-        $message_to_generate     = new EE_Message_To_Generate(
1019
-            $messenger,
1020
-            $type,
1021
-            [],
1022
-            $context,
1023
-            true
1024
-        );
1025
-        $generated_preview_queue = self::$_MSG_PROCESSOR->generate_for_preview($message_to_generate, $send);
1026
-
1027
-        if ($generated_preview_queue instanceof EE_Messages_Queue) {
1028
-            // loop through all content for the preview and remove any persisted records.
1029
-            $content = '';
1030
-            foreach ($generated_preview_queue->get_message_repository() as $message) {
1031
-                $content = $message->content();
1032
-                if ($message->ID() > 0 && $message->STS_ID() !== EEM_Message::status_failed) {
1033
-                    $message->delete();
1034
-                }
1035
-            }
1036
-            return $content;
1037
-        }
1038
-        return $generated_preview_queue;
1039
-    }
1040
-
1041
-
1042
-    /**
1043
-     * This is a method that allows for sending a message using a messenger matching the string given and the provided
1044
-     * EE_Message_Queue object.  The EE_Message_Queue object is used to create a single aggregate EE_Message via the
1045
-     * content found in the EE_Message objects in the queue.
1046
-     *
1047
-     * @param string            $messenger            a string matching a valid active messenger in the system
1048
-     * @param string            $message_type         Although it seems contrary to the name of the method, a message
1049
-     *                                                type name is still required to send along the message type to the
1050
-     *                                                messenger because this is used for determining what specific
1051
-     *                                                variations might be loaded for the generated message.
1052
-     * @param EE_Messages_Queue $queue
1053
-     * @param string            $custom_subject       Can be used to set what the custom subject string will be on the
1054
-     *                                                aggregate EE_Message object.
1055
-     * @return bool success or fail.
1056
-     * @throws EE_Error
1057
-     * @throws InvalidArgumentException
1058
-     * @throws ReflectionException
1059
-     * @throws InvalidDataTypeException
1060
-     * @throws InvalidInterfaceException
1061
-     * @since 4.9.0
1062
-     */
1063
-    public static function send_message_with_messenger_only(
1064
-        $messenger,
1065
-        $message_type,
1066
-        EE_Messages_Queue $queue,
1067
-        $custom_subject = ''
1068
-    ) {
1069
-        self::_load_controller();
1070
-        /** @type EE_Message_To_Generate_From_Queue $message_to_generate */
1071
-        $message_to_generate = EE_Registry::instance()->load_lib(
1072
-            'Message_To_Generate_From_Queue',
1073
-            [
1074
-                $messenger,
1075
-                $message_type,
1076
-                $queue,
1077
-                $custom_subject,
1078
-            ]
1079
-        );
1080
-        return self::$_MSG_PROCESSOR->queue_for_sending($message_to_generate);
1081
-    }
1082
-
1083
-
1084
-    /**
1085
-     * Generates Messages immediately for EE_Message IDs (but only for the correct status for generation)
1086
-     *
1087
-     * @param array $message_ids An array of message ids
1088
-     * @return bool|EE_Messages_Queue false if nothing was generated, EE_Messages_Queue containing generated
1089
-     *                           messages.
1090
-     * @throws EE_Error
1091
-     * @throws InvalidArgumentException
1092
-     * @throws InvalidDataTypeException
1093
-     * @throws InvalidInterfaceException
1094
-     * @throws ReflectionException
1095
-     * @since 4.9.0
1096
-     */
1097
-    public static function generate_now($message_ids)
1098
-    {
1099
-        self::_load_controller();
1100
-        $messages        = EEM_Message::instance()->get_all(
1101
-            [
1102
-                0 => [
1103
-                    'MSG_ID' => ['IN', $message_ids],
1104
-                    'STS_ID' => EEM_Message::status_incomplete,
1105
-                ],
1106
-            ]
1107
-        );
1108
-        $generated_queue = false;
1109
-        if ($messages) {
1110
-            $generated_queue = self::$_MSG_PROCESSOR->batch_generate_from_queue($messages);
1111
-        }
1112
-
1113
-        if (! $generated_queue instanceof EE_Messages_Queue) {
1114
-            EE_Error::add_error(
1115
-                esc_html__(
1116
-                    'The messages were not generated. This could mean there is already a batch being generated on a separate request, or because the selected messages are not ready for generation. Please wait a minute or two and try again.',
1117
-                    'event_espresso'
1118
-                ),
1119
-                __FILE__,
1120
-                __FUNCTION__,
1121
-                __LINE__
1122
-            );
1123
-        }
1124
-        return $generated_queue;
1125
-    }
1126
-
1127
-
1128
-    /**
1129
-     * Sends messages immediately for the incoming message_ids that have the status of EEM_Message::status_resend or,
1130
-     * EEM_Message::status_idle
1131
-     *
1132
-     * @param $message_ids
1133
-     * @return bool|EE_Messages_Queue false if no messages sent.
1134
-     * @throws EE_Error
1135
-     * @throws InvalidArgumentException
1136
-     * @throws InvalidDataTypeException
1137
-     * @throws InvalidInterfaceException
1138
-     * @throws ReflectionException
1139
-     * @since 4.9.0
1140
-     */
1141
-    public static function send_now($message_ids)
1142
-    {
1143
-        self::_load_controller();
1144
-        $messages   = EEM_Message::instance()->get_all(
1145
-            [
1146
-                0 => [
1147
-                    'MSG_ID' => ['IN', $message_ids],
1148
-                    'STS_ID' => [
1149
-                        'IN',
1150
-                        [EEM_Message::status_idle, EEM_Message::status_resend, EEM_Message::status_retry],
1151
-                    ],
1152
-                ],
1153
-            ]
1154
-        );
1155
-        $sent_queue = false;
1156
-        if ($messages) {
1157
-            $sent_queue = self::$_MSG_PROCESSOR->batch_send_from_queue($messages);
1158
-        }
1159
-
1160
-        if (! $sent_queue instanceof EE_Messages_Queue) {
1161
-            EE_Error::add_error(
1162
-                esc_html__(
1163
-                    'The messages were not sent. This could mean there is already a batch being sent on a separate request, or because the selected messages are not sendable. Please wait a minute or two and try again.',
1164
-                    'event_espresso'
1165
-                ),
1166
-                __FILE__,
1167
-                __FUNCTION__,
1168
-                __LINE__
1169
-            );
1170
-        } else {
1171
-            // can count how many sent by using the messages in the queue
1172
-            $sent_count = $sent_queue->count_STS_in_queue(EEM_Message::instance()->stati_indicating_sent());
1173
-            if ($sent_count > 0) {
1174
-                EE_Error::add_success(
1175
-                    sprintf(
1176
-                        _n(
1177
-                            'There was %d message successfully sent.',
1178
-                            'There were %d messages successfully sent.',
1179
-                            $sent_count,
1180
-                            'event_espresso'
1181
-                        ),
1182
-                        $sent_count
1183
-                    )
1184
-                );
1185
-            } else {
1186
-                EE_Error::overwrite_errors();
1187
-                EE_Error::add_error(
1188
-                    esc_html__(
1189
-                        'No message was sent because of problems with sending. Either all the messages you selected were not a sendable message, they were ALREADY sent on a different scheduled task, or there was an error.
261
+				exit;
262
+			}
263
+		}
264
+	}
265
+
266
+
267
+	/**
268
+	 *  This runs when the msg_url_trigger route has initiated.
269
+	 *
270
+	 * @param WP $WP
271
+	 * @throws EE_Error
272
+	 * @throws InvalidArgumentException
273
+	 * @throws ReflectionException
274
+	 * @throws InvalidDataTypeException
275
+	 * @throws InvalidInterfaceException
276
+	 * @since 4.5.0
277
+	 */
278
+	public function run($WP)
279
+	{
280
+		// ensure controller is loaded
281
+		self::_load_controller();
282
+		// attempt to process message
283
+		try {
284
+			/** @type EE_Message_To_Generate_From_Request $message_to_generate */
285
+			$message_to_generate = EE_Registry::instance()->load_lib('Message_To_Generate_From_Request');
286
+			self::$_MSG_PROCESSOR->generate_and_send_now($message_to_generate);
287
+		} catch (EE_Error $e) {
288
+			$error_msg = esc_html__(
289
+				'Please note that a system message failed to send due to a technical issue.',
290
+				'event_espresso'
291
+			);
292
+			// add specific message for developers if WP_DEBUG in on
293
+			$error_msg .= '||' . $e->getMessage();
294
+			EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
295
+		}
296
+	}
297
+
298
+
299
+	/**
300
+	 * This is triggered by the 'msg_cron_trigger' route.
301
+	 *
302
+	 * @param WP $WP
303
+	 */
304
+	public function execute_batch_request($WP)
305
+	{
306
+		$this->run_cron();
307
+		header('HTTP/1.1 200 OK');
308
+		exit();
309
+	}
310
+
311
+
312
+	/**
313
+	 * This gets executed on wp_cron jobs or when a batch request is initiated on its own separate non regular wp
314
+	 * request.
315
+	 */
316
+	public function run_cron()
317
+	{
318
+		self::_load_controller();
319
+		$request = self::getRequest();
320
+		// get required vars
321
+		$cron_type     = $request->getRequestParam('type');
322
+		$transient_key = $request->getRequestParam('key');
323
+
324
+		// now let's verify transient, if not valid exit immediately
325
+		if (! get_transient($transient_key)) {
326
+			/**
327
+			 * trigger error so this gets in the error logs.  This is important because it happens on a non-user
328
+			 * request.
329
+			 */
330
+			trigger_error(esc_attr__('Invalid Request (Transient does not exist)', 'event_espresso'));
331
+		}
332
+
333
+		// if made it here, lets' delete the transient to keep the db clean
334
+		delete_transient($transient_key);
335
+
336
+		if (apply_filters('FHEE__EED_Messages__run_cron__use_wp_cron', true)) {
337
+			$method = 'batch_' . $cron_type . '_from_queue';
338
+			if (method_exists(self::$_MSG_PROCESSOR, $method)) {
339
+				self::$_MSG_PROCESSOR->$method();
340
+			} else {
341
+				// no matching task
342
+				/**
343
+				 * trigger error so this gets in the error logs.  This is important because it happens on a non user
344
+				 * request.
345
+				 */
346
+				trigger_error(
347
+					esc_attr(
348
+						sprintf(
349
+							esc_html__('There is no task corresponding to this route %s', 'event_espresso'),
350
+							$cron_type
351
+						)
352
+					)
353
+				);
354
+			}
355
+		}
356
+
357
+		do_action('FHEE__EED_Messages__run_cron__end');
358
+	}
359
+
360
+
361
+	/**
362
+	 * This is used to retrieve the template pack for the given name.
363
+	 * Retrieved packs are cached on the static $_TMP_PACKS array.  If there is no class matching the given name then
364
+	 * the default template pack is returned.
365
+	 *
366
+	 * @param string $template_pack_name This should correspond to the dbref of the template pack (which is also used
367
+	 *                                   in generating the Pack class name).
368
+	 * @return EE_Messages_Template_Pack
369
+	 * @throws EE_Error
370
+	 * @throws InvalidArgumentException
371
+	 * @throws ReflectionException
372
+	 * @throws InvalidDataTypeException
373
+	 * @throws InvalidInterfaceException
374
+	 * @deprecated 4.9.0  @see EEH_MSG_Template::get_template_pack()
375
+	 */
376
+	public static function get_template_pack($template_pack_name)
377
+	{
378
+		EE_Registry::instance()->load_helper('MSG_Template');
379
+		return EEH_MSG_Template::get_template_pack($template_pack_name);
380
+	}
381
+
382
+
383
+	/**
384
+	 * Retrieves an array of all template packs.
385
+	 * Array is in the format array( 'dbref' => EE_Messages_Template_Pack )
386
+	 *
387
+	 * @return EE_Messages_Template_Pack[]
388
+	 * @throws EE_Error
389
+	 * @throws InvalidArgumentException
390
+	 * @throws ReflectionException
391
+	 * @throws InvalidDataTypeException
392
+	 * @throws InvalidInterfaceException
393
+	 * @deprecated 4.9.0  @see EEH_MSG_Template_Pack::get_template_pack_collection
394
+	 */
395
+	public static function get_template_packs()
396
+	{
397
+		EE_Registry::instance()->load_helper('MSG_Template');
398
+
399
+		// for backward compat, let's make sure this returns in the same format as originally.
400
+		$template_pack_collection = EEH_MSG_Template::get_template_pack_collection();
401
+		$template_pack_collection->rewind();
402
+		$template_packs = [];
403
+		while ($template_pack_collection->valid()) {
404
+			$template_packs[ $template_pack_collection->current()->dbref ] = $template_pack_collection->current();
405
+			$template_pack_collection->next();
406
+		}
407
+		return $template_packs;
408
+	}
409
+
410
+
411
+	/**
412
+	 * This simply makes sure the autoloaders are registered for the EE_messages system.
413
+	 *
414
+	 * @return void
415
+	 * @throws EE_Error
416
+	 * @since 4.5.0
417
+	 */
418
+	public static function set_autoloaders()
419
+	{
420
+		if (empty(self::$_MSG_PATHS)) {
421
+			self::_set_messages_paths();
422
+			foreach (self::$_MSG_PATHS as $path) {
423
+				EEH_Autoloader::register_autoloaders_for_each_file_in_folder($path);
424
+			}
425
+			// add aliases
426
+			EEH_Autoloader::add_alias('EE_messages', 'EE_messages');
427
+			EEH_Autoloader::add_alias('EE_messenger', 'EE_messenger');
428
+		}
429
+	}
430
+
431
+
432
+	/**
433
+	 * Take care of adding all the paths for the messages components to the $_MSG_PATHS property
434
+	 * for use by the Messages Autoloaders
435
+	 *
436
+	 * @return void.
437
+	 * @since 4.5.0
438
+	 */
439
+	protected static function _set_messages_paths()
440
+	{
441
+		self::$_MSG_PATHS = apply_filters(
442
+			'FHEE__EED_Messages___set_messages_paths___MSG_PATHS',
443
+			[
444
+				EE_LIBRARIES . 'messages/message_type',
445
+				EE_LIBRARIES . 'messages/messenger',
446
+				EE_LIBRARIES . 'messages/defaults',
447
+				EE_LIBRARIES . 'messages/defaults/email',
448
+				EE_LIBRARIES . 'messages/data_class',
449
+				EE_LIBRARIES . 'messages/validators',
450
+				EE_LIBRARIES . 'messages/validators/email',
451
+				EE_LIBRARIES . 'messages/validators/html',
452
+				EE_LIBRARIES . 'shortcodes',
453
+			]
454
+		);
455
+	}
456
+
457
+
458
+	/**
459
+	 * Takes care of loading dependencies
460
+	 *
461
+	 * @return void
462
+	 * @throws EE_Error
463
+	 * @throws InvalidArgumentException
464
+	 * @throws ReflectionException
465
+	 * @throws InvalidDataTypeException
466
+	 * @throws InvalidInterfaceException
467
+	 * @since 4.5.0
468
+	 */
469
+	protected static function _load_controller()
470
+	{
471
+		if (! self::$_MSG_PROCESSOR instanceof EE_Messages_Processor) {
472
+			EE_Registry::instance()->load_core('Request_Handler');
473
+			self::set_autoloaders();
474
+			self::$_EEMSG                    = EE_Registry::instance()->load_lib('messages');
475
+			self::$_MSG_PROCESSOR            = EE_Registry::instance()->load_lib('Messages_Processor');
476
+			self::$_message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
477
+		}
478
+	}
479
+
480
+
481
+	/**
482
+	 * @param EE_Transaction $transaction
483
+	 * @throws EE_Error
484
+	 * @throws InvalidArgumentException
485
+	 * @throws InvalidDataTypeException
486
+	 * @throws InvalidInterfaceException
487
+	 * @throws ReflectionException
488
+	 */
489
+	public static function payment_reminder(EE_Transaction $transaction)
490
+	{
491
+		self::_load_controller();
492
+		$data = [$transaction, null];
493
+		self::$_MSG_PROCESSOR->generate_for_all_active_messengers('payment_reminder', $data);
494
+	}
495
+
496
+
497
+	/**
498
+	 * Any messages triggers for after successful gateway payments should go in here.
499
+	 *
500
+	 * @param EE_Transaction  $transaction object
501
+	 * @param EE_Payment|null $payment     object
502
+	 * @return void
503
+	 * @throws EE_Error
504
+	 * @throws InvalidArgumentException
505
+	 * @throws ReflectionException
506
+	 * @throws InvalidDataTypeException
507
+	 * @throws InvalidInterfaceException
508
+	 */
509
+	public static function payment(EE_Transaction $transaction, EE_Payment $payment = null)
510
+	{
511
+		// if there's no payment object, then we cannot do a payment type message!
512
+		if (! $payment instanceof EE_Payment) {
513
+			return;
514
+		}
515
+		self::_load_controller();
516
+		$data = [$transaction, $payment];
517
+		EE_Registry::instance()->load_helper('MSG_Template');
518
+		$message_type = EEH_MSG_Template::convert_payment_status_to_message_type($payment->STS_ID());
519
+		// if payment amount is less than 0 then switch to payment_refund message type.
520
+		$message_type = $payment->amount() < 0 ? 'payment_refund' : $message_type;
521
+		self::$_MSG_PROCESSOR->generate_for_all_active_messengers($message_type, $data);
522
+	}
523
+
524
+
525
+	/**
526
+	 * @param EE_Transaction $transaction
527
+	 * @throws EE_Error
528
+	 * @throws InvalidArgumentException
529
+	 * @throws InvalidDataTypeException
530
+	 * @throws InvalidInterfaceException
531
+	 * @throws ReflectionException
532
+	 */
533
+	public static function cancelled_registration(EE_Transaction $transaction)
534
+	{
535
+		self::_load_controller();
536
+		$data = [$transaction, null];
537
+		self::$_MSG_PROCESSOR->generate_for_all_active_messengers('cancelled_registration', $data);
538
+	}
539
+
540
+
541
+	/**
542
+	 * Trigger for Registration messages
543
+	 * Note that what registration message type is sent depends on what the reg status is for the registrations on the
544
+	 * incoming transaction.
545
+	 *
546
+	 * @param EE_Registration $registration
547
+	 * @param array           $extra_details
548
+	 * @return void
549
+	 * @throws EE_Error
550
+	 * @throws InvalidArgumentException
551
+	 * @throws InvalidDataTypeException
552
+	 * @throws InvalidInterfaceException
553
+	 * @throws ReflectionException
554
+	 * @throws EntityNotFoundException
555
+	 */
556
+	public static function maybe_registration(EE_Registration $registration, $extra_details = [])
557
+	{
558
+
559
+		if (! self::_verify_registration_notification_send($registration, $extra_details)) {
560
+			// no messages please
561
+			return;
562
+		}
563
+
564
+		// get all non-trashed registrations so we make sure we send messages for the right status.
565
+		$all_registrations = $registration->transaction()->registrations(
566
+			[
567
+				['REG_deleted' => false],
568
+				'order_by' => [
569
+					'Event.EVT_name'     => 'ASC',
570
+					'Attendee.ATT_lname' => 'ASC',
571
+					'Attendee.ATT_fname' => 'ASC',
572
+				],
573
+			]
574
+		);
575
+		// cached array of statuses so we only trigger messages once per status.
576
+		$statuses_sent = [];
577
+		self::_load_controller();
578
+		$mtgs = [];
579
+
580
+		// loop through registrations and trigger messages once per status.
581
+		foreach ($all_registrations as $reg) {
582
+			// already triggered?
583
+			if (in_array($reg->status_ID(), $statuses_sent)) {
584
+				continue;
585
+			}
586
+
587
+			$message_type    = EEH_MSG_Template::convert_reg_status_to_message_type($reg->status_ID());
588
+			$mtgs            = array_merge(
589
+				$mtgs,
590
+				self::$_MSG_PROCESSOR->setup_mtgs_for_all_active_messengers(
591
+					$message_type,
592
+					[$registration->transaction(), null, $reg->status_ID()]
593
+				)
594
+			);
595
+			$statuses_sent[] = $reg->status_ID();
596
+		}
597
+
598
+		if (count($statuses_sent) > 1) {
599
+			$mtgs = array_merge(
600
+				$mtgs,
601
+				self::$_MSG_PROCESSOR->setup_mtgs_for_all_active_messengers(
602
+					'registration_summary',
603
+					[$registration->transaction(), null]
604
+				)
605
+			);
606
+		}
607
+
608
+		// batch queue and initiate request
609
+		self::$_MSG_PROCESSOR->batch_queue_for_generation_and_persist($mtgs);
610
+		self::$_MSG_PROCESSOR->get_queue()->initiate_request_by_priority();
611
+	}
612
+
613
+
614
+	/**
615
+	 * This is a helper method used to very whether a registration notification should be sent or
616
+	 * not.  Prevents duplicate notifications going out for registration context notifications.
617
+	 *
618
+	 * @param EE_Registration $registration  [description]
619
+	 * @param array           $extra_details [description]
620
+	 * @return bool          true = send away, false = nope halt the presses.
621
+	 */
622
+	protected static function _verify_registration_notification_send(
623
+		EE_Registration $registration,
624
+		$extra_details = []
625
+	) {
626
+		$request = self::getRequest();
627
+		if (
628
+			! $request->getRequestParam('non_primary_reg_notification', 0, 'int')
629
+			&& ! $registration->is_primary_registrant()
630
+		) {
631
+			return false;
632
+		}
633
+		// first we check if we're in admin and not doing front ajax
634
+		if (
635
+			($request->isAdmin() || $request->isAdminAjax())
636
+			&& ! $request->isFrontAjax()
637
+		) {
638
+			$status_change = $request->getRequestParam('txn_reg_status_change', [], 'int', true);
639
+			// make sure appropriate admin params are set for sending messages
640
+			if (
641
+				! isset($status_change['send_notifications'])
642
+				|| (isset($status_change['send_notifications']) && ! $status_change['send_notifications'])
643
+			) {
644
+				// no messages sent please.
645
+				return false;
646
+			}
647
+		} else {
648
+			// frontend request (either regular or via AJAX)
649
+			// TXN is NOT finalized ?
650
+			if (! isset($extra_details['finalized']) || $extra_details['finalized'] === false) {
651
+				return false;
652
+			}
653
+			// return visit but nothing changed ???
654
+			if (
655
+				isset($extra_details['revisit'], $extra_details['status_updates'])
656
+				&& $extra_details['revisit']
657
+				&& ! $extra_details['status_updates']
658
+			) {
659
+				return false;
660
+			}
661
+			// NOT sending messages && reg status is something other than "Not-Approved"
662
+			if (
663
+				! apply_filters('FHEE__EED_Messages___maybe_registration__deliver_notifications', false)
664
+				&& $registration->status_ID() !== EEM_Registration::status_id_not_approved
665
+			) {
666
+				return false;
667
+			}
668
+		}
669
+		// release the kraken
670
+		return true;
671
+	}
672
+
673
+
674
+	/**
675
+	 * Simply returns an array indexed by Registration Status ID and the related message_type name associated with that
676
+	 * status id.
677
+	 *
678
+	 * @param string $reg_status
679
+	 * @return array
680
+	 * @throws EE_Error
681
+	 * @throws InvalidArgumentException
682
+	 * @throws ReflectionException
683
+	 * @throws InvalidDataTypeException
684
+	 * @throws InvalidInterfaceException
685
+	 * @deprecated        4.9.0  Use EEH_MSG_Template::reg_status_to_message_type_array()
686
+	 *                    or EEH_MSG_Template::convert_reg_status_to_message_type
687
+	 */
688
+	protected static function _get_reg_status_array($reg_status = '')
689
+	{
690
+		EE_Registry::instance()->load_helper('MSG_Template');
691
+		return EEH_MSG_Template::convert_reg_status_to_message_type($reg_status)
692
+			? EEH_MSG_Template::convert_reg_status_to_message_type($reg_status)
693
+			: EEH_MSG_Template::reg_status_to_message_type_array();
694
+	}
695
+
696
+
697
+	/**
698
+	 * Simply returns the payment message type for the given payment status.
699
+	 *
700
+	 * @param string $payment_status The payment status being matched.
701
+	 * @return bool|string The payment message type slug matching the status or false if no match.
702
+	 * @throws EE_Error
703
+	 * @throws InvalidArgumentException
704
+	 * @throws ReflectionException
705
+	 * @throws InvalidDataTypeException
706
+	 * @throws InvalidInterfaceException
707
+	 * @deprecated       4.9.0 Use EEH_MSG_Template::payment_status_to_message_type_array
708
+	 *                   or EEH_MSG_Template::convert_payment_status_to_message_type
709
+	 */
710
+	protected static function _get_payment_message_type($payment_status)
711
+	{
712
+		EE_Registry::instance()->load_helper('MSG_Template');
713
+		return EEH_MSG_Template::convert_payment_status_to_message_type($payment_status)
714
+			? EEH_MSG_Template::convert_payment_status_to_message_type($payment_status)
715
+			: false;
716
+	}
717
+
718
+
719
+	/**
720
+	 * Message triggers for a resending already sent message(s) (via EE_Message list table)
721
+	 *
722
+	 * @access public
723
+	 * @param array $req_data This is the $_POST & $_GET data sent from EE_Admin Pages
724
+	 * @return bool success/fail
725
+	 * @throws EE_Error
726
+	 * @throws InvalidArgumentException
727
+	 * @throws InvalidDataTypeException
728
+	 * @throws InvalidInterfaceException
729
+	 * @throws ReflectionException
730
+	 */
731
+	public static function process_resend(array $req_data = [])
732
+	{
733
+		self::_load_controller();
734
+		$request = self::getRequest();
735
+		// if $msgID in this request then skip to the new resend_message
736
+		if ($request->getRequestParam('MSG_ID')) {
737
+			return self::resend_message();
738
+		}
739
+
740
+		// make sure any incoming request data is set on the request so that it gets picked up later.
741
+		foreach ((array) $req_data as $request_key => $request_value) {
742
+			if (! $request->requestParamIsSet($request_key)) {
743
+				$request->setRequestParam($request_key, $request_value);
744
+			}
745
+		}
746
+
747
+		if (
748
+			! $messages_to_send = self::$_MSG_PROCESSOR->setup_messages_to_generate_from_registration_ids_in_request()
749
+		) {
750
+			return false;
751
+		}
752
+
753
+		try {
754
+			self::$_MSG_PROCESSOR->batch_queue_for_generation_and_persist($messages_to_send);
755
+			self::$_MSG_PROCESSOR->get_queue()->initiate_request_by_priority();
756
+		} catch (EE_Error $e) {
757
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
758
+			return false;
759
+		}
760
+		EE_Error::add_success(
761
+			esc_html__('Messages have been successfully queued for generation and sending.', 'event_espresso')
762
+		);
763
+		return true; // everything got queued.
764
+	}
765
+
766
+
767
+	/**
768
+	 * Message triggers for a resending already sent message(s) (via EE_Message list table)
769
+	 *
770
+	 * @return bool
771
+	 * @throws EE_Error
772
+	 * @throws InvalidArgumentException
773
+	 * @throws InvalidDataTypeException
774
+	 * @throws InvalidInterfaceException
775
+	 * @throws ReflectionException
776
+	 */
777
+	public static function resend_message()
778
+	{
779
+		self::_load_controller();
780
+
781
+		$msgID = self::getRequest()->getRequestParam('MSG_ID', 0, 'int');
782
+		if (! $msgID) {
783
+			EE_Error::add_error(
784
+				esc_html__(
785
+					'Something went wrong because there is no "MSG_ID" value in the request',
786
+					'event_espresso'
787
+				),
788
+				__FILE__,
789
+				__FUNCTION__,
790
+				__LINE__
791
+			);
792
+			return false;
793
+		}
794
+
795
+		self::$_MSG_PROCESSOR->setup_messages_from_ids_and_send((array) $msgID);
796
+
797
+		// setup success message.
798
+		$count_ready_for_resend = self::$_MSG_PROCESSOR->get_queue()->count_STS_in_queue(EEM_Message::status_resend);
799
+		EE_Error::add_success(
800
+			sprintf(
801
+				_n(
802
+					'There was %d message queued for resending.',
803
+					'There were %d messages queued for resending.',
804
+					$count_ready_for_resend,
805
+					'event_espresso'
806
+				),
807
+				$count_ready_for_resend
808
+			)
809
+		);
810
+		return true;
811
+	}
812
+
813
+
814
+	/**
815
+	 * Message triggers for manual payment applied by admin
816
+	 *
817
+	 * @param EE_Payment $payment EE_payment object
818
+	 * @return bool success/fail
819
+	 * @throws EE_Error
820
+	 * @throws InvalidArgumentException
821
+	 * @throws ReflectionException
822
+	 * @throws InvalidDataTypeException
823
+	 * @throws InvalidInterfaceException
824
+	 */
825
+	public static function process_admin_payment(EE_Payment $payment)
826
+	{
827
+		EE_Registry::instance()->load_helper('MSG_Template');
828
+		// we need to get the transaction object
829
+		$transaction = $payment->transaction();
830
+		if ($transaction instanceof EE_Transaction) {
831
+			$data         = [$transaction, $payment];
832
+			$message_type = EEH_MSG_Template::convert_payment_status_to_message_type($payment->STS_ID());
833
+
834
+			// if payment amount is less than 0 then switch to payment_refund message type.
835
+			$message_type = $payment->amount() < 0 ? 'payment_refund' : $message_type;
836
+
837
+			// if payment_refund is selected, but the status is NOT accepted.  Then change message type to false so NO message notification goes out.
838
+			$message_type = $message_type == 'payment_refund' && $payment->STS_ID() != EEM_Payment::status_id_approved
839
+				? false : $message_type;
840
+
841
+			self::_load_controller();
842
+
843
+			self::$_MSG_PROCESSOR->generate_for_all_active_messengers($message_type, $data);
844
+
845
+			// get count of queued for generation
846
+			$count_to_generate = self::$_MSG_PROCESSOR->get_queue()->count_STS_in_queue(
847
+				[
848
+					EEM_Message::status_incomplete,
849
+					EEM_Message::status_idle,
850
+				]
851
+			);
852
+
853
+			if ($count_to_generate > 0 && self::$_MSG_PROCESSOR->get_queue()->get_message_repository()->count() !== 0) {
854
+				add_filter('FHEE__EE_Admin_Page___process_admin_payment_notification__success', '__return_true');
855
+				return true;
856
+			} else {
857
+				$count_failed = self::$_MSG_PROCESSOR->get_queue()->count_STS_in_queue(
858
+					EEM_Message::instance()->stati_indicating_failed_sending()
859
+				);
860
+				/**
861
+				 * Verify that there are actually errors.  If not then we return a success message because the queue might have been emptied due to successful
862
+				 * IMMEDIATE generation.
863
+				 */
864
+				if ($count_failed > 0) {
865
+					EE_Error::add_error(
866
+						sprintf(
867
+							_n(
868
+								'The payment notification generation failed.',
869
+								'%d payment notifications failed being sent.',
870
+								$count_failed,
871
+								'event_espresso'
872
+							),
873
+							$count_failed
874
+						),
875
+						__FILE__,
876
+						__FUNCTION__,
877
+						__LINE__
878
+					);
879
+
880
+					return false;
881
+				} else {
882
+					add_filter('FHEE__EE_Admin_Page___process_admin_payment_notification__success', '__return_true');
883
+					return true;
884
+				}
885
+			}
886
+		} else {
887
+			EE_Error::add_error(
888
+				'Unable to generate the payment notification because the given value for the transaction is invalid.',
889
+				'event_espresso'
890
+			);
891
+			return false;
892
+		}
893
+	}
894
+
895
+
896
+	/**
897
+	 * Callback for AHEE__Extend_Registrations_Admin_Page___newsletter_selected_send_with_registrations trigger
898
+	 *
899
+	 * @param EE_Registration[] $registrations an array of EE_Registration objects
900
+	 * @param int               $grp_id        a specific message template group id.
901
+	 * @return void
902
+	 * @throws EE_Error
903
+	 * @throws InvalidArgumentException
904
+	 * @throws InvalidDataTypeException
905
+	 * @throws InvalidInterfaceException
906
+	 * @throws ReflectionException
907
+	 * @since   4.3.0
908
+	 */
909
+	public static function send_newsletter_message($registrations, $grp_id)
910
+	{
911
+		// make sure mtp is id and set it in the request later messages setup.
912
+		self::getRequest()->setRequestParam('GRP_ID', (int) $grp_id);
913
+		self::_load_controller();
914
+		self::$_MSG_PROCESSOR->generate_for_all_active_messengers('newsletter', $registrations);
915
+	}
916
+
917
+
918
+	/**
919
+	 * Callback for FHEE__EE_Registration__invoice_url__invoice_url or FHEE__EE_Registration__receipt_url__receipt_url
920
+	 *
921
+	 * @param string          $registration_message_trigger_url
922
+	 * @param EE_Registration $registration
923
+	 * @param string          $messenger
924
+	 * @param string          $message_type
925
+	 * @return string
926
+	 * @throws EE_Error
927
+	 * @throws InvalidArgumentException
928
+	 * @throws InvalidDataTypeException
929
+	 * @throws InvalidInterfaceException
930
+	 * @since   4.3.0
931
+	 */
932
+	public static function registration_message_trigger_url(
933
+		$registration_message_trigger_url,
934
+		EE_Registration $registration,
935
+		$messenger = 'html',
936
+		$message_type = 'invoice'
937
+	) {
938
+		// whitelist $messenger
939
+		switch ($messenger) {
940
+			case 'pdf':
941
+				$sending_messenger    = 'pdf';
942
+				$generating_messenger = 'html';
943
+				break;
944
+			case 'html':
945
+			default:
946
+				$sending_messenger    = 'html';
947
+				$generating_messenger = 'html';
948
+				break;
949
+		}
950
+		// whitelist $message_type
951
+		switch ($message_type) {
952
+			case 'receipt':
953
+				$message_type = 'receipt';
954
+				break;
955
+			case 'invoice':
956
+			default:
957
+				$message_type = 'invoice';
958
+				break;
959
+		}
960
+		// verify that both the messenger AND the message type are active
961
+		if (
962
+			EEH_MSG_Template::is_messenger_active($sending_messenger)
963
+			&& EEH_MSG_Template::is_mt_active($message_type)
964
+		) {
965
+			// need to get the correct message template group for this (i.e. is there a custom invoice for the event this registration is registered for?)
966
+			$template_query_params = [
967
+				'MTP_is_active'    => true,
968
+				'MTP_messenger'    => $generating_messenger,
969
+				'MTP_message_type' => $message_type,
970
+				'Event.EVT_ID'     => $registration->event_ID(),
971
+			];
972
+			// get the message template group.
973
+			$msg_template_group = EEM_Message_Template_Group::instance()->get_one([$template_query_params]);
974
+			// if we don't have an EE_Message_Template_Group then return
975
+			if (! $msg_template_group instanceof EE_Message_Template_Group) {
976
+				// remove EVT_ID from query params so that global templates get picked up
977
+				unset($template_query_params['Event.EVT_ID']);
978
+				// get global template as the fallback
979
+				$msg_template_group = EEM_Message_Template_Group::instance()->get_one([$template_query_params]);
980
+			}
981
+			// if we don't have an EE_Message_Template_Group then return
982
+			if (! $msg_template_group instanceof EE_Message_Template_Group) {
983
+				return '';
984
+			}
985
+			// generate the URL
986
+			$registration_message_trigger_url = EEH_MSG_Template::generate_url_trigger(
987
+				$sending_messenger,
988
+				$generating_messenger,
989
+				'purchaser',
990
+				$message_type,
991
+				$registration,
992
+				$msg_template_group->ID(),
993
+				$registration->transaction_ID()
994
+			);
995
+		}
996
+		return $registration_message_trigger_url;
997
+	}
998
+
999
+
1000
+	/**
1001
+	 * Use to generate and return a message preview!
1002
+	 *
1003
+	 * @param string $type       This should correspond with a valid message type
1004
+	 * @param string $context    This should correspond with a valid context for the message type
1005
+	 * @param string $messenger  This should correspond with a valid messenger.
1006
+	 * @param bool   $send       true we will do a test send using the messenger delivery, false we just do a regular
1007
+	 *                           preview
1008
+	 * @return bool|string The body of the message or if send is requested, sends.
1009
+	 * @throws EE_Error
1010
+	 * @throws InvalidArgumentException
1011
+	 * @throws InvalidDataTypeException
1012
+	 * @throws InvalidInterfaceException
1013
+	 * @throws ReflectionException
1014
+	 */
1015
+	public static function preview_message($type, $context, $messenger, $send = false)
1016
+	{
1017
+		self::_load_controller();
1018
+		$message_to_generate     = new EE_Message_To_Generate(
1019
+			$messenger,
1020
+			$type,
1021
+			[],
1022
+			$context,
1023
+			true
1024
+		);
1025
+		$generated_preview_queue = self::$_MSG_PROCESSOR->generate_for_preview($message_to_generate, $send);
1026
+
1027
+		if ($generated_preview_queue instanceof EE_Messages_Queue) {
1028
+			// loop through all content for the preview and remove any persisted records.
1029
+			$content = '';
1030
+			foreach ($generated_preview_queue->get_message_repository() as $message) {
1031
+				$content = $message->content();
1032
+				if ($message->ID() > 0 && $message->STS_ID() !== EEM_Message::status_failed) {
1033
+					$message->delete();
1034
+				}
1035
+			}
1036
+			return $content;
1037
+		}
1038
+		return $generated_preview_queue;
1039
+	}
1040
+
1041
+
1042
+	/**
1043
+	 * This is a method that allows for sending a message using a messenger matching the string given and the provided
1044
+	 * EE_Message_Queue object.  The EE_Message_Queue object is used to create a single aggregate EE_Message via the
1045
+	 * content found in the EE_Message objects in the queue.
1046
+	 *
1047
+	 * @param string            $messenger            a string matching a valid active messenger in the system
1048
+	 * @param string            $message_type         Although it seems contrary to the name of the method, a message
1049
+	 *                                                type name is still required to send along the message type to the
1050
+	 *                                                messenger because this is used for determining what specific
1051
+	 *                                                variations might be loaded for the generated message.
1052
+	 * @param EE_Messages_Queue $queue
1053
+	 * @param string            $custom_subject       Can be used to set what the custom subject string will be on the
1054
+	 *                                                aggregate EE_Message object.
1055
+	 * @return bool success or fail.
1056
+	 * @throws EE_Error
1057
+	 * @throws InvalidArgumentException
1058
+	 * @throws ReflectionException
1059
+	 * @throws InvalidDataTypeException
1060
+	 * @throws InvalidInterfaceException
1061
+	 * @since 4.9.0
1062
+	 */
1063
+	public static function send_message_with_messenger_only(
1064
+		$messenger,
1065
+		$message_type,
1066
+		EE_Messages_Queue $queue,
1067
+		$custom_subject = ''
1068
+	) {
1069
+		self::_load_controller();
1070
+		/** @type EE_Message_To_Generate_From_Queue $message_to_generate */
1071
+		$message_to_generate = EE_Registry::instance()->load_lib(
1072
+			'Message_To_Generate_From_Queue',
1073
+			[
1074
+				$messenger,
1075
+				$message_type,
1076
+				$queue,
1077
+				$custom_subject,
1078
+			]
1079
+		);
1080
+		return self::$_MSG_PROCESSOR->queue_for_sending($message_to_generate);
1081
+	}
1082
+
1083
+
1084
+	/**
1085
+	 * Generates Messages immediately for EE_Message IDs (but only for the correct status for generation)
1086
+	 *
1087
+	 * @param array $message_ids An array of message ids
1088
+	 * @return bool|EE_Messages_Queue false if nothing was generated, EE_Messages_Queue containing generated
1089
+	 *                           messages.
1090
+	 * @throws EE_Error
1091
+	 * @throws InvalidArgumentException
1092
+	 * @throws InvalidDataTypeException
1093
+	 * @throws InvalidInterfaceException
1094
+	 * @throws ReflectionException
1095
+	 * @since 4.9.0
1096
+	 */
1097
+	public static function generate_now($message_ids)
1098
+	{
1099
+		self::_load_controller();
1100
+		$messages        = EEM_Message::instance()->get_all(
1101
+			[
1102
+				0 => [
1103
+					'MSG_ID' => ['IN', $message_ids],
1104
+					'STS_ID' => EEM_Message::status_incomplete,
1105
+				],
1106
+			]
1107
+		);
1108
+		$generated_queue = false;
1109
+		if ($messages) {
1110
+			$generated_queue = self::$_MSG_PROCESSOR->batch_generate_from_queue($messages);
1111
+		}
1112
+
1113
+		if (! $generated_queue instanceof EE_Messages_Queue) {
1114
+			EE_Error::add_error(
1115
+				esc_html__(
1116
+					'The messages were not generated. This could mean there is already a batch being generated on a separate request, or because the selected messages are not ready for generation. Please wait a minute or two and try again.',
1117
+					'event_espresso'
1118
+				),
1119
+				__FILE__,
1120
+				__FUNCTION__,
1121
+				__LINE__
1122
+			);
1123
+		}
1124
+		return $generated_queue;
1125
+	}
1126
+
1127
+
1128
+	/**
1129
+	 * Sends messages immediately for the incoming message_ids that have the status of EEM_Message::status_resend or,
1130
+	 * EEM_Message::status_idle
1131
+	 *
1132
+	 * @param $message_ids
1133
+	 * @return bool|EE_Messages_Queue false if no messages sent.
1134
+	 * @throws EE_Error
1135
+	 * @throws InvalidArgumentException
1136
+	 * @throws InvalidDataTypeException
1137
+	 * @throws InvalidInterfaceException
1138
+	 * @throws ReflectionException
1139
+	 * @since 4.9.0
1140
+	 */
1141
+	public static function send_now($message_ids)
1142
+	{
1143
+		self::_load_controller();
1144
+		$messages   = EEM_Message::instance()->get_all(
1145
+			[
1146
+				0 => [
1147
+					'MSG_ID' => ['IN', $message_ids],
1148
+					'STS_ID' => [
1149
+						'IN',
1150
+						[EEM_Message::status_idle, EEM_Message::status_resend, EEM_Message::status_retry],
1151
+					],
1152
+				],
1153
+			]
1154
+		);
1155
+		$sent_queue = false;
1156
+		if ($messages) {
1157
+			$sent_queue = self::$_MSG_PROCESSOR->batch_send_from_queue($messages);
1158
+		}
1159
+
1160
+		if (! $sent_queue instanceof EE_Messages_Queue) {
1161
+			EE_Error::add_error(
1162
+				esc_html__(
1163
+					'The messages were not sent. This could mean there is already a batch being sent on a separate request, or because the selected messages are not sendable. Please wait a minute or two and try again.',
1164
+					'event_espresso'
1165
+				),
1166
+				__FILE__,
1167
+				__FUNCTION__,
1168
+				__LINE__
1169
+			);
1170
+		} else {
1171
+			// can count how many sent by using the messages in the queue
1172
+			$sent_count = $sent_queue->count_STS_in_queue(EEM_Message::instance()->stati_indicating_sent());
1173
+			if ($sent_count > 0) {
1174
+				EE_Error::add_success(
1175
+					sprintf(
1176
+						_n(
1177
+							'There was %d message successfully sent.',
1178
+							'There were %d messages successfully sent.',
1179
+							$sent_count,
1180
+							'event_espresso'
1181
+						),
1182
+						$sent_count
1183
+					)
1184
+				);
1185
+			} else {
1186
+				EE_Error::overwrite_errors();
1187
+				EE_Error::add_error(
1188
+					esc_html__(
1189
+						'No message was sent because of problems with sending. Either all the messages you selected were not a sendable message, they were ALREADY sent on a different scheduled task, or there was an error.
1190 1190
 					If there was an error, you can look at the messages in the message activity list table for any error messages.',
1191
-                        'event_espresso'
1192
-                    ),
1193
-                    __FILE__,
1194
-                    __FUNCTION__,
1195
-                    __LINE__
1196
-                );
1197
-            }
1198
-        }
1199
-        return $sent_queue;
1200
-    }
1201
-
1202
-
1203
-    /**
1204
-     * Generate and send immediately from the given $message_ids
1205
-     *
1206
-     * @param array $message_ids EE_Message entity ids.
1207
-     * @throws EE_Error
1208
-     * @throws InvalidArgumentException
1209
-     * @throws InvalidDataTypeException
1210
-     * @throws InvalidInterfaceException
1211
-     * @throws ReflectionException
1212
-     */
1213
-    public static function generate_and_send_now(array $message_ids)
1214
-    {
1215
-        $generated_queue = self::generate_now($message_ids);
1216
-        // now let's just trigger sending immediately from this queue.
1217
-        $messages_sent = $generated_queue instanceof EE_Messages_Queue
1218
-            ? $generated_queue->execute()
1219
-            : 0;
1220
-        if ($messages_sent) {
1221
-            EE_Error::add_success(
1222
-                esc_html(
1223
-                    sprintf(
1224
-                        _n(
1225
-                            'There was %d message successfully generated and sent.',
1226
-                            'There were %d messages successfully generated and sent.',
1227
-                            $messages_sent,
1228
-                            'event_espresso'
1229
-                        ),
1230
-                        $messages_sent
1231
-                    )
1232
-                )
1233
-            );
1234
-            // errors would be added via the generate_now method.
1235
-        }
1236
-    }
1237
-
1238
-
1239
-    /**
1240
-     * This will queue the incoming message ids for resending.
1241
-     * Note, only message_ids corresponding to messages with the status of EEM_Message::sent will be queued.
1242
-     *
1243
-     * @param array $message_ids An array of EE_Message IDs
1244
-     * @return bool true means messages were successfully queued for resending, false means none were queued for
1245
-     *                           resending.
1246
-     * @throws EE_Error
1247
-     * @throws InvalidArgumentException
1248
-     * @throws InvalidDataTypeException
1249
-     * @throws InvalidInterfaceException
1250
-     * @throws ReflectionException
1251
-     * @since 4.9.0
1252
-     */
1253
-    public static function queue_for_resending($message_ids)
1254
-    {
1255
-        self::_load_controller();
1256
-        self::$_MSG_PROCESSOR->setup_messages_from_ids_and_send($message_ids);
1257
-
1258
-        // get queue and count
1259
-        $queue_count = self::$_MSG_PROCESSOR->get_queue()->count_STS_in_queue(EEM_Message::status_resend);
1260
-
1261
-        if (
1262
-            $queue_count > 0
1263
-        ) {
1264
-            EE_Error::add_success(
1265
-                sprintf(
1266
-                    _n(
1267
-                        '%d message successfully queued for resending.',
1268
-                        '%d messages successfully queued for resending.',
1269
-                        $queue_count,
1270
-                        'event_espresso'
1271
-                    ),
1272
-                    $queue_count
1273
-                )
1274
-            );
1275
-            /**
1276
-             * @see filter usage in EE_Messages_Queue::initiate_request_by_priority
1277
-             */
1278
-        } elseif (
1279
-            apply_filters('FHEE__EE_Messages_Processor__initiate_request_by_priority__do_immediate_processing', true)
1280
-            || EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request
1281
-        ) {
1282
-            $queue_count = self::$_MSG_PROCESSOR->get_queue()->count_STS_in_queue(EEM_Message::status_sent);
1283
-            if ($queue_count > 0) {
1284
-                EE_Error::add_success(
1285
-                    sprintf(
1286
-                        _n(
1287
-                            '%d message successfully sent.',
1288
-                            '%d messages successfully sent.',
1289
-                            $queue_count,
1290
-                            'event_espresso'
1291
-                        ),
1292
-                        $queue_count
1293
-                    )
1294
-                );
1295
-            } else {
1296
-                EE_Error::add_error(
1297
-                    esc_html__(
1298
-                        'No messages were queued for resending. This usually only happens when all the messages flagged for resending are not a status that can be resent.',
1299
-                        'event_espresso'
1300
-                    ),
1301
-                    __FILE__,
1302
-                    __FUNCTION__,
1303
-                    __LINE__
1304
-                );
1305
-            }
1306
-        } else {
1307
-            EE_Error::add_error(
1308
-                esc_html__(
1309
-                    'No messages were queued for resending. This usually only happens when all the messages flagged for resending are not a status that can be resent.',
1310
-                    'event_espresso'
1311
-                ),
1312
-                __FILE__,
1313
-                __FUNCTION__,
1314
-                __LINE__
1315
-            );
1316
-        }
1317
-        return (bool) $queue_count;
1318
-    }
1319
-
1320
-
1321
-    /**
1322
-     * debug
1323
-     *
1324
-     * @param string          $class
1325
-     * @param string          $func
1326
-     * @param string          $line
1327
-     * @param \EE_Transaction $transaction
1328
-     * @param array           $info
1329
-     * @param bool            $display_request
1330
-     * @throws EE_Error
1331
-     * @throws \EventEspresso\core\exceptions\InvalidSessionDataException
1332
-     */
1333
-    protected static function log(
1334
-        $class = '',
1335
-        $func = '',
1336
-        $line = '',
1337
-        EE_Transaction $transaction = null,
1338
-        $info = [],
1339
-        $display_request = false
1340
-    ) {
1341
-        if (defined('EE_DEBUG') && EE_DEBUG) {
1342
-            if ($transaction instanceof EE_Transaction) {
1343
-                // don't serialize objects
1344
-                $info                  = EEH_Debug_Tools::strip_objects($info);
1345
-                $info['TXN_status']    = $transaction->status_ID();
1346
-                $info['TXN_reg_steps'] = $transaction->reg_steps();
1347
-                if ($transaction->ID()) {
1348
-                    $index = 'EE_Transaction: ' . $transaction->ID();
1349
-                    EEH_Debug_Tools::log($class, $func, $line, $info, $display_request, $index);
1350
-                }
1351
-            }
1352
-        }
1353
-    }
1354
-
1355
-
1356
-    /**
1357
-     *  Resets all the static properties in this class when called.
1358
-     */
1359
-    public static function reset()
1360
-    {
1361
-        self::$_EEMSG                    = null;
1362
-        self::$_message_resource_manager = null;
1363
-        self::$_MSG_PROCESSOR            = null;
1364
-        self::$_MSG_PATHS                = null;
1365
-        self::$_TMP_PACKS                = [];
1366
-    }
1191
+						'event_espresso'
1192
+					),
1193
+					__FILE__,
1194
+					__FUNCTION__,
1195
+					__LINE__
1196
+				);
1197
+			}
1198
+		}
1199
+		return $sent_queue;
1200
+	}
1201
+
1202
+
1203
+	/**
1204
+	 * Generate and send immediately from the given $message_ids
1205
+	 *
1206
+	 * @param array $message_ids EE_Message entity ids.
1207
+	 * @throws EE_Error
1208
+	 * @throws InvalidArgumentException
1209
+	 * @throws InvalidDataTypeException
1210
+	 * @throws InvalidInterfaceException
1211
+	 * @throws ReflectionException
1212
+	 */
1213
+	public static function generate_and_send_now(array $message_ids)
1214
+	{
1215
+		$generated_queue = self::generate_now($message_ids);
1216
+		// now let's just trigger sending immediately from this queue.
1217
+		$messages_sent = $generated_queue instanceof EE_Messages_Queue
1218
+			? $generated_queue->execute()
1219
+			: 0;
1220
+		if ($messages_sent) {
1221
+			EE_Error::add_success(
1222
+				esc_html(
1223
+					sprintf(
1224
+						_n(
1225
+							'There was %d message successfully generated and sent.',
1226
+							'There were %d messages successfully generated and sent.',
1227
+							$messages_sent,
1228
+							'event_espresso'
1229
+						),
1230
+						$messages_sent
1231
+					)
1232
+				)
1233
+			);
1234
+			// errors would be added via the generate_now method.
1235
+		}
1236
+	}
1237
+
1238
+
1239
+	/**
1240
+	 * This will queue the incoming message ids for resending.
1241
+	 * Note, only message_ids corresponding to messages with the status of EEM_Message::sent will be queued.
1242
+	 *
1243
+	 * @param array $message_ids An array of EE_Message IDs
1244
+	 * @return bool true means messages were successfully queued for resending, false means none were queued for
1245
+	 *                           resending.
1246
+	 * @throws EE_Error
1247
+	 * @throws InvalidArgumentException
1248
+	 * @throws InvalidDataTypeException
1249
+	 * @throws InvalidInterfaceException
1250
+	 * @throws ReflectionException
1251
+	 * @since 4.9.0
1252
+	 */
1253
+	public static function queue_for_resending($message_ids)
1254
+	{
1255
+		self::_load_controller();
1256
+		self::$_MSG_PROCESSOR->setup_messages_from_ids_and_send($message_ids);
1257
+
1258
+		// get queue and count
1259
+		$queue_count = self::$_MSG_PROCESSOR->get_queue()->count_STS_in_queue(EEM_Message::status_resend);
1260
+
1261
+		if (
1262
+			$queue_count > 0
1263
+		) {
1264
+			EE_Error::add_success(
1265
+				sprintf(
1266
+					_n(
1267
+						'%d message successfully queued for resending.',
1268
+						'%d messages successfully queued for resending.',
1269
+						$queue_count,
1270
+						'event_espresso'
1271
+					),
1272
+					$queue_count
1273
+				)
1274
+			);
1275
+			/**
1276
+			 * @see filter usage in EE_Messages_Queue::initiate_request_by_priority
1277
+			 */
1278
+		} elseif (
1279
+			apply_filters('FHEE__EE_Messages_Processor__initiate_request_by_priority__do_immediate_processing', true)
1280
+			|| EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request
1281
+		) {
1282
+			$queue_count = self::$_MSG_PROCESSOR->get_queue()->count_STS_in_queue(EEM_Message::status_sent);
1283
+			if ($queue_count > 0) {
1284
+				EE_Error::add_success(
1285
+					sprintf(
1286
+						_n(
1287
+							'%d message successfully sent.',
1288
+							'%d messages successfully sent.',
1289
+							$queue_count,
1290
+							'event_espresso'
1291
+						),
1292
+						$queue_count
1293
+					)
1294
+				);
1295
+			} else {
1296
+				EE_Error::add_error(
1297
+					esc_html__(
1298
+						'No messages were queued for resending. This usually only happens when all the messages flagged for resending are not a status that can be resent.',
1299
+						'event_espresso'
1300
+					),
1301
+					__FILE__,
1302
+					__FUNCTION__,
1303
+					__LINE__
1304
+				);
1305
+			}
1306
+		} else {
1307
+			EE_Error::add_error(
1308
+				esc_html__(
1309
+					'No messages were queued for resending. This usually only happens when all the messages flagged for resending are not a status that can be resent.',
1310
+					'event_espresso'
1311
+				),
1312
+				__FILE__,
1313
+				__FUNCTION__,
1314
+				__LINE__
1315
+			);
1316
+		}
1317
+		return (bool) $queue_count;
1318
+	}
1319
+
1320
+
1321
+	/**
1322
+	 * debug
1323
+	 *
1324
+	 * @param string          $class
1325
+	 * @param string          $func
1326
+	 * @param string          $line
1327
+	 * @param \EE_Transaction $transaction
1328
+	 * @param array           $info
1329
+	 * @param bool            $display_request
1330
+	 * @throws EE_Error
1331
+	 * @throws \EventEspresso\core\exceptions\InvalidSessionDataException
1332
+	 */
1333
+	protected static function log(
1334
+		$class = '',
1335
+		$func = '',
1336
+		$line = '',
1337
+		EE_Transaction $transaction = null,
1338
+		$info = [],
1339
+		$display_request = false
1340
+	) {
1341
+		if (defined('EE_DEBUG') && EE_DEBUG) {
1342
+			if ($transaction instanceof EE_Transaction) {
1343
+				// don't serialize objects
1344
+				$info                  = EEH_Debug_Tools::strip_objects($info);
1345
+				$info['TXN_status']    = $transaction->status_ID();
1346
+				$info['TXN_reg_steps'] = $transaction->reg_steps();
1347
+				if ($transaction->ID()) {
1348
+					$index = 'EE_Transaction: ' . $transaction->ID();
1349
+					EEH_Debug_Tools::log($class, $func, $line, $info, $display_request, $index);
1350
+				}
1351
+			}
1352
+		}
1353
+	}
1354
+
1355
+
1356
+	/**
1357
+	 *  Resets all the static properties in this class when called.
1358
+	 */
1359
+	public static function reset()
1360
+	{
1361
+		self::$_EEMSG                    = null;
1362
+		self::$_message_resource_manager = null;
1363
+		self::$_MSG_PROCESSOR            = null;
1364
+		self::$_MSG_PATHS                = null;
1365
+		self::$_TMP_PACKS                = [];
1366
+	}
1367 1367
 }
Please login to merge, or discard this patch.
caffeinated/admin/new/pricing/espresso_events_Pricing_Hooks.class.php 2 patches
Spacing   +88 added lines, -88 removed lines patch added patch discarded remove patch
@@ -76,7 +76,7 @@  discard block
 block discarded – undo
76 76
     protected function _setup_metaboxes()
77 77
     {
78 78
         // if we were going to add our own metaboxes we'd use the below.
79
-        $this->_metaboxes        = [
79
+        $this->_metaboxes = [
80 80
             0 => [
81 81
                 'page_route' => ['edit', 'create_new'],
82 82
                 'func'       => [$this, 'pricing_metabox'],
@@ -119,7 +119,7 @@  discard block
 block discarded – undo
119 119
         $this->_date_format_strings['date'] = $this->_date_format_strings['date'] ?? '';
120 120
         $this->_date_format_strings['time'] = $this->_date_format_strings['time'] ?? '';
121 121
 
122
-        $this->_date_time_format = $this->_date_format_strings['date'] . ' ' . $this->_date_format_strings['time'];
122
+        $this->_date_time_format = $this->_date_format_strings['date'].' '.$this->_date_format_strings['time'];
123 123
     }
124 124
 
125 125
 
@@ -143,7 +143,7 @@  discard block
 block discarded – undo
143 143
             );
144 144
             $msg .= '</p><ul>';
145 145
             foreach ($format_validation as $error) {
146
-                $msg .= '<li>' . $error . '</li>';
146
+                $msg .= '<li>'.$error.'</li>';
147 147
             }
148 148
             $msg .= '</ul><p>';
149 149
             $msg .= sprintf(
@@ -172,11 +172,11 @@  discard block
 block discarded – undo
172 172
         $this->_scripts_styles = [
173 173
             'registers'   => [
174 174
                 'ee-tickets-datetimes-css' => [
175
-                    'url'  => PRICING_ASSETS_URL . 'event-tickets-datetimes.css',
175
+                    'url'  => PRICING_ASSETS_URL.'event-tickets-datetimes.css',
176 176
                     'type' => 'css',
177 177
                 ],
178 178
                 'ee-dtt-ticket-metabox'    => [
179
-                    'url'     => PRICING_ASSETS_URL . 'ee-datetime-ticket-metabox.js',
179
+                    'url'     => PRICING_ASSETS_URL.'ee-datetime-ticket-metabox.js',
180 180
                     'depends' => ['ee-datepicker', 'ee-dialog', 'underscore'],
181 181
                 ],
182 182
             ],
@@ -201,11 +201,11 @@  discard block
 block discarded – undo
201 201
                         ),
202 202
                         'cancel_button'           => '
203 203
                             <button class="button--secondary ee-modal-cancel">
204
-                                ' . esc_html__('Cancel', 'event_espresso') . '
204
+                                ' . esc_html__('Cancel', 'event_espresso').'
205 205
                             </button>',
206 206
                         'close_button'            => '
207 207
                             <button class="button--secondary ee-modal-cancel">
208
-                                ' . esc_html__('Close', 'event_espresso') . '
208
+                                ' . esc_html__('Close', 'event_espresso').'
209 209
                             </button>',
210 210
                         'single_warning_from_tkt' => esc_html__(
211 211
                             'The Datetime you are attempting to unassign from this ticket is the only remaining datetime for this ticket. Tickets must always have at least one datetime assigned to them.',
@@ -217,7 +217,7 @@  discard block
 block discarded – undo
217 217
                         ),
218 218
                         'dismiss_button'          => '
219 219
                             <button class="button--secondary ee-modal-cancel">
220
-                                ' . esc_html__('Dismiss', 'event_espresso') . '
220
+                                ' . esc_html__('Dismiss', 'event_espresso').'
221 221
                             </button>',
222 222
                     ],
223 223
                     'DTT_ERROR_MSG'         => [
@@ -225,7 +225,7 @@  discard block
 block discarded – undo
225 225
                         'dismiss_button' => '
226 226
                             <div class="save-cancel-button-container">
227 227
                                 <button class="button--secondary ee-modal-cancel">
228
-                                    ' . esc_html__('Dismiss', 'event_espresso') . '
228
+                                    ' . esc_html__('Dismiss', 'event_espresso').'
229 229
                                 </button>
230 230
                             </div>',
231 231
                     ],
@@ -311,8 +311,8 @@  discard block
 block discarded – undo
311 311
         }
312 312
         foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
313 313
             // trim all values to ensure any excess whitespace is removed.
314
-            $datetime_data                = array_map(
315
-                function ($datetime_data) {
314
+            $datetime_data = array_map(
315
+                function($datetime_data) {
316 316
                     return is_array($datetime_data) ? $datetime_data : trim($datetime_data);
317 317
                 },
318 318
                 $datetime_data
@@ -323,7 +323,7 @@  discard block
 block discarded – undo
323 323
                 ? $datetime_data['DTT_EVT_end']
324 324
                 : $datetime_data['DTT_EVT_start'];
325 325
 
326
-            $datetime_values              = [
326
+            $datetime_values = [
327 327
                 'DTT_ID'          => ! empty($datetime_data['DTT_ID'])
328 328
                     ? $datetime_data['DTT_ID']
329 329
                     : null,
@@ -345,7 +345,7 @@  discard block
 block discarded – undo
345 345
 
346 346
             // if we have an id then let's get existing object first and then set the new values.
347 347
             // Otherwise we instantiate a new object for save.
348
-            if (! empty($datetime_data['DTT_ID'])) {
348
+            if ( ! empty($datetime_data['DTT_ID'])) {
349 349
                 $datetime = EEM_Datetime::instance($timezone)->get_one_by_ID($datetime_data['DTT_ID']);
350 350
                 // set date and time format according to what is set in this class.
351 351
                 $datetime->set_date_format($this->_date_format_strings['date']);
@@ -358,7 +358,7 @@  discard block
 block discarded – undo
358 358
                 // after the add_relation_to() the autosave replaces it.
359 359
                 // We need to do this so we dont' TRASH the parent DTT.
360 360
                 // (save the ID for both key and value to avoid duplications)
361
-                $saved_datetime_ids[ $datetime->ID() ] = $datetime->ID();
361
+                $saved_datetime_ids[$datetime->ID()] = $datetime->ID();
362 362
             } else {
363 363
                 $datetime = EE_Datetime::new_instance(
364 364
                     $datetime_values,
@@ -389,8 +389,8 @@  discard block
 block discarded – undo
389 389
             // because it is possible there was a new one created for the autosave.
390 390
             // (save the ID for both key and value to avoid duplications)
391 391
             $DTT_ID                        = $datetime->ID();
392
-            $saved_datetime_ids[ $DTT_ID ] = $DTT_ID;
393
-            $saved_datetime_objs[ $row ]   = $datetime;
392
+            $saved_datetime_ids[$DTT_ID] = $DTT_ID;
393
+            $saved_datetime_objs[$row]   = $datetime;
394 394
             // @todo if ANY of these updates fail then we want the appropriate global error message.
395 395
         }
396 396
         $event->save();
@@ -454,13 +454,13 @@  discard block
 block discarded – undo
454 454
             $update_prices = $create_new_TKT = false;
455 455
             // figure out what datetimes were added to the ticket
456 456
             // and what datetimes were removed from the ticket in the session.
457
-            $starting_ticket_datetime_rows = explode(',', $data['starting_ticket_datetime_rows'][ $row ]);
458
-            $ticket_datetime_rows          = explode(',', $data['ticket_datetime_rows'][ $row ]);
457
+            $starting_ticket_datetime_rows = explode(',', $data['starting_ticket_datetime_rows'][$row]);
458
+            $ticket_datetime_rows          = explode(',', $data['ticket_datetime_rows'][$row]);
459 459
             $datetimes_added               = array_diff($ticket_datetime_rows, $starting_ticket_datetime_rows);
460 460
             $datetimes_removed             = array_diff($starting_ticket_datetime_rows, $ticket_datetime_rows);
461 461
             // trim inputs to ensure any excess whitespace is removed.
462 462
             $ticket_data = array_map(
463
-                function ($ticket_data) {
463
+                function($ticket_data) {
464 464
                     return is_array($ticket_data) ? $ticket_data : trim($ticket_data);
465 465
                 },
466 466
                 $ticket_data
@@ -480,8 +480,8 @@  discard block
 block discarded – undo
480 480
                 ? $base_price
481 481
                 : $ticket_price;
482 482
             $base_price_id = $ticket_data['TKT_base_price_ID'] ?? 0;
483
-            $price_rows    = is_array($data['edit_prices']) && isset($data['edit_prices'][ $row ])
484
-                ? $data['edit_prices'][ $row ]
483
+            $price_rows    = is_array($data['edit_prices']) && isset($data['edit_prices'][$row])
484
+                ? $data['edit_prices'][$row]
485 485
                 : [];
486 486
             $now           = null;
487 487
             if (empty($ticket_data['TKT_start_date'])) {
@@ -493,7 +493,7 @@  discard block
 block discarded – undo
493 493
                 /**
494 494
                  * set the TKT_end_date to the first datetime attached to the ticket.
495 495
                  */
496
-                $first_datetime              = $saved_datetimes[ reset($ticket_datetime_rows) ];
496
+                $first_datetime              = $saved_datetimes[reset($ticket_datetime_rows)];
497 497
                 $ticket_data['TKT_end_date'] = $first_datetime->start_date_and_time($this->_date_time_format);
498 498
             }
499 499
             $TKT_values = [
@@ -592,7 +592,7 @@  discard block
 block discarded – undo
592 592
                 if ($ticket instanceof EE_Ticket) {
593 593
                     // make sure ticket has an ID of setting relations won't work
594 594
                     $ticket->save();
595
-                    $ticket        = $this->_update_ticket_datetimes(
595
+                    $ticket = $this->_update_ticket_datetimes(
596 596
                         $ticket,
597 597
                         $saved_datetimes,
598 598
                         $datetimes_added,
@@ -626,7 +626,7 @@  discard block
 block discarded – undo
626 626
             // need to make sue that the TKT_price is accurate after saving the prices.
627 627
             $ticket->ensure_TKT_Price_correct();
628 628
             // handle CREATING a default ticket from the incoming ticket but ONLY if this isn't an autosave.
629
-            if (! defined('DOING_AUTOSAVE') && ! empty($ticket_data['TKT_is_default_selector'])) {
629
+            if ( ! defined('DOING_AUTOSAVE') && ! empty($ticket_data['TKT_is_default_selector'])) {
630 630
                 $new_default = clone $ticket;
631 631
                 $new_default->set('TKT_ID', 0);
632 632
                 $new_default->set('TKT_is_default', 1);
@@ -670,7 +670,7 @@  discard block
 block discarded – undo
670 670
                 // save new TKT
671 671
                 $new_ticket->save();
672 672
                 // add new ticket to array
673
-                $saved_tickets[ $new_ticket->ID() ] = $new_ticket;
673
+                $saved_tickets[$new_ticket->ID()] = $new_ticket;
674 674
                 do_action(
675 675
                     'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_ticket',
676 676
                     $new_ticket,
@@ -680,7 +680,7 @@  discard block
 block discarded – undo
680 680
                 );
681 681
             } else {
682 682
                 // add ticket to saved tickets
683
-                $saved_tickets[ $ticket->ID() ] = $ticket;
683
+                $saved_tickets[$ticket->ID()] = $ticket;
684 684
                 do_action(
685 685
                     'AHEE__espresso_events_Pricing_Hooks___update_tkts_update_ticket',
686 686
                     $ticket,
@@ -748,20 +748,20 @@  discard block
 block discarded – undo
748 748
         // to start we have to add the ticket to all the datetimes its supposed to be with,
749 749
         // and removing the ticket from datetimes it got removed from.
750 750
         // first let's add datetimes
751
-        if (! empty($added_datetimes) && is_array($added_datetimes)) {
751
+        if ( ! empty($added_datetimes) && is_array($added_datetimes)) {
752 752
             foreach ($added_datetimes as $row_id) {
753
-                if (isset($saved_datetimes[ $row_id ]) && $saved_datetimes[ $row_id ] instanceof EE_Datetime) {
754
-                    $ticket->_add_relation_to($saved_datetimes[ $row_id ], 'Datetime');
753
+                if (isset($saved_datetimes[$row_id]) && $saved_datetimes[$row_id] instanceof EE_Datetime) {
754
+                    $ticket->_add_relation_to($saved_datetimes[$row_id], 'Datetime');
755 755
                 }
756 756
             }
757 757
         }
758 758
         // then remove datetimes
759
-        if (! empty($removed_datetimes) && is_array($removed_datetimes)) {
759
+        if ( ! empty($removed_datetimes) && is_array($removed_datetimes)) {
760 760
             foreach ($removed_datetimes as $row_id) {
761 761
                 // its entirely possible that a datetime got deleted (instead of just removed from relationship.
762 762
                 // So make sure we skip over this if the datetime isn't in the $saved_datetimes array)
763
-                if (isset($saved_datetimes[ $row_id ]) && $saved_datetimes[ $row_id ] instanceof EE_Datetime) {
764
-                    $ticket->_remove_relation_to($saved_datetimes[ $row_id ], 'Datetime');
763
+                if (isset($saved_datetimes[$row_id]) && $saved_datetimes[$row_id] instanceof EE_Datetime) {
764
+                    $ticket->_remove_relation_to($saved_datetimes[$row_id], 'Datetime');
765 765
                 }
766 766
             }
767 767
         }
@@ -872,7 +872,7 @@  discard block
 block discarded – undo
872 872
             ];
873 873
         }
874 874
         // possibly need to save ticket
875
-        if (! $ticket->ID()) {
875
+        if ( ! $ticket->ID()) {
876 876
             $ticket->save();
877 877
         }
878 878
         foreach ($prices as $row => $prc) {
@@ -906,17 +906,17 @@  discard block
 block discarded – undo
906 906
                 }
907 907
             }
908 908
             $price->save();
909
-            $updated_prices[ $price->ID() ] = $price;
909
+            $updated_prices[$price->ID()] = $price;
910 910
             $ticket->_add_relation_to($price, 'Price');
911 911
         }
912 912
         // now let's remove any prices that got removed from the ticket
913
-        if (! empty($current_prices_on_ticket)) {
913
+        if ( ! empty($current_prices_on_ticket)) {
914 914
             $current          = array_keys($current_prices_on_ticket);
915 915
             $updated          = array_keys($updated_prices);
916 916
             $prices_to_remove = array_diff($current, $updated);
917
-            if (! empty($prices_to_remove)) {
917
+            if ( ! empty($prices_to_remove)) {
918 918
                 foreach ($prices_to_remove as $prc_id) {
919
-                    $p = $current_prices_on_ticket[ $prc_id ];
919
+                    $p = $current_prices_on_ticket[$prc_id];
920 920
                     $ticket->_remove_relation_to($p, 'Price');
921 921
                     // delete permanently the price
922 922
                     $p->delete_permanently();
@@ -965,7 +965,7 @@  discard block
 block discarded – undo
965 965
             'ticket_rows'              => '',
966 966
             'ee_collapsible_status'    => ' ee-collapsible-open',
967 967
         ];
968
-        $timezone           = $event instanceof EE_Event ? $event->timezone_string() : null;
968
+        $timezone = $event instanceof EE_Event ? $event->timezone_string() : null;
969 969
         do_action('AHEE_log', __FILE__, __FUNCTION__, '');
970 970
 
971 971
         /**
@@ -1029,18 +1029,18 @@  discard block
 block discarded – undo
1029 1029
                 $TKT_ID     = $ticket->get('TKT_ID');
1030 1030
                 $ticket_row = $ticket->get('TKT_row');
1031 1031
                 // we only want unique tickets in our final display!!
1032
-                if (! in_array($TKT_ID, $existing_ticket_ids, true)) {
1032
+                if ( ! in_array($TKT_ID, $existing_ticket_ids, true)) {
1033 1033
                     $existing_ticket_ids[] = $TKT_ID;
1034 1034
                     $all_tickets[]         = $ticket;
1035 1035
                 }
1036 1036
                 // temporary cache of this ticket info for this datetime for later processing of datetime rows.
1037
-                $datetime_tickets[ $DTT_ID ][] = $ticket_row;
1037
+                $datetime_tickets[$DTT_ID][] = $ticket_row;
1038 1038
                 // temporary cache of this datetime info for this ticket for later processing of ticket rows.
1039 1039
                 if (
1040
-                    ! isset($ticket_datetimes[ $TKT_ID ])
1041
-                    || ! in_array($datetime_row, $ticket_datetimes[ $TKT_ID ], true)
1040
+                    ! isset($ticket_datetimes[$TKT_ID])
1041
+                    || ! in_array($datetime_row, $ticket_datetimes[$TKT_ID], true)
1042 1042
                 ) {
1043
-                    $ticket_datetimes[ $TKT_ID ][] = $datetime_row;
1043
+                    $ticket_datetimes[$TKT_ID][] = $datetime_row;
1044 1044
                 }
1045 1045
             }
1046 1046
             $datetime_row++;
@@ -1051,7 +1051,7 @@  discard block
 block discarded – undo
1051 1051
         // sort $all_tickets by order
1052 1052
         usort(
1053 1053
             $all_tickets,
1054
-            function (EE_Ticket $a, EE_Ticket $b) {
1054
+            function(EE_Ticket $a, EE_Ticket $b) {
1055 1055
                 $a_order = (int) $a->get('TKT_order');
1056 1056
                 $b_order = (int) $b->get('TKT_order');
1057 1057
                 if ($a_order === $b_order) {
@@ -1099,7 +1099,7 @@  discard block
 block discarded – undo
1099 1099
         );
1100 1100
 
1101 1101
         EEH_Template::display_template(
1102
-            PRICING_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php',
1102
+            PRICING_TEMPLATE_PATH.'event_tickets_metabox_main.template.php',
1103 1103
             $main_template_args
1104 1104
         );
1105 1105
     }
@@ -1126,7 +1126,7 @@  discard block
 block discarded – undo
1126 1126
         array $all_datetimes = []
1127 1127
     ): string {
1128 1128
         return EEH_Template::display_template(
1129
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_row_wrapper.template.php',
1129
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_row_wrapper.template.php',
1130 1130
             [
1131 1131
                 'dtt_edit_row'             => $this->_get_dtt_edit_row(
1132 1132
                     $datetime_row,
@@ -1215,7 +1215,7 @@  discard block
 block discarded – undo
1215 1215
             $this->_is_creating_event
1216 1216
         );
1217 1217
         return EEH_Template::display_template(
1218
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_edit_row.template.php',
1218
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_edit_row.template.php',
1219 1219
             $template_args,
1220 1220
             true
1221 1221
         );
@@ -1255,7 +1255,7 @@  discard block
 block discarded – undo
1255 1255
             'DTT_ID'                            => $default ? '' : $datetime->ID(),
1256 1256
         ];
1257 1257
         // need to setup the list items (but only if this isn't a default skeleton setup)
1258
-        if (! $default) {
1258
+        if ( ! $default) {
1259 1259
             $ticket_row = 1;
1260 1260
             foreach ($all_tickets as $ticket) {
1261 1261
                 $template_args['datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
@@ -1281,7 +1281,7 @@  discard block
 block discarded – undo
1281 1281
             $this->_is_creating_event
1282 1282
         );
1283 1283
         return EEH_Template::display_template(
1284
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_attached_tickets_row.template.php',
1284
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_attached_tickets_row.template.php',
1285 1285
             $template_args,
1286 1286
             true
1287 1287
         );
@@ -1307,8 +1307,8 @@  discard block
 block discarded – undo
1307 1307
         array $datetime_tickets = [],
1308 1308
         bool $default = false
1309 1309
     ): string {
1310
-        $datetime_tickets = $datetime instanceof EE_Datetime && isset($datetime_tickets[ $datetime->ID() ])
1311
-            ? $datetime_tickets[ $datetime->ID() ]
1310
+        $datetime_tickets = $datetime instanceof EE_Datetime && isset($datetime_tickets[$datetime->ID()])
1311
+            ? $datetime_tickets[$datetime->ID()]
1312 1312
             : [];
1313 1313
         $display_row      = $ticket instanceof EE_Ticket ? $ticket->get('TKT_row') : 0;
1314 1314
         $no_ticket        = $default && empty($ticket);
@@ -1329,8 +1329,8 @@  discard block
 block discarded – undo
1329 1329
                 ? 'TKTNAME'
1330 1330
                 : $ticket->get('TKT_name'),
1331 1331
             'tkt_status_class'        => $no_ticket || $this->_is_creating_event
1332
-                ? ' tkt-status-' . EE_Ticket::onsale
1333
-                : ' tkt-status-' . $ticket->ticket_status(),
1332
+                ? ' tkt-status-'.EE_Ticket::onsale
1333
+                : ' tkt-status-'.$ticket->ticket_status(),
1334 1334
         ];
1335 1335
         // filter template args
1336 1336
         $template_args = apply_filters(
@@ -1345,7 +1345,7 @@  discard block
 block discarded – undo
1345 1345
             $this->_is_creating_event
1346 1346
         );
1347 1347
         return EEH_Template::display_template(
1348
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_dtt_tickets_list.template.php',
1348
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_dtt_tickets_list.template.php',
1349 1349
             $template_args,
1350 1350
             true
1351 1351
         );
@@ -1401,19 +1401,19 @@  discard block
 block discarded – undo
1401 1401
         // (otherwise there won't be any new relationships created for tickets based off of the default ticket).
1402 1402
         // This will future proof in case there is ever any behaviour change between what the primary_key defaults to.
1403 1403
         $default_datetime = $default || ($ticket instanceof EE_Ticket && $ticket->is_default());
1404
-        $ticket_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[ $ticket->ID() ])
1405
-            ? $ticket_datetimes[ $ticket->ID() ]
1404
+        $ticket_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[$ticket->ID()])
1405
+            ? $ticket_datetimes[$ticket->ID()]
1406 1406
             : [];
1407 1407
         $ticket_subtotal  = $default ? 0 : $ticket->get_ticket_subtotal();
1408 1408
         $base_price       = $default ? null : $ticket->base_price();
1409 1409
         $count_price_mods = EEM_Price::instance()->get_all_default_prices(true);
1410 1410
         // breaking out complicated condition for ticket_status
1411 1411
         if ($default) {
1412
-            $ticket_status_class = ' tkt-status-' . EE_Ticket::onsale;
1412
+            $ticket_status_class = ' tkt-status-'.EE_Ticket::onsale;
1413 1413
         } else {
1414 1414
             $ticket_status_class = $ticket->is_default()
1415
-                ? ' tkt-status-' . EE_Ticket::onsale
1416
-                : ' tkt-status-' . $ticket->ticket_status();
1415
+                ? ' tkt-status-'.EE_Ticket::onsale
1416
+                : ' tkt-status-'.$ticket->ticket_status();
1417 1417
         }
1418 1418
         // breaking out complicated condition for TKT_taxable
1419 1419
         if ($default) {
@@ -1438,7 +1438,7 @@  discard block
 block discarded – undo
1438 1438
                 $TKT_min = '';
1439 1439
             }
1440 1440
         }
1441
-        $template_args                 = [
1441
+        $template_args = [
1442 1442
             'tkt_row'                       => $default ? 'TICKETNUM' : $ticket_row,
1443 1443
             'TKT_order'                     => $default ? 'TICKETNUM' : $ticket_row,
1444 1444
             // on initial page load this will always be the correct order.
@@ -1505,7 +1505,7 @@  discard block
 block discarded – undo
1505 1505
                 : 'display:none;',
1506 1506
             'show_price_mod_button'         => count($prices) > 1
1507 1507
                                                || ($default && $count_price_mods > 0)
1508
-                                               || (! $default && $ticket->deleted())
1508
+                                               || ( ! $default && $ticket->deleted())
1509 1509
                 ? 'display:none;'
1510 1510
                 : '',
1511 1511
             'total_price_rows'              => count($prices) > 1 ? count($prices) : 1,
@@ -1546,11 +1546,11 @@  discard block
 block discarded – undo
1546 1546
         // handle rows that should NOT be empty
1547 1547
         if (empty($template_args['TKT_start_date'])) {
1548 1548
             // if empty then the start date will be now.
1549
-            $template_args['TKT_start_date']   = date(
1549
+            $template_args['TKT_start_date'] = date(
1550 1550
                 $this->_date_time_format,
1551 1551
                 current_time('timestamp')
1552 1552
             );
1553
-            $template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1553
+            $template_args['tkt_status_class'] = ' tkt-status-'.EE_Ticket::onsale;
1554 1554
         }
1555 1555
         if (empty($template_args['TKT_end_date'])) {
1556 1556
             // get the earliest datetime (if present);
@@ -1560,7 +1560,7 @@  discard block
 block discarded – undo
1560 1560
                     ['order_by' => ['DTT_EVT_start' => 'ASC']]
1561 1561
                 )
1562 1562
                 : null;
1563
-            if (! empty($earliest_datetime)) {
1563
+            if ( ! empty($earliest_datetime)) {
1564 1564
                 $template_args['TKT_end_date'] = $earliest_datetime->get_datetime(
1565 1565
                     'DTT_EVT_start',
1566 1566
                     $this->_date_time_format
@@ -1579,10 +1579,10 @@  discard block
 block discarded – undo
1579 1579
                     )
1580 1580
                 );
1581 1581
             }
1582
-            $template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1582
+            $template_args['tkt_status_class'] = ' tkt-status-'.EE_Ticket::onsale;
1583 1583
         }
1584 1584
         // generate ticket_datetime items
1585
-        if (! $default) {
1585
+        if ( ! $default) {
1586 1586
             $datetime_row = 1;
1587 1587
             foreach ($all_datetimes as $datetime) {
1588 1588
                 $template_args['ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
@@ -1598,7 +1598,7 @@  discard block
 block discarded – undo
1598 1598
         }
1599 1599
         $price_row = 1;
1600 1600
         foreach ($prices as $price) {
1601
-            if (! $price instanceof EE_Price) {
1601
+            if ( ! $price instanceof EE_Price) {
1602 1602
                 continue;
1603 1603
             }
1604 1604
             if ($price->is_base_price()) {
@@ -1633,7 +1633,7 @@  discard block
 block discarded – undo
1633 1633
             $this->_is_creating_event
1634 1634
         );
1635 1635
         return EEH_Template::display_template(
1636
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_row.template.php',
1636
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_row.template.php',
1637 1637
             $template_args,
1638 1638
             true
1639 1639
         );
@@ -1673,8 +1673,8 @@  discard block
 block discarded – undo
1673 1673
                 $ticket,
1674 1674
                 $this->_is_creating_event
1675 1675
             );
1676
-            $tax_rows      .= EEH_Template::display_template(
1677
-                PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_tax_row.template.php',
1676
+            $tax_rows .= EEH_Template::display_template(
1677
+                PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_tax_row.template.php',
1678 1678
                 $template_args,
1679 1679
                 true
1680 1680
             );
@@ -1794,7 +1794,7 @@  discard block
 block discarded – undo
1794 1794
             $this->_is_creating_event
1795 1795
         );
1796 1796
         return EEH_Template::display_template(
1797
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_price_row.template.php',
1797
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_price_row.template.php',
1798 1798
             $template_args,
1799 1799
             true
1800 1800
         );
@@ -1874,7 +1874,7 @@  discard block
 block discarded – undo
1874 1874
             $this->_is_creating_event
1875 1875
         );
1876 1876
         return EEH_Template::display_template(
1877
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_type_base.template.php',
1877
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_price_type_base.template.php',
1878 1878
             $template_args,
1879 1879
             true
1880 1880
         );
@@ -1904,7 +1904,7 @@  discard block
 block discarded – undo
1904 1904
     ): string {
1905 1905
         $select_name = $default && ! $price instanceof EE_Price
1906 1906
             ? 'edit_prices[TICKETNUM][PRICENUM][PRT_ID]'
1907
-            : 'edit_prices[' . esc_attr($ticket_row) . '][' . esc_attr($price_row) . '][PRT_ID]';
1907
+            : 'edit_prices['.esc_attr($ticket_row).']['.esc_attr($price_row).'][PRT_ID]';
1908 1908
         /** @var EEM_Price_Type $price_type_model */
1909 1909
         $price_type_model       = EE_Registry::instance()->load_model('Price_Type');
1910 1910
         $price_types            = $price_type_model->get_all(
@@ -1924,25 +1924,25 @@  discard block
 block discarded – undo
1924 1924
         $price_option_spans     = '';
1925 1925
         // setup price types for selector
1926 1926
         foreach ($price_types as $price_type) {
1927
-            if (! $price_type instanceof EE_Price_Type) {
1927
+            if ( ! $price_type instanceof EE_Price_Type) {
1928 1928
                 continue;
1929 1929
             }
1930
-            $all_price_types[ $price_type->ID() ] = $price_type->get('PRT_name');
1930
+            $all_price_types[$price_type->ID()] = $price_type->get('PRT_name');
1931 1931
             // while we're in the loop let's setup the option spans used by js
1932
-            $span_args          = [
1932
+            $span_args = [
1933 1933
                 'PRT_ID'         => $price_type->ID(),
1934 1934
                 'PRT_operator'   => $price_type->is_discount() ? '-' : '+',
1935 1935
                 'PRT_is_percent' => $price_type->get('PRT_is_percent') ? 1 : 0,
1936 1936
             ];
1937 1937
             $price_option_spans .= EEH_Template::display_template(
1938
-                PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_option_span.template.php',
1938
+                PRICING_TEMPLATE_PATH.'event_tickets_datetime_price_option_span.template.php',
1939 1939
                 $span_args,
1940 1940
                 true
1941 1941
             );
1942 1942
         }
1943 1943
 
1944 1944
         $select_name = $disabled
1945
-            ? 'archive_price[' . $ticket_row . '][' . $price_row . '][PRT_ID]'
1945
+            ? 'archive_price['.$ticket_row.']['.$price_row.'][PRT_ID]'
1946 1946
             : $select_name;
1947 1947
 
1948 1948
         $select_input = new EE_Select_Input(
@@ -1970,7 +1970,7 @@  discard block
 block discarded – undo
1970 1970
             'price_selected_is_percent' => $price_selected_is_percent,
1971 1971
             'disabled'                  => $disabled,
1972 1972
         ];
1973
-        $template_args             = apply_filters(
1973
+        $template_args = apply_filters(
1974 1974
             'FHEE__espresso_events_Pricing_Hooks___get_price_modifier_template__template_args',
1975 1975
             $template_args,
1976 1976
             $ticket_row,
@@ -1981,7 +1981,7 @@  discard block
 block discarded – undo
1981 1981
             $this->_is_creating_event
1982 1982
         );
1983 1983
         return EEH_Template::display_template(
1984
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_modifier_selector.template.php',
1984
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_price_modifier_selector.template.php',
1985 1985
             $template_args,
1986 1986
             true
1987 1987
         );
@@ -2008,8 +2008,8 @@  discard block
 block discarded – undo
2008 2008
         array $ticket_datetimes = [],
2009 2009
         bool $default = false
2010 2010
     ): string {
2011
-        $ticket_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[ $ticket->ID() ])
2012
-            ? $ticket_datetimes[ $ticket->ID() ]
2011
+        $ticket_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[$ticket->ID()])
2012
+            ? $ticket_datetimes[$ticket->ID()]
2013 2013
             : [];
2014 2014
         $template_args    = [
2015 2015
             'dtt_row'                  => $default && ! $datetime instanceof EE_Datetime
@@ -2029,7 +2029,7 @@  discard block
 block discarded – undo
2029 2029
                 : $datetime->get_dtt_display_name(true),
2030 2030
             'tkt_status_class'         => '',
2031 2031
         ];
2032
-        $template_args    = apply_filters(
2032
+        $template_args = apply_filters(
2033 2033
             'FHEE__espresso_events_Pricing_Hooks___get_ticket_datetime_list_item__template_args',
2034 2034
             $template_args,
2035 2035
             $datetime_row,
@@ -2041,7 +2041,7 @@  discard block
 block discarded – undo
2041 2041
             $this->_is_creating_event
2042 2042
         );
2043 2043
         return EEH_Template::display_template(
2044
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_datetimes_list_item.template.php',
2044
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_datetimes_list_item.template.php',
2045 2045
             $template_args,
2046 2046
             true
2047 2047
         );
@@ -2119,7 +2119,7 @@  discard block
 block discarded – undo
2119 2119
                 true
2120 2120
             ),
2121 2121
         ];
2122
-        $ticket_row    = 1;
2122
+        $ticket_row = 1;
2123 2123
         foreach ($all_tickets as $ticket) {
2124 2124
             $template_args['existing_available_datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
2125 2125
                 'DTTNUM',
@@ -2148,11 +2148,11 @@  discard block
 block discarded – undo
2148 2148
         $default_prices = $price_model->get_all_default_prices();
2149 2149
         $price_row      = 1;
2150 2150
         foreach ($default_prices as $price) {
2151
-            if (! $price instanceof EE_Price) {
2151
+            if ( ! $price instanceof EE_Price) {
2152 2152
                 continue;
2153 2153
             }
2154 2154
             if ($price->is_base_price()) {
2155
-                $template_args['default_base_price_amount']      = $price->get_pretty(
2155
+                $template_args['default_base_price_amount'] = $price->get_pretty(
2156 2156
                     'PRC_amount',
2157 2157
                     'localized_float'
2158 2158
                 );
@@ -2184,7 +2184,7 @@  discard block
 block discarded – undo
2184 2184
             $this->_is_creating_event
2185 2185
         );
2186 2186
         return EEH_Template::display_template(
2187
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_js_structure.template.php',
2187
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_js_structure.template.php',
2188 2188
             $template_args,
2189 2189
             true
2190 2190
         );
Please login to merge, or discard this patch.
Indentation   +2160 added lines, -2160 removed lines patch added patch discarded remove patch
@@ -15,2178 +15,2178 @@
 block discarded – undo
15 15
  */
16 16
 class espresso_events_Pricing_Hooks extends EE_Admin_Hooks
17 17
 {
18
-    /**
19
-     * This property is just used to hold the status of whether an event is currently being
20
-     * created (true) or edited (false)
21
-     *
22
-     * @access protected
23
-     * @var bool
24
-     */
25
-    protected $_is_creating_event;
26
-
27
-    /**
28
-     * Used to contain the format strings for date and time that will be used for php date and
29
-     * time.
30
-     * Is set in the _set_hooks_properties() method.
31
-     *
32
-     * @var array
33
-     */
34
-    protected $_date_format_strings;
35
-
36
-    /**
37
-     * @var string $_date_time_format
38
-     */
39
-    protected $_date_time_format;
40
-
41
-
42
-    /**
43
-     * @throws InvalidArgumentException
44
-     * @throws InvalidInterfaceException
45
-     * @throws InvalidDataTypeException
46
-     */
47
-    protected function _set_hooks_properties()
48
-    {
49
-        $this->_name = 'pricing';
50
-        // capability check
51
-        if (
52
-            $this->_adminpage_obj->adminConfig()->useAdvancedEditor()
53
-            || ! EE_Registry::instance()->CAP->current_user_can(
54
-                'ee_read_default_prices',
55
-                'advanced_ticket_datetime_metabox'
56
-            )
57
-        ) {
58
-            $this->_metaboxes      = [];
59
-            $this->_scripts_styles = [];
60
-            return;
61
-        }
62
-        $this->_setup_metaboxes();
63
-        $this->_set_date_time_formats();
64
-        $this->_validate_format_strings();
65
-        $this->_set_scripts_styles();
66
-        add_filter(
67
-            'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
68
-            [$this, 'caf_updates']
69
-        );
70
-    }
71
-
72
-
73
-    /**
74
-     * @return void
75
-     */
76
-    protected function _setup_metaboxes()
77
-    {
78
-        // if we were going to add our own metaboxes we'd use the below.
79
-        $this->_metaboxes        = [
80
-            0 => [
81
-                'page_route' => ['edit', 'create_new'],
82
-                'func'       => [$this, 'pricing_metabox'],
83
-                'label'      => esc_html__('Event Tickets & Datetimes', 'event_espresso'),
84
-                'priority'   => 'high',
85
-                'context'    => 'normal',
86
-            ],
87
-        ];
88
-        $this->_remove_metaboxes = [
89
-            0 => [
90
-                'page_route' => ['edit', 'create_new'],
91
-                'id'         => 'espresso_event_editor_tickets',
92
-                'context'    => 'normal',
93
-            ],
94
-        ];
95
-    }
96
-
97
-
98
-    /**
99
-     * @return void
100
-     */
101
-    protected function _set_date_time_formats()
102
-    {
103
-        /**
104
-         * Format strings for date and time.  Defaults are existing behaviour from 4.1.
105
-         * Note, that if you return null as the value for 'date', and 'time' in the array, then
106
-         * EE will automatically use the set wp_options, 'date_format', and 'time_format'.
107
-         *
108
-         * @since 4.6.7
109
-         * @var array  Expected an array returned with 'date' and 'time' keys.
110
-         */
111
-        $this->_date_format_strings = apply_filters(
112
-            'FHEE__espresso_events_Pricing_Hooks___set_hooks_properties__date_format_strings',
113
-            [
114
-                'date' => 'Y-m-d',
115
-                'time' => 'h:i a',
116
-            ]
117
-        );
118
-        // validate
119
-        $this->_date_format_strings['date'] = $this->_date_format_strings['date'] ?? '';
120
-        $this->_date_format_strings['time'] = $this->_date_format_strings['time'] ?? '';
121
-
122
-        $this->_date_time_format = $this->_date_format_strings['date'] . ' ' . $this->_date_format_strings['time'];
123
-    }
124
-
125
-
126
-    /**
127
-     * @return void
128
-     */
129
-    protected function _validate_format_strings()
130
-    {
131
-        // validate format strings
132
-        $format_validation = EEH_DTT_Helper::validate_format_string(
133
-            $this->_date_time_format
134
-        );
135
-        if (is_array($format_validation)) {
136
-            $msg = '<p>';
137
-            $msg .= sprintf(
138
-                esc_html__(
139
-                    'The format "%s" was likely added via a filter and is invalid for the following reasons:',
140
-                    'event_espresso'
141
-                ),
142
-                $this->_date_time_format
143
-            );
144
-            $msg .= '</p><ul>';
145
-            foreach ($format_validation as $error) {
146
-                $msg .= '<li>' . $error . '</li>';
147
-            }
148
-            $msg .= '</ul><p>';
149
-            $msg .= sprintf(
150
-                esc_html__(
151
-                    '%sPlease note that your date and time formats have been reset to "Y-m-d" and "h:i a" respectively.%s',
152
-                    'event_espresso'
153
-                ),
154
-                '<span style="color:#D54E21;">',
155
-                '</span>'
156
-            );
157
-            $msg .= '</p>';
158
-            EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
159
-            $this->_date_format_strings = [
160
-                'date' => 'Y-m-d',
161
-                'time' => 'h:i a',
162
-            ];
163
-        }
164
-    }
165
-
166
-
167
-    /**
168
-     * @return void
169
-     */
170
-    protected function _set_scripts_styles()
171
-    {
172
-        $this->_scripts_styles = [
173
-            'registers'   => [
174
-                'ee-tickets-datetimes-css' => [
175
-                    'url'  => PRICING_ASSETS_URL . 'event-tickets-datetimes.css',
176
-                    'type' => 'css',
177
-                ],
178
-                'ee-dtt-ticket-metabox'    => [
179
-                    'url'     => PRICING_ASSETS_URL . 'ee-datetime-ticket-metabox.js',
180
-                    'depends' => ['ee-datepicker', 'ee-dialog', 'underscore'],
181
-                ],
182
-            ],
183
-            'deregisters' => [
184
-                'event-editor-css'       => ['type' => 'css'],
185
-                'event-datetime-metabox' => ['type' => 'js'],
186
-            ],
187
-            'enqueues'    => [
188
-                'ee-tickets-datetimes-css' => ['edit', 'create_new'],
189
-                'ee-dtt-ticket-metabox'    => ['edit', 'create_new'],
190
-            ],
191
-            'localize'    => [
192
-                'ee-dtt-ticket-metabox' => [
193
-                    'DTT_TRASH_BLOCK'       => [
194
-                        'main_warning'            => esc_html__(
195
-                            'The Datetime you are attempting to trash is the only datetime selected for the following ticket(s):',
196
-                            'event_espresso'
197
-                        ),
198
-                        'after_warning'           => esc_html__(
199
-                            'In order to trash this datetime you must first make sure the above ticket(s) are assigned to other datetimes.',
200
-                            'event_espresso'
201
-                        ),
202
-                        'cancel_button'           => '
18
+	/**
19
+	 * This property is just used to hold the status of whether an event is currently being
20
+	 * created (true) or edited (false)
21
+	 *
22
+	 * @access protected
23
+	 * @var bool
24
+	 */
25
+	protected $_is_creating_event;
26
+
27
+	/**
28
+	 * Used to contain the format strings for date and time that will be used for php date and
29
+	 * time.
30
+	 * Is set in the _set_hooks_properties() method.
31
+	 *
32
+	 * @var array
33
+	 */
34
+	protected $_date_format_strings;
35
+
36
+	/**
37
+	 * @var string $_date_time_format
38
+	 */
39
+	protected $_date_time_format;
40
+
41
+
42
+	/**
43
+	 * @throws InvalidArgumentException
44
+	 * @throws InvalidInterfaceException
45
+	 * @throws InvalidDataTypeException
46
+	 */
47
+	protected function _set_hooks_properties()
48
+	{
49
+		$this->_name = 'pricing';
50
+		// capability check
51
+		if (
52
+			$this->_adminpage_obj->adminConfig()->useAdvancedEditor()
53
+			|| ! EE_Registry::instance()->CAP->current_user_can(
54
+				'ee_read_default_prices',
55
+				'advanced_ticket_datetime_metabox'
56
+			)
57
+		) {
58
+			$this->_metaboxes      = [];
59
+			$this->_scripts_styles = [];
60
+			return;
61
+		}
62
+		$this->_setup_metaboxes();
63
+		$this->_set_date_time_formats();
64
+		$this->_validate_format_strings();
65
+		$this->_set_scripts_styles();
66
+		add_filter(
67
+			'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
68
+			[$this, 'caf_updates']
69
+		);
70
+	}
71
+
72
+
73
+	/**
74
+	 * @return void
75
+	 */
76
+	protected function _setup_metaboxes()
77
+	{
78
+		// if we were going to add our own metaboxes we'd use the below.
79
+		$this->_metaboxes        = [
80
+			0 => [
81
+				'page_route' => ['edit', 'create_new'],
82
+				'func'       => [$this, 'pricing_metabox'],
83
+				'label'      => esc_html__('Event Tickets & Datetimes', 'event_espresso'),
84
+				'priority'   => 'high',
85
+				'context'    => 'normal',
86
+			],
87
+		];
88
+		$this->_remove_metaboxes = [
89
+			0 => [
90
+				'page_route' => ['edit', 'create_new'],
91
+				'id'         => 'espresso_event_editor_tickets',
92
+				'context'    => 'normal',
93
+			],
94
+		];
95
+	}
96
+
97
+
98
+	/**
99
+	 * @return void
100
+	 */
101
+	protected function _set_date_time_formats()
102
+	{
103
+		/**
104
+		 * Format strings for date and time.  Defaults are existing behaviour from 4.1.
105
+		 * Note, that if you return null as the value for 'date', and 'time' in the array, then
106
+		 * EE will automatically use the set wp_options, 'date_format', and 'time_format'.
107
+		 *
108
+		 * @since 4.6.7
109
+		 * @var array  Expected an array returned with 'date' and 'time' keys.
110
+		 */
111
+		$this->_date_format_strings = apply_filters(
112
+			'FHEE__espresso_events_Pricing_Hooks___set_hooks_properties__date_format_strings',
113
+			[
114
+				'date' => 'Y-m-d',
115
+				'time' => 'h:i a',
116
+			]
117
+		);
118
+		// validate
119
+		$this->_date_format_strings['date'] = $this->_date_format_strings['date'] ?? '';
120
+		$this->_date_format_strings['time'] = $this->_date_format_strings['time'] ?? '';
121
+
122
+		$this->_date_time_format = $this->_date_format_strings['date'] . ' ' . $this->_date_format_strings['time'];
123
+	}
124
+
125
+
126
+	/**
127
+	 * @return void
128
+	 */
129
+	protected function _validate_format_strings()
130
+	{
131
+		// validate format strings
132
+		$format_validation = EEH_DTT_Helper::validate_format_string(
133
+			$this->_date_time_format
134
+		);
135
+		if (is_array($format_validation)) {
136
+			$msg = '<p>';
137
+			$msg .= sprintf(
138
+				esc_html__(
139
+					'The format "%s" was likely added via a filter and is invalid for the following reasons:',
140
+					'event_espresso'
141
+				),
142
+				$this->_date_time_format
143
+			);
144
+			$msg .= '</p><ul>';
145
+			foreach ($format_validation as $error) {
146
+				$msg .= '<li>' . $error . '</li>';
147
+			}
148
+			$msg .= '</ul><p>';
149
+			$msg .= sprintf(
150
+				esc_html__(
151
+					'%sPlease note that your date and time formats have been reset to "Y-m-d" and "h:i a" respectively.%s',
152
+					'event_espresso'
153
+				),
154
+				'<span style="color:#D54E21;">',
155
+				'</span>'
156
+			);
157
+			$msg .= '</p>';
158
+			EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
159
+			$this->_date_format_strings = [
160
+				'date' => 'Y-m-d',
161
+				'time' => 'h:i a',
162
+			];
163
+		}
164
+	}
165
+
166
+
167
+	/**
168
+	 * @return void
169
+	 */
170
+	protected function _set_scripts_styles()
171
+	{
172
+		$this->_scripts_styles = [
173
+			'registers'   => [
174
+				'ee-tickets-datetimes-css' => [
175
+					'url'  => PRICING_ASSETS_URL . 'event-tickets-datetimes.css',
176
+					'type' => 'css',
177
+				],
178
+				'ee-dtt-ticket-metabox'    => [
179
+					'url'     => PRICING_ASSETS_URL . 'ee-datetime-ticket-metabox.js',
180
+					'depends' => ['ee-datepicker', 'ee-dialog', 'underscore'],
181
+				],
182
+			],
183
+			'deregisters' => [
184
+				'event-editor-css'       => ['type' => 'css'],
185
+				'event-datetime-metabox' => ['type' => 'js'],
186
+			],
187
+			'enqueues'    => [
188
+				'ee-tickets-datetimes-css' => ['edit', 'create_new'],
189
+				'ee-dtt-ticket-metabox'    => ['edit', 'create_new'],
190
+			],
191
+			'localize'    => [
192
+				'ee-dtt-ticket-metabox' => [
193
+					'DTT_TRASH_BLOCK'       => [
194
+						'main_warning'            => esc_html__(
195
+							'The Datetime you are attempting to trash is the only datetime selected for the following ticket(s):',
196
+							'event_espresso'
197
+						),
198
+						'after_warning'           => esc_html__(
199
+							'In order to trash this datetime you must first make sure the above ticket(s) are assigned to other datetimes.',
200
+							'event_espresso'
201
+						),
202
+						'cancel_button'           => '
203 203
                             <button class="button--secondary ee-modal-cancel">
204 204
                                 ' . esc_html__('Cancel', 'event_espresso') . '
205 205
                             </button>',
206
-                        'close_button'            => '
206
+						'close_button'            => '
207 207
                             <button class="button--secondary ee-modal-cancel">
208 208
                                 ' . esc_html__('Close', 'event_espresso') . '
209 209
                             </button>',
210
-                        'single_warning_from_tkt' => esc_html__(
211
-                            'The Datetime you are attempting to unassign from this ticket is the only remaining datetime for this ticket. Tickets must always have at least one datetime assigned to them.',
212
-                            'event_espresso'
213
-                        ),
214
-                        'single_warning_from_dtt' => esc_html__(
215
-                            'The ticket you are attempting to unassign from this datetime cannot be unassigned because the datetime is the only remaining datetime for the ticket.  Tickets must always have at least one datetime assigned to them.',
216
-                            'event_espresso'
217
-                        ),
218
-                        'dismiss_button'          => '
210
+						'single_warning_from_tkt' => esc_html__(
211
+							'The Datetime you are attempting to unassign from this ticket is the only remaining datetime for this ticket. Tickets must always have at least one datetime assigned to them.',
212
+							'event_espresso'
213
+						),
214
+						'single_warning_from_dtt' => esc_html__(
215
+							'The ticket you are attempting to unassign from this datetime cannot be unassigned because the datetime is the only remaining datetime for the ticket.  Tickets must always have at least one datetime assigned to them.',
216
+							'event_espresso'
217
+						),
218
+						'dismiss_button'          => '
219 219
                             <button class="button--secondary ee-modal-cancel">
220 220
                                 ' . esc_html__('Dismiss', 'event_espresso') . '
221 221
                             </button>',
222
-                    ],
223
-                    'DTT_ERROR_MSG'         => [
224
-                        'no_ticket_name' => esc_html__('General Admission', 'event_espresso'),
225
-                        'dismiss_button' => '
222
+					],
223
+					'DTT_ERROR_MSG'         => [
224
+						'no_ticket_name' => esc_html__('General Admission', 'event_espresso'),
225
+						'dismiss_button' => '
226 226
                             <div class="save-cancel-button-container">
227 227
                                 <button class="button--secondary ee-modal-cancel">
228 228
                                     ' . esc_html__('Dismiss', 'event_espresso') . '
229 229
                                 </button>
230 230
                             </div>',
231
-                    ],
232
-                    'DTT_OVERSELL_WARNING'  => [
233
-                        'datetime_ticket' => esc_html__(
234
-                            'You cannot add this ticket to this datetime because it has a sold amount that is greater than the amount of spots remaining for this datetime.',
235
-                            'event_espresso'
236
-                        ),
237
-                        'ticket_datetime' => esc_html__(
238
-                            'You cannot add this datetime to this ticket because the ticket has a sold amount that is greater than the amount of spots remaining on the datetime.',
239
-                            'event_espresso'
240
-                        ),
241
-                    ],
242
-                    'DTT_CONVERTED_FORMATS' => EEH_DTT_Helper::convert_php_to_js_and_moment_date_formats(
243
-                        $this->_date_format_strings['date'],
244
-                        $this->_date_format_strings['time']
245
-                    ),
246
-                    'DTT_START_OF_WEEK'     => ['dayValue' => (int) get_option('start_of_week')],
247
-                ],
248
-            ],
249
-        ];
250
-    }
251
-
252
-
253
-    /**
254
-     * @param array $update_callbacks
255
-     * @return array
256
-     */
257
-    public function caf_updates(array $update_callbacks): array
258
-    {
259
-        unset($update_callbacks['_default_tickets_update']);
260
-        $update_callbacks['datetime_and_tickets_caf_update'] = [$this, 'datetime_and_tickets_caf_update'];
261
-        return $update_callbacks;
262
-    }
263
-
264
-
265
-    /**
266
-     * Handles saving everything related to Tickets (datetimes, tickets, prices)
267
-     *
268
-     * @param EE_Event $event The Event object we're attaching data to
269
-     * @param array    $data  The request data from the form
270
-     * @throws ReflectionException
271
-     * @throws Exception
272
-     * @throws InvalidInterfaceException
273
-     * @throws InvalidDataTypeException
274
-     * @throws EE_Error
275
-     * @throws InvalidArgumentException
276
-     */
277
-    public function datetime_and_tickets_caf_update(EE_Event $event, array $data)
278
-    {
279
-        // first we need to start with datetimes cause they are the "root" items attached to events.
280
-        $saved_datetimes = $this->_update_datetimes($event, $data);
281
-        // next tackle the tickets (and prices?)
282
-        $this->_update_tickets($event, $saved_datetimes, $data);
283
-    }
284
-
285
-
286
-    /**
287
-     * update event_datetimes
288
-     *
289
-     * @param EE_Event $event Event being updated
290
-     * @param array    $data  the request data from the form
291
-     * @return EE_Datetime[]
292
-     * @throws Exception
293
-     * @throws ReflectionException
294
-     * @throws InvalidInterfaceException
295
-     * @throws InvalidDataTypeException
296
-     * @throws InvalidArgumentException
297
-     * @throws EE_Error
298
-     */
299
-    protected function _update_datetimes(EE_Event $event, array $data): array
300
-    {
301
-        $timezone            = $data['timezone_string'] ?? null;
302
-        $saved_datetime_ids  = [];
303
-        $saved_datetime_objs = [];
304
-        if (empty($data['edit_event_datetimes']) || ! is_array($data['edit_event_datetimes'])) {
305
-            throw new InvalidArgumentException(
306
-                esc_html__(
307
-                    'The "edit_event_datetimes" array is invalid therefore the event can not be updated.',
308
-                    'event_espresso'
309
-                )
310
-            );
311
-        }
312
-        foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
313
-            // trim all values to ensure any excess whitespace is removed.
314
-            $datetime_data                = array_map(
315
-                function ($datetime_data) {
316
-                    return is_array($datetime_data) ? $datetime_data : trim($datetime_data);
317
-                },
318
-                $datetime_data
319
-            );
320
-
321
-            $datetime_data['DTT_EVT_end'] = isset($datetime_data['DTT_EVT_end'])
322
-                                            && ! empty($datetime_data['DTT_EVT_end'])
323
-                ? $datetime_data['DTT_EVT_end']
324
-                : $datetime_data['DTT_EVT_start'];
325
-
326
-            $datetime_values              = [
327
-                'DTT_ID'          => ! empty($datetime_data['DTT_ID'])
328
-                    ? $datetime_data['DTT_ID']
329
-                    : null,
330
-                'DTT_name'        => ! empty($datetime_data['DTT_name'])
331
-                    ? $datetime_data['DTT_name']
332
-                    : '',
333
-                'DTT_description' => ! empty($datetime_data['DTT_description'])
334
-                    ? $datetime_data['DTT_description']
335
-                    : '',
336
-                'DTT_EVT_start'   => $datetime_data['DTT_EVT_start'],
337
-                'DTT_EVT_end'     => $datetime_data['DTT_EVT_end'],
338
-                'DTT_reg_limit'   => empty($datetime_data['DTT_reg_limit'])
339
-                    ? EE_INF
340
-                    : $datetime_data['DTT_reg_limit'],
341
-                'DTT_order'       => ! isset($datetime_data['DTT_order'])
342
-                    ? $row
343
-                    : $datetime_data['DTT_order'],
344
-            ];
345
-
346
-            // if we have an id then let's get existing object first and then set the new values.
347
-            // Otherwise we instantiate a new object for save.
348
-            if (! empty($datetime_data['DTT_ID'])) {
349
-                $datetime = EEM_Datetime::instance($timezone)->get_one_by_ID($datetime_data['DTT_ID']);
350
-                // set date and time format according to what is set in this class.
351
-                $datetime->set_date_format($this->_date_format_strings['date']);
352
-                $datetime->set_time_format($this->_date_format_strings['time']);
353
-                foreach ($datetime_values as $field => $value) {
354
-                    $datetime->set($field, $value);
355
-                }
356
-
357
-                // make sure the $datetime_id here is saved just in case
358
-                // after the add_relation_to() the autosave replaces it.
359
-                // We need to do this so we dont' TRASH the parent DTT.
360
-                // (save the ID for both key and value to avoid duplications)
361
-                $saved_datetime_ids[ $datetime->ID() ] = $datetime->ID();
362
-            } else {
363
-                $datetime = EE_Datetime::new_instance(
364
-                    $datetime_values,
365
-                    $timezone,
366
-                    [$this->_date_format_strings['date'], $this->_date_format_strings['time']]
367
-                );
368
-                foreach ($datetime_values as $field => $value) {
369
-                    $datetime->set($field, $value);
370
-                }
371
-            }
372
-            $datetime->save();
373
-            do_action(
374
-                'AHEE__espresso_events_Pricing_Hooks___update_datetimes_after_save',
375
-                $datetime,
376
-                $row,
377
-                $datetime_data,
378
-                $data
379
-            );
380
-            $datetime = $event->_add_relation_to($datetime, 'Datetime');
381
-            // before going any further make sure our dates are setup correctly
382
-            // so that the end date is always equal or greater than the start date.
383
-            if ($datetime->get_raw('DTT_EVT_start') > $datetime->get_raw('DTT_EVT_end')) {
384
-                $datetime->set('DTT_EVT_end', $datetime->get('DTT_EVT_start'));
385
-                $datetime = EEH_DTT_Helper::date_time_add($datetime, 'DTT_EVT_end', 'days');
386
-                $datetime->save();
387
-            }
388
-            // now we have to make sure we add the new DTT_ID to the $saved_datetime_ids array
389
-            // because it is possible there was a new one created for the autosave.
390
-            // (save the ID for both key and value to avoid duplications)
391
-            $DTT_ID                        = $datetime->ID();
392
-            $saved_datetime_ids[ $DTT_ID ] = $DTT_ID;
393
-            $saved_datetime_objs[ $row ]   = $datetime;
394
-            // @todo if ANY of these updates fail then we want the appropriate global error message.
395
-        }
396
-        $event->save();
397
-        // now we need to REMOVE any datetimes that got deleted.
398
-        // Keep in mind that this process will only kick in for datetimes that don't have any DTT_sold on them.
399
-        // So its safe to permanently delete at this point.
400
-        $old_datetimes = explode(',', $data['datetime_IDs']);
401
-        $old_datetimes = $old_datetimes[0] === '' ? [] : $old_datetimes;
402
-        if (is_array($old_datetimes)) {
403
-            $datetimes_to_delete = array_diff($old_datetimes, $saved_datetime_ids);
404
-            foreach ($datetimes_to_delete as $id) {
405
-                $id = absint($id);
406
-                if (empty($id)) {
407
-                    continue;
408
-                }
409
-                $datetime_to_remove = EE_Registry::instance()->load_model('Datetime')->get_one_by_ID($id);
410
-                // remove ticket relationships.
411
-                $related_tickets = $datetime_to_remove->get_many_related('Ticket');
412
-                foreach ($related_tickets as $ticket) {
413
-                    $datetime_to_remove->_remove_relation_to($ticket, 'Ticket');
414
-                }
415
-                $event->_remove_relation_to($id, 'Datetime');
416
-                $datetime_to_remove->refresh_cache_of_related_objects();
417
-            }
418
-        }
419
-        return $saved_datetime_objs;
420
-    }
421
-
422
-
423
-    /**
424
-     * update tickets
425
-     *
426
-     * @param EE_Event      $event           Event object being updated
427
-     * @param EE_Datetime[] $saved_datetimes an array of datetime ids being updated
428
-     * @param array         $data            incoming request data
429
-     * @return EE_Ticket[]
430
-     * @throws Exception
431
-     * @throws ReflectionException
432
-     * @throws InvalidInterfaceException
433
-     * @throws InvalidDataTypeException
434
-     * @throws InvalidArgumentException
435
-     * @throws EE_Error
436
-     */
437
-    protected function _update_tickets(EE_Event $event, array $saved_datetimes, array $data): array
438
-    {
439
-        $new_ticket = null;
440
-        // stripslashes because WP filtered the $_POST ($data) array to add slashes
441
-        $data          = stripslashes_deep($data);
442
-        $timezone      = $data['timezone_string'] ?? null;
443
-        $saved_tickets = [];
444
-        $old_tickets   = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : [];
445
-        if (empty($data['edit_tickets']) || ! is_array($data['edit_tickets'])) {
446
-            throw new InvalidArgumentException(
447
-                esc_html__(
448
-                    'The "edit_tickets" array is invalid therefore the event can not be updated.',
449
-                    'event_espresso'
450
-                )
451
-            );
452
-        }
453
-        foreach ($data['edit_tickets'] as $row => $ticket_data) {
454
-            $update_prices = $create_new_TKT = false;
455
-            // figure out what datetimes were added to the ticket
456
-            // and what datetimes were removed from the ticket in the session.
457
-            $starting_ticket_datetime_rows = explode(',', $data['starting_ticket_datetime_rows'][ $row ]);
458
-            $ticket_datetime_rows          = explode(',', $data['ticket_datetime_rows'][ $row ]);
459
-            $datetimes_added               = array_diff($ticket_datetime_rows, $starting_ticket_datetime_rows);
460
-            $datetimes_removed             = array_diff($starting_ticket_datetime_rows, $ticket_datetime_rows);
461
-            // trim inputs to ensure any excess whitespace is removed.
462
-            $ticket_data = array_map(
463
-                function ($ticket_data) {
464
-                    return is_array($ticket_data) ? $ticket_data : trim($ticket_data);
465
-                },
466
-                $ticket_data
467
-            );
468
-            // note we are doing conversions to floats here instead of allowing EE_Money_Field to handle
469
-            // because we're doing calculations prior to using the models.
470
-            // note incoming ['TKT_price'] value is already in standard notation (via js).
471
-            $ticket_price = isset($ticket_data['TKT_price'])
472
-                ? round((float) $ticket_data['TKT_price'], 3)
473
-                : 0;
474
-            // note incoming base price needs converted from localized value.
475
-            $base_price = isset($ticket_data['TKT_base_price'])
476
-                ? EEH_Money::convert_to_float_from_localized_money($ticket_data['TKT_base_price'])
477
-                : 0;
478
-            // if ticket price == 0 and $base_price != 0 then ticket price == base_price
479
-            $ticket_price  = $ticket_price === 0 && $base_price !== 0
480
-                ? $base_price
481
-                : $ticket_price;
482
-            $base_price_id = $ticket_data['TKT_base_price_ID'] ?? 0;
483
-            $price_rows    = is_array($data['edit_prices']) && isset($data['edit_prices'][ $row ])
484
-                ? $data['edit_prices'][ $row ]
485
-                : [];
486
-            $now           = null;
487
-            if (empty($ticket_data['TKT_start_date'])) {
488
-                // lets' use now in the set timezone.
489
-                $now                           = new DateTime('now', new DateTimeZone($event->get_timezone()));
490
-                $ticket_data['TKT_start_date'] = $now->format($this->_date_time_format);
491
-            }
492
-            if (empty($ticket_data['TKT_end_date'])) {
493
-                /**
494
-                 * set the TKT_end_date to the first datetime attached to the ticket.
495
-                 */
496
-                $first_datetime              = $saved_datetimes[ reset($ticket_datetime_rows) ];
497
-                $ticket_data['TKT_end_date'] = $first_datetime->start_date_and_time($this->_date_time_format);
498
-            }
499
-            $TKT_values = [
500
-                'TKT_ID'          => ! empty($ticket_data['TKT_ID']) ? $ticket_data['TKT_ID'] : null,
501
-                'TTM_ID'          => ! empty($ticket_data['TTM_ID']) ? $ticket_data['TTM_ID'] : 0,
502
-                'TKT_name'        => ! empty($ticket_data['TKT_name']) ? $ticket_data['TKT_name'] : '',
503
-                'TKT_description' => ! empty($ticket_data['TKT_description'])
504
-                                     && $ticket_data['TKT_description'] !== esc_html__(
505
-                                         'You can modify this description',
506
-                                         'event_espresso'
507
-                                     )
508
-                    ? $ticket_data['TKT_description']
509
-                    : '',
510
-                'TKT_start_date'  => $ticket_data['TKT_start_date'],
511
-                'TKT_end_date'    => $ticket_data['TKT_end_date'],
512
-                'TKT_qty'         => ! isset($ticket_data['TKT_qty']) || $ticket_data['TKT_qty'] === ''
513
-                    ? EE_INF
514
-                    : $ticket_data['TKT_qty'],
515
-                'TKT_uses'        => ! isset($ticket_data['TKT_uses']) || $ticket_data['TKT_uses'] === ''
516
-                    ? EE_INF
517
-                    : $ticket_data['TKT_uses'],
518
-                'TKT_min'         => empty($ticket_data['TKT_min']) ? 0 : $ticket_data['TKT_min'],
519
-                'TKT_max'         => empty($ticket_data['TKT_max']) ? EE_INF : $ticket_data['TKT_max'],
520
-                'TKT_row'         => $row,
521
-                'TKT_order'       => $ticket_data['TKT_order'] ?? 0,
522
-                'TKT_taxable'     => ! empty($ticket_data['TKT_taxable']) ? 1 : 0,
523
-                'TKT_required'    => ! empty($ticket_data['TKT_required']) ? 1 : 0,
524
-                'TKT_price'       => $ticket_price,
525
-            ];
526
-            // if this is a default TKT, then we need to set the TKT_ID to 0 and update accordingly,
527
-            // which means in turn that the prices will become new prices as well.
528
-            if (isset($ticket_data['TKT_is_default']) && $ticket_data['TKT_is_default']) {
529
-                $TKT_values['TKT_ID']         = 0;
530
-                $TKT_values['TKT_is_default'] = 0;
531
-                $update_prices                = true;
532
-            }
533
-            // if we have a TKT_ID then we need to get that existing TKT_obj and update it
534
-            // we actually do our saves ahead of doing any add_relations to
535
-            // because its entirely possible that this ticket wasn't removed or added to any datetime in the session
536
-            // but DID have it's items modified.
537
-            // keep in mind that if the TKT has been sold (and we have changed pricing information),
538
-            // then we won't be updating the ticket but instead a new ticket will be created and the old one archived.
539
-            if (absint($TKT_values['TKT_ID'])) {
540
-                $ticket = EEM_Ticket::instance($timezone)->get_one_by_ID($ticket_data['TKT_ID']);
541
-                if ($ticket instanceof EE_Ticket) {
542
-                    $ticket = $this->_update_ticket_datetimes(
543
-                        $ticket,
544
-                        $saved_datetimes,
545
-                        $datetimes_added,
546
-                        $datetimes_removed
547
-                    );
548
-                    // are there any registrations using this ticket ?
549
-                    $tickets_sold = $ticket->count_related(
550
-                        'Registration',
551
-                        [
552
-                            [
553
-                                'STS_ID' => ['NOT IN', [EEM_Registration::status_id_incomplete]],
554
-                            ],
555
-                        ]
556
-                    );
557
-                    // set ticket formats
558
-                    $ticket->set_date_format($this->_date_format_strings['date']);
559
-                    $ticket->set_time_format($this->_date_format_strings['time']);
560
-                    // let's just check the total price for the existing ticket
561
-                    // and determine if it matches the new total price.
562
-                    // if they are different then we create a new ticket (if tickets sold)
563
-                    // if they aren't different then we go ahead and modify existing ticket.
564
-                    $create_new_TKT = $tickets_sold > 0 && $ticket_price !== $ticket->price() && ! $ticket->deleted();
565
-                    // set new values
566
-                    foreach ($TKT_values as $field => $value) {
567
-                        if ($field === 'TKT_qty') {
568
-                            $ticket->set_qty($value);
569
-                        } else {
570
-                            $ticket->set($field, $value);
571
-                        }
572
-                    }
573
-                    // if $create_new_TKT is false then we can safely update the existing ticket.
574
-                    // Otherwise we have to create a new ticket.
575
-                    if ($create_new_TKT) {
576
-                        $new_ticket = $this->_duplicate_ticket(
577
-                            $ticket,
578
-                            $price_rows,
579
-                            $ticket_price,
580
-                            $base_price,
581
-                            $base_price_id
582
-                        );
583
-                    }
584
-                }
585
-            } else {
586
-                // no TKT_id so a new TKT
587
-                $ticket = EE_Ticket::new_instance(
588
-                    $TKT_values,
589
-                    $timezone,
590
-                    [$this->_date_format_strings['date'], $this->_date_format_strings['time']]
591
-                );
592
-                if ($ticket instanceof EE_Ticket) {
593
-                    // make sure ticket has an ID of setting relations won't work
594
-                    $ticket->save();
595
-                    $ticket        = $this->_update_ticket_datetimes(
596
-                        $ticket,
597
-                        $saved_datetimes,
598
-                        $datetimes_added,
599
-                        $datetimes_removed
600
-                    );
601
-                    $update_prices = true;
602
-                }
603
-            }
604
-            // make sure any current values have been saved.
605
-            // $ticket->save();
606
-            // before going any further make sure our dates are setup correctly
607
-            // so that the end date is always equal or greater than the start date.
608
-            if ($ticket->get_raw('TKT_start_date') > $ticket->get_raw('TKT_end_date')) {
609
-                $ticket->set('TKT_end_date', $ticket->get('TKT_start_date'));
610
-                $ticket = EEH_DTT_Helper::date_time_add($ticket, 'TKT_end_date', 'days');
611
-            }
612
-            // let's make sure the base price is handled
613
-            $ticket = ! $create_new_TKT
614
-                ? $this->_add_prices_to_ticket(
615
-                    [],
616
-                    $ticket,
617
-                    $update_prices,
618
-                    $base_price,
619
-                    $base_price_id
620
-                )
621
-                : $ticket;
622
-            // add/update price_modifiers
623
-            $ticket = ! $create_new_TKT
624
-                ? $this->_add_prices_to_ticket($price_rows, $ticket, $update_prices)
625
-                : $ticket;
626
-            // need to make sue that the TKT_price is accurate after saving the prices.
627
-            $ticket->ensure_TKT_Price_correct();
628
-            // handle CREATING a default ticket from the incoming ticket but ONLY if this isn't an autosave.
629
-            if (! defined('DOING_AUTOSAVE') && ! empty($ticket_data['TKT_is_default_selector'])) {
630
-                $new_default = clone $ticket;
631
-                $new_default->set('TKT_ID', 0);
632
-                $new_default->set('TKT_is_default', 1);
633
-                $new_default->set('TKT_row', 1);
634
-                $new_default->set('TKT_price', $ticket_price);
635
-                // remove any datetime relations cause we DON'T want datetime relations attached
636
-                // (note this is just removing the cached relations in the object)
637
-                $new_default->_remove_relations('Datetime');
638
-                // @todo we need to add the current attached prices as new prices to the new default ticket.
639
-                $new_default = $this->_add_prices_to_ticket(
640
-                    $price_rows,
641
-                    $new_default,
642
-                    true
643
-                );
644
-                // don't forget the base price!
645
-                $new_default = $this->_add_prices_to_ticket(
646
-                    [],
647
-                    $new_default,
648
-                    true,
649
-                    $base_price,
650
-                    $base_price_id
651
-                );
652
-                $new_default->save();
653
-                do_action(
654
-                    'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_default_ticket',
655
-                    $new_default,
656
-                    $row,
657
-                    $ticket,
658
-                    $data
659
-                );
660
-            }
661
-            // DO ALL datetime relationships for both current tickets and any archived tickets
662
-            // for the given datetime that are related to the current ticket.
663
-            // TODO... not sure exactly how we're going to do this considering we don't know
664
-            // what current ticket the archived tickets are related to
665
-            // (and TKT_parent is used for autosaves so that's not a field we can reliably use).
666
-            // let's assign any tickets that have been setup to the saved_tickets tracker
667
-            // save existing TKT
668
-            $ticket->save();
669
-            if ($create_new_TKT && $new_ticket instanceof EE_Ticket) {
670
-                // save new TKT
671
-                $new_ticket->save();
672
-                // add new ticket to array
673
-                $saved_tickets[ $new_ticket->ID() ] = $new_ticket;
674
-                do_action(
675
-                    'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_ticket',
676
-                    $new_ticket,
677
-                    $row,
678
-                    $ticket_data,
679
-                    $data
680
-                );
681
-            } else {
682
-                // add ticket to saved tickets
683
-                $saved_tickets[ $ticket->ID() ] = $ticket;
684
-                do_action(
685
-                    'AHEE__espresso_events_Pricing_Hooks___update_tkts_update_ticket',
686
-                    $ticket,
687
-                    $row,
688
-                    $ticket_data,
689
-                    $data
690
-                );
691
-            }
692
-        }
693
-        // now we need to handle tickets actually "deleted permanently".
694
-        // There are cases where we'd want this to happen
695
-        // (i.e. autosaves are happening and then in between autosaves the user trashes a ticket).
696
-        // Or a draft event was saved and in the process of editing a ticket is trashed.
697
-        // No sense in keeping all the related data in the db!
698
-        $old_tickets     = isset($old_tickets[0]) && $old_tickets[0] === '' ? [] : $old_tickets;
699
-        $tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
700
-        foreach ($tickets_removed as $id) {
701
-            $id = absint($id);
702
-            // get the ticket for this id
703
-            $ticket_to_remove = EE_Registry::instance()->load_model('Ticket')->get_one_by_ID($id);
704
-            // if this ticket is a default ticket we leave it alone cause it won't be attached to the datetime
705
-            if ($ticket_to_remove->get('TKT_is_default')) {
706
-                continue;
707
-            }
708
-            // if this ticket has any registrations attached so then we just ARCHIVE
709
-            // because we don't actually permanently delete these tickets.
710
-            if ($ticket_to_remove->count_related('Registration') > 0) {
711
-                $ticket_to_remove->delete();
712
-                continue;
713
-            }
714
-            // need to get all the related datetimes on this ticket and remove from every single one of them
715
-            // (remember this process can ONLY kick off if there are NO tickets_sold)
716
-            $datetimes = $ticket_to_remove->get_many_related('Datetime');
717
-            foreach ($datetimes as $datetime) {
718
-                $ticket_to_remove->_remove_relation_to($datetime, 'Datetime');
719
-            }
720
-            // need to do the same for prices (except these prices can also be deleted because again,
721
-            // tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
722
-            $ticket_to_remove->delete_related_permanently('Price');
723
-            do_action('AHEE__espresso_events_Pricing_Hooks___update_tkts_delete_ticket', $ticket_to_remove);
724
-            // finally let's delete this ticket
725
-            // (which should not be blocked at this point b/c we've removed all our relationships)
726
-            $ticket_to_remove->delete_permanently();
727
-        }
728
-        return $saved_tickets;
729
-    }
730
-
731
-
732
-    /**
733
-     * @access  protected
734
-     * @param EE_Ticket     $ticket
735
-     * @param EE_Datetime[] $saved_datetimes
736
-     * @param int[]         $added_datetimes
737
-     * @param int[]         $removed_datetimes
738
-     * @return EE_Ticket
739
-     * @throws EE_Error
740
-     * @throws ReflectionException
741
-     */
742
-    protected function _update_ticket_datetimes(
743
-        EE_Ticket $ticket,
744
-        array $saved_datetimes = [],
745
-        array $added_datetimes = [],
746
-        array $removed_datetimes = []
747
-    ): EE_Ticket {
748
-        // to start we have to add the ticket to all the datetimes its supposed to be with,
749
-        // and removing the ticket from datetimes it got removed from.
750
-        // first let's add datetimes
751
-        if (! empty($added_datetimes) && is_array($added_datetimes)) {
752
-            foreach ($added_datetimes as $row_id) {
753
-                if (isset($saved_datetimes[ $row_id ]) && $saved_datetimes[ $row_id ] instanceof EE_Datetime) {
754
-                    $ticket->_add_relation_to($saved_datetimes[ $row_id ], 'Datetime');
755
-                }
756
-            }
757
-        }
758
-        // then remove datetimes
759
-        if (! empty($removed_datetimes) && is_array($removed_datetimes)) {
760
-            foreach ($removed_datetimes as $row_id) {
761
-                // its entirely possible that a datetime got deleted (instead of just removed from relationship.
762
-                // So make sure we skip over this if the datetime isn't in the $saved_datetimes array)
763
-                if (isset($saved_datetimes[ $row_id ]) && $saved_datetimes[ $row_id ] instanceof EE_Datetime) {
764
-                    $ticket->_remove_relation_to($saved_datetimes[ $row_id ], 'Datetime');
765
-                }
766
-            }
767
-        }
768
-        // cap ticket qty by datetime reg limits
769
-        $ticket->set_qty(min($ticket->qty(), $ticket->qty('reg_limit')));
770
-        return $ticket;
771
-    }
772
-
773
-
774
-    /**
775
-     * @access  protected
776
-     * @param EE_Ticket $ticket
777
-     * @param array     $price_rows
778
-     * @param int|float $ticket_price
779
-     * @param int|float $base_price
780
-     * @param int       $base_price_id
781
-     * @return EE_Ticket
782
-     * @throws ReflectionException
783
-     * @throws InvalidArgumentException
784
-     * @throws InvalidInterfaceException
785
-     * @throws InvalidDataTypeException
786
-     * @throws EE_Error
787
-     */
788
-    protected function _duplicate_ticket(
789
-        EE_Ticket $ticket,
790
-        array $price_rows = [],
791
-        $ticket_price = 0,
792
-        $base_price = 0,
793
-        int $base_price_id = 0
794
-    ): EE_Ticket {
795
-        // create new ticket that's a copy of the existing
796
-        // except a new id of course (and not archived)
797
-        // AND has the new TKT_price associated with it.
798
-        $new_ticket = clone $ticket;
799
-        $new_ticket->set('TKT_ID', 0);
800
-        $new_ticket->set_deleted(0);
801
-        $new_ticket->set_price($ticket_price);
802
-        $new_ticket->set_sold(0);
803
-        // let's get a new ID for this ticket
804
-        $new_ticket->save();
805
-        // we also need to make sure this new ticket gets the same datetime attachments as the archived ticket
806
-        $datetimes_on_existing = $ticket->datetimes();
807
-        $new_ticket            = $this->_update_ticket_datetimes(
808
-            $new_ticket,
809
-            $datetimes_on_existing,
810
-            array_keys($datetimes_on_existing)
811
-        );
812
-        // $ticket will get archived later b/c we are NOT adding it to the saved_tickets array.
813
-        // if existing $ticket has sold amount, then we need to adjust the qty for the new TKT to = the remaining
814
-        // available.
815
-        if ($ticket->sold() > 0) {
816
-            $new_qty = $ticket->qty() - $ticket->sold();
817
-            $new_ticket->set_qty($new_qty);
818
-        }
819
-        // now we update the prices just for this ticket
820
-        $new_ticket = $this->_add_prices_to_ticket($price_rows, $new_ticket, true);
821
-        // and we update the base price
822
-        return $this->_add_prices_to_ticket(
823
-            [],
824
-            $new_ticket,
825
-            true,
826
-            $base_price,
827
-            $base_price_id
828
-        );
829
-    }
830
-
831
-
832
-    /**
833
-     * This attaches a list of given prices to a ticket.
834
-     * Note we dont' have to worry about ever removing relationships (or archiving prices) because if there is a change
835
-     * in price information on a ticket, a new ticket is created anyways so the archived ticket will retain the old
836
-     * price info and prices are automatically "archived" via the ticket.
837
-     *
838
-     * @access  private
839
-     * @param array     $prices        Array of prices from the form.
840
-     * @param EE_Ticket $ticket        EE_Ticket object that prices are being attached to.
841
-     * @param bool      $new_prices    Whether attach existing incoming prices or create new ones.
842
-     * @param int|bool  $base_price    if FALSE then NOT doing a base price add.
843
-     * @param int|bool  $base_price_id if present then this is the base_price_id being updated.
844
-     * @return EE_Ticket
845
-     * @throws ReflectionException
846
-     * @throws InvalidArgumentException
847
-     * @throws InvalidInterfaceException
848
-     * @throws InvalidDataTypeException
849
-     * @throws EE_Error
850
-     */
851
-    protected function _add_prices_to_ticket(
852
-        array $prices,
853
-        EE_Ticket $ticket,
854
-        bool $new_prices = false,
855
-        $base_price = false,
856
-        $base_price_id = false
857
-    ): EE_Ticket {
858
-        // let's just get any current prices that may exist on the given ticket
859
-        // so we can remove any prices that got trashed in this session.
860
-        $current_prices_on_ticket = $base_price !== false
861
-            ? $ticket->base_price(true)
862
-            : $ticket->price_modifiers();
863
-        $updated_prices           = [];
864
-        // if $base_price ! FALSE then updating a base price.
865
-        if ($base_price !== false) {
866
-            $prices[1] = [
867
-                'PRC_ID'     => $new_prices || $base_price_id === 1 ? null : $base_price_id,
868
-                'PRT_ID'     => 1,
869
-                'PRC_amount' => $base_price,
870
-                'PRC_name'   => $ticket->get('TKT_name'),
871
-                'PRC_desc'   => $ticket->get('TKT_description'),
872
-            ];
873
-        }
874
-        // possibly need to save ticket
875
-        if (! $ticket->ID()) {
876
-            $ticket->save();
877
-        }
878
-        foreach ($prices as $row => $prc) {
879
-            $prt_id = ! empty($prc['PRT_ID']) ? $prc['PRT_ID'] : null;
880
-            if (empty($prt_id)) {
881
-                continue;
882
-            } //prices MUST have a price type id.
883
-            $PRC_values = [
884
-                'PRC_ID'         => ! empty($prc['PRC_ID']) ? $prc['PRC_ID'] : null,
885
-                'PRT_ID'         => $prt_id,
886
-                'PRC_amount'     => ! empty($prc['PRC_amount']) ? $prc['PRC_amount'] : 0,
887
-                'PRC_name'       => ! empty($prc['PRC_name']) ? $prc['PRC_name'] : '',
888
-                'PRC_desc'       => ! empty($prc['PRC_desc']) ? $prc['PRC_desc'] : '',
889
-                'PRC_is_default' => false,
890
-                // make sure we set PRC_is_default to false for all ticket saves from event_editor
891
-                'PRC_order'      => $row,
892
-            ];
893
-            if ($new_prices || empty($PRC_values['PRC_ID'])) {
894
-                $PRC_values['PRC_ID'] = 0;
895
-                $price                = EE_Registry::instance()->load_class(
896
-                    'Price',
897
-                    [$PRC_values],
898
-                    false,
899
-                    false
900
-                );
901
-            } else {
902
-                $price = EE_Registry::instance()->load_model('Price')->get_one_by_ID($prc['PRC_ID']);
903
-                // update this price with new values
904
-                foreach ($PRC_values as $field => $value) {
905
-                    $price->set($field, $value);
906
-                }
907
-            }
908
-            $price->save();
909
-            $updated_prices[ $price->ID() ] = $price;
910
-            $ticket->_add_relation_to($price, 'Price');
911
-        }
912
-        // now let's remove any prices that got removed from the ticket
913
-        if (! empty($current_prices_on_ticket)) {
914
-            $current          = array_keys($current_prices_on_ticket);
915
-            $updated          = array_keys($updated_prices);
916
-            $prices_to_remove = array_diff($current, $updated);
917
-            if (! empty($prices_to_remove)) {
918
-                foreach ($prices_to_remove as $prc_id) {
919
-                    $p = $current_prices_on_ticket[ $prc_id ];
920
-                    $ticket->_remove_relation_to($p, 'Price');
921
-                    // delete permanently the price
922
-                    $p->delete_permanently();
923
-                }
924
-            }
925
-        }
926
-        return $ticket;
927
-    }
928
-
929
-
930
-    /**
931
-     * @throws ReflectionException
932
-     * @throws InvalidArgumentException
933
-     * @throws InvalidInterfaceException
934
-     * @throws InvalidDataTypeException
935
-     * @throws DomainException
936
-     * @throws EE_Error
937
-     */
938
-    public function pricing_metabox()
939
-    {
940
-        $existing_datetime_ids = $existing_ticket_ids = $datetime_tickets = $ticket_datetimes = [];
941
-        $event                 = $this->_adminpage_obj->get_cpt_model_obj();
942
-
943
-        // set is_creating_event property.
944
-        $EVT_ID                   = $event->ID();
945
-        $this->_is_creating_event = empty($this->_req_data['post']);
946
-
947
-        // default main template args
948
-        $main_template_args = [
949
-            'event_datetime_help_link' => EEH_Template::get_help_tab_link(
950
-                'event_editor_event_datetimes_help_tab',
951
-                $this->_adminpage_obj->page_slug,
952
-                $this->_adminpage_obj->get_req_action()
953
-            ),
954
-
955
-            // todo need to add a filter to the template for the help text
956
-            // in the Events_Admin_Page core file so we can add further help
957
-            'add_new_dtt_help_link'    => EEH_Template::get_help_tab_link(
958
-                'add_new_dtt_info',
959
-                $this->_adminpage_obj->page_slug,
960
-                $this->_adminpage_obj->get_req_action()
961
-            ),
962
-            // todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
963
-            'datetime_rows'            => '',
964
-            'show_tickets_container'   => '',
965
-            'ticket_rows'              => '',
966
-            'ee_collapsible_status'    => ' ee-collapsible-open',
967
-        ];
968
-        $timezone           = $event instanceof EE_Event ? $event->timezone_string() : null;
969
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
970
-
971
-        /**
972
-         * 1. Start with retrieving Datetimes
973
-         * 2. For each datetime get related tickets
974
-         * 3. For each ticket get related prices
975
-         */
976
-        /** @var EEM_Datetime $datetime_model */
977
-        $datetime_model                       = EE_Registry::instance()->load_model('Datetime', [$timezone]);
978
-        $datetimes                            = $datetime_model->get_all_event_dates($EVT_ID);
979
-        $main_template_args['total_dtt_rows'] = count($datetimes);
980
-
981
-        /**
982
-         * @see https://events.codebasehq.com/projects/event-espresso/tickets/9486
983
-         * for why we are counting $datetime_row and then setting that on the Datetime object
984
-         */
985
-        $datetime_row = 1;
986
-        foreach ($datetimes as $datetime) {
987
-            $DTT_ID = $datetime->get('DTT_ID');
988
-            $datetime->set('DTT_order', $datetime_row);
989
-            $existing_datetime_ids[] = $DTT_ID;
990
-            // tickets attached
991
-            $related_tickets = $datetime->ID() > 0
992
-                ? $datetime->get_many_related(
993
-                    'Ticket',
994
-                    [
995
-                        [
996
-                            'OR' => ['TKT_deleted' => 1, 'TKT_deleted*' => 0],
997
-                        ],
998
-                        'default_where_conditions' => 'none',
999
-                        'order_by'                 => ['TKT_order' => 'ASC'],
1000
-                    ]
1001
-                )
1002
-                : [];
1003
-            // if there are no related tickets this is likely a new event OR auto-draft
1004
-            // event so we need to generate the default tickets because datetimes
1005
-            // ALWAYS have at least one related ticket!!.  EXCEPT, we dont' do this if there is already more than one
1006
-            // datetime on the event.
1007
-            if (empty($related_tickets) && count($datetimes) < 2) {
1008
-                /** @var EEM_Ticket $ticket_model */
1009
-                $ticket_model    = EE_Registry::instance()->load_model('Ticket');
1010
-                $related_tickets = $ticket_model->get_all_default_tickets();
1011
-                // this should be ordered by TKT_ID, so let's grab the first default ticket
1012
-                // (which will be the main default) and ensure it has any default prices added to it (but do NOT save).
1013
-                $default_prices      = EEM_Price::instance()->get_all_default_prices();
1014
-                $main_default_ticket = reset($related_tickets);
1015
-                if ($main_default_ticket instanceof EE_Ticket) {
1016
-                    foreach ($default_prices as $default_price) {
1017
-                        if ($default_price instanceof EE_Price && $default_price->is_base_price()) {
1018
-                            continue;
1019
-                        }
1020
-                        $main_default_ticket->cache('Price', $default_price);
1021
-                    }
1022
-                }
1023
-            }
1024
-            // we can't actually setup rows in this loop yet cause we don't know all
1025
-            // the unique tickets for this event yet (tickets are linked through all datetimes).
1026
-            // So we're going to temporarily cache some of that information.
1027
-            // loop through and setup the ticket rows and make sure the order is set.
1028
-            foreach ($related_tickets as $ticket) {
1029
-                $TKT_ID     = $ticket->get('TKT_ID');
1030
-                $ticket_row = $ticket->get('TKT_row');
1031
-                // we only want unique tickets in our final display!!
1032
-                if (! in_array($TKT_ID, $existing_ticket_ids, true)) {
1033
-                    $existing_ticket_ids[] = $TKT_ID;
1034
-                    $all_tickets[]         = $ticket;
1035
-                }
1036
-                // temporary cache of this ticket info for this datetime for later processing of datetime rows.
1037
-                $datetime_tickets[ $DTT_ID ][] = $ticket_row;
1038
-                // temporary cache of this datetime info for this ticket for later processing of ticket rows.
1039
-                if (
1040
-                    ! isset($ticket_datetimes[ $TKT_ID ])
1041
-                    || ! in_array($datetime_row, $ticket_datetimes[ $TKT_ID ], true)
1042
-                ) {
1043
-                    $ticket_datetimes[ $TKT_ID ][] = $datetime_row;
1044
-                }
1045
-            }
1046
-            $datetime_row++;
1047
-        }
1048
-        $main_template_args['total_ticket_rows']     = count($existing_ticket_ids);
1049
-        $main_template_args['existing_ticket_ids']   = implode(',', $existing_ticket_ids);
1050
-        $main_template_args['existing_datetime_ids'] = implode(',', $existing_datetime_ids);
1051
-        // sort $all_tickets by order
1052
-        usort(
1053
-            $all_tickets,
1054
-            function (EE_Ticket $a, EE_Ticket $b) {
1055
-                $a_order = (int) $a->get('TKT_order');
1056
-                $b_order = (int) $b->get('TKT_order');
1057
-                if ($a_order === $b_order) {
1058
-                    return 0;
1059
-                }
1060
-                return ($a_order < $b_order) ? -1 : 1;
1061
-            }
1062
-        );
1063
-        // k NOW we have all the data we need for setting up the datetime rows
1064
-        // and ticket rows so we start our datetime loop again.
1065
-        $datetime_row = 1;
1066
-        foreach ($datetimes as $datetime) {
1067
-            $main_template_args['datetime_rows'] .= $this->_get_datetime_row(
1068
-                $datetime_row,
1069
-                $datetime,
1070
-                $datetime_tickets,
1071
-                $all_tickets,
1072
-                false,
1073
-                $datetimes
1074
-            );
1075
-            $datetime_row++;
1076
-        }
1077
-        // then loop through all tickets for the ticket rows.
1078
-        $ticket_row = 1;
1079
-        foreach ($all_tickets as $ticket) {
1080
-            $main_template_args['ticket_rows'] .= $this->_get_ticket_row(
1081
-                $ticket_row,
1082
-                $ticket,
1083
-                $ticket_datetimes,
1084
-                $datetimes,
1085
-                false,
1086
-                $all_tickets
1087
-            );
1088
-            $ticket_row++;
1089
-        }
1090
-        $main_template_args['ticket_js_structure'] = $this->_get_ticket_js_structure($datetimes, $all_tickets);
1091
-
1092
-        $status_change_notice = LoaderFactory::getLoader()->getShared(
1093
-            'EventEspresso\core\domain\services\admin\notices\status_change\StatusChangeNotice'
1094
-        );
1095
-
1096
-        $main_template_args['status_change_notice'] = $status_change_notice->display(
1097
-            '__event-editor',
1098
-            'espresso-events'
1099
-        );
1100
-
1101
-        EEH_Template::display_template(
1102
-            PRICING_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php',
1103
-            $main_template_args
1104
-        );
1105
-    }
1106
-
1107
-
1108
-    /**
1109
-     * @param int         $datetime_row
1110
-     * @param EE_Datetime $datetime
1111
-     * @param array       $datetime_tickets
1112
-     * @param array       $all_tickets
1113
-     * @param bool        $default
1114
-     * @param array       $all_datetimes
1115
-     * @return string
1116
-     * @throws DomainException
1117
-     * @throws EE_Error
1118
-     * @throws ReflectionException
1119
-     */
1120
-    protected function _get_datetime_row(
1121
-        int $datetime_row,
1122
-        EE_Datetime $datetime,
1123
-        array $datetime_tickets = [],
1124
-        array $all_tickets = [],
1125
-        bool $default = false,
1126
-        array $all_datetimes = []
1127
-    ): string {
1128
-        return EEH_Template::display_template(
1129
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_row_wrapper.template.php',
1130
-            [
1131
-                'dtt_edit_row'             => $this->_get_dtt_edit_row(
1132
-                    $datetime_row,
1133
-                    $datetime,
1134
-                    $default,
1135
-                    $all_datetimes
1136
-                ),
1137
-                'dtt_attached_tickets_row' => $this->_get_dtt_attached_tickets_row(
1138
-                    $datetime_row,
1139
-                    $datetime,
1140
-                    $datetime_tickets,
1141
-                    $all_tickets,
1142
-                    $default
1143
-                ),
1144
-                'dtt_row'                  => $default ? 'DTTNUM' : $datetime_row,
1145
-            ],
1146
-            true
1147
-        );
1148
-    }
1149
-
1150
-
1151
-    /**
1152
-     * This method is used to generate a datetime fields  edit row.
1153
-     * The same row is used to generate a row with valid DTT objects
1154
-     * and the default row that is used as the skeleton by the js.
1155
-     *
1156
-     * @param int              $datetime_row  The row number for the row being generated.
1157
-     * @param EE_Datetime|null $datetime
1158
-     * @param bool             $default       Whether a default row is being generated or not.
1159
-     * @param EE_Datetime[]    $all_datetimes This is the array of all datetimes used in the editor.
1160
-     * @return string
1161
-     * @throws EE_Error
1162
-     * @throws ReflectionException
1163
-     */
1164
-    protected function _get_dtt_edit_row(
1165
-        int $datetime_row,
1166
-        ?EE_Datetime $datetime,
1167
-        bool $default,
1168
-        array $all_datetimes
1169
-    ): string {
1170
-        // if the incoming $datetime object is NOT an instance of EE_Datetime then force default to true.
1171
-        $default                     = ! $datetime instanceof EE_Datetime ? true : $default;
1172
-        $template_args               = [
1173
-            'dtt_row'              => $default ? 'DTTNUM' : $datetime_row,
1174
-            'event_datetimes_name' => $default ? 'DTTNAMEATTR' : 'edit_event_datetimes',
1175
-            'edit_dtt_expanded'    => '',
1176
-            'DTT_ID'               => $default ? '' : $datetime->ID(),
1177
-            'DTT_name'             => $default ? '' : $datetime->get_f('DTT_name'),
1178
-            'DTT_description'      => $default ? '' : $datetime->get_f('DTT_description'),
1179
-            'DTT_EVT_start'        => $default ? '' : $datetime->start_date($this->_date_time_format),
1180
-            'DTT_EVT_end'          => $default ? '' : $datetime->end_date($this->_date_time_format),
1181
-            'DTT_reg_limit'        => $default
1182
-                ? ''
1183
-                : $datetime->get_pretty(
1184
-                    'DTT_reg_limit',
1185
-                    'input'
1186
-                ),
1187
-            'DTT_order'            => $default ? 'DTTNUM' : $datetime_row,
1188
-            'dtt_sold'             => $default ? '0' : $datetime->get('DTT_sold'),
1189
-            'dtt_reserved'         => $default ? '0' : $datetime->reserved(),
1190
-            'clone_icon'           => ! empty($datetime) && $datetime->get('DTT_sold') > 0
1191
-                ? ''
1192
-                : 'clone-icon ee-icon ee-icon-clone clickable',
1193
-            'trash_icon'           => ! empty($datetime) && $datetime->get('DTT_sold') > 0
1194
-                ? 'dashicons dashicons-lock'
1195
-                : 'trash-icon dashicons dashicons-post-trash clickable',
1196
-            'reg_list_url'         => $default || ! $datetime->event() instanceof EE_Event
1197
-                ? ''
1198
-                : EE_Admin_Page::add_query_args_and_nonce(
1199
-                    ['event_id' => $datetime->event()->ID(), 'datetime_id' => $datetime->ID()],
1200
-                    REG_ADMIN_URL
1201
-                ),
1202
-        ];
1203
-        $template_args['show_trash'] = count($all_datetimes) === 1
1204
-                                       && $template_args['trash_icon'] !== 'dashicons dashicons-lock'
1205
-            ? 'display:none'
1206
-            : '';
1207
-        // allow filtering of template args at this point.
1208
-        $template_args = apply_filters(
1209
-            'FHEE__espresso_events_Pricing_Hooks___get_dtt_edit_row__template_args',
1210
-            $template_args,
1211
-            $datetime_row,
1212
-            $datetime,
1213
-            $default,
1214
-            $all_datetimes,
1215
-            $this->_is_creating_event
1216
-        );
1217
-        return EEH_Template::display_template(
1218
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_edit_row.template.php',
1219
-            $template_args,
1220
-            true
1221
-        );
1222
-    }
1223
-
1224
-
1225
-    /**
1226
-     * @param int         $datetime_row
1227
-     * @param EE_Datetime $datetime
1228
-     * @param array       $datetime_tickets
1229
-     * @param array       $all_tickets
1230
-     * @param bool        $default
1231
-     * @return string
1232
-     * @throws DomainException
1233
-     * @throws EE_Error
1234
-     * @throws ReflectionException
1235
-     */
1236
-    protected function _get_dtt_attached_tickets_row(
1237
-        int $datetime_row,
1238
-        EE_Datetime $datetime,
1239
-        array $datetime_tickets = [],
1240
-        array $all_tickets = [],
1241
-        bool $default = false
1242
-    ): string {
1243
-        $template_args = [
1244
-            'dtt_row'                           => $default ? 'DTTNUM' : $datetime_row,
1245
-            'event_datetimes_name'              => $default ? 'DTTNAMEATTR' : 'edit_event_datetimes',
1246
-            'DTT_description'                   => $default ? '' : $datetime->get_f('DTT_description'),
1247
-            'datetime_tickets_list'             => $default ? '<li class="hidden"></li>' : '',
1248
-            'show_tickets_row'                  => 'display:none;',
1249
-            'add_new_datetime_ticket_help_link' => EEH_Template::get_help_tab_link(
1250
-                'add_new_ticket_via_datetime',
1251
-                $this->_adminpage_obj->page_slug,
1252
-                $this->_adminpage_obj->get_req_action()
1253
-            ),
1254
-            // todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
1255
-            'DTT_ID'                            => $default ? '' : $datetime->ID(),
1256
-        ];
1257
-        // need to setup the list items (but only if this isn't a default skeleton setup)
1258
-        if (! $default) {
1259
-            $ticket_row = 1;
1260
-            foreach ($all_tickets as $ticket) {
1261
-                $template_args['datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
1262
-                    $datetime_row,
1263
-                    $ticket_row,
1264
-                    $datetime,
1265
-                    $ticket,
1266
-                    $datetime_tickets,
1267
-                    $default
1268
-                );
1269
-                $ticket_row++;
1270
-            }
1271
-        }
1272
-        // filter template args at this point
1273
-        $template_args = apply_filters(
1274
-            'FHEE__espresso_events_Pricing_Hooks___get_dtt_attached_ticket_row__template_args',
1275
-            $template_args,
1276
-            $datetime_row,
1277
-            $datetime,
1278
-            $datetime_tickets,
1279
-            $all_tickets,
1280
-            $default,
1281
-            $this->_is_creating_event
1282
-        );
1283
-        return EEH_Template::display_template(
1284
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_attached_tickets_row.template.php',
1285
-            $template_args,
1286
-            true
1287
-        );
1288
-    }
1289
-
1290
-
1291
-    /**
1292
-     * @param int              $datetime_row
1293
-     * @param int              $ticket_row
1294
-     * @param EE_Datetime|null $datetime
1295
-     * @param EE_Ticket|null   $ticket
1296
-     * @param array            $datetime_tickets
1297
-     * @param bool             $default
1298
-     * @return string
1299
-     * @throws EE_Error
1300
-     * @throws ReflectionException
1301
-     */
1302
-    protected function _get_datetime_tickets_list_item(
1303
-        int $datetime_row,
1304
-        int $ticket_row,
1305
-        ?EE_Datetime $datetime,
1306
-        ?EE_Ticket $ticket,
1307
-        array $datetime_tickets = [],
1308
-        bool $default = false
1309
-    ): string {
1310
-        $datetime_tickets = $datetime instanceof EE_Datetime && isset($datetime_tickets[ $datetime->ID() ])
1311
-            ? $datetime_tickets[ $datetime->ID() ]
1312
-            : [];
1313
-        $display_row      = $ticket instanceof EE_Ticket ? $ticket->get('TKT_row') : 0;
1314
-        $no_ticket        = $default && empty($ticket);
1315
-        $template_args    = [
1316
-            'dtt_row'                 => $default
1317
-                ? 'DTTNUM'
1318
-                : $datetime_row,
1319
-            'tkt_row'                 => $no_ticket
1320
-                ? 'TICKETNUM'
1321
-                : $ticket_row,
1322
-            'datetime_ticket_checked' => in_array($display_row, $datetime_tickets, true)
1323
-                ? ' checked'
1324
-                : '',
1325
-            'ticket_selected'         => in_array($display_row, $datetime_tickets, true)
1326
-                ? ' ticket-selected'
1327
-                : '',
1328
-            'TKT_name'                => $no_ticket
1329
-                ? 'TKTNAME'
1330
-                : $ticket->get('TKT_name'),
1331
-            'tkt_status_class'        => $no_ticket || $this->_is_creating_event
1332
-                ? ' tkt-status-' . EE_Ticket::onsale
1333
-                : ' tkt-status-' . $ticket->ticket_status(),
1334
-        ];
1335
-        // filter template args
1336
-        $template_args = apply_filters(
1337
-            'FHEE__espresso_events_Pricing_Hooks___get_datetime_tickets_list_item__template_args',
1338
-            $template_args,
1339
-            $datetime_row,
1340
-            $ticket_row,
1341
-            $datetime,
1342
-            $ticket,
1343
-            $datetime_tickets,
1344
-            $default,
1345
-            $this->_is_creating_event
1346
-        );
1347
-        return EEH_Template::display_template(
1348
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_dtt_tickets_list.template.php',
1349
-            $template_args,
1350
-            true
1351
-        );
1352
-    }
1353
-
1354
-
1355
-    /**
1356
-     * This generates the ticket row for tickets.
1357
-     * This same method is used to generate both the actual rows and the js skeleton row
1358
-     * (when default === true)
1359
-     *
1360
-     * @param int            $ticket_row       Represents the row number being generated.
1361
-     * @param EE_Ticket|null $ticket
1362
-     * @param EE_Datetime[]  $ticket_datetimes Either an array of all datetimes on all tickets indexed by each ticket
1363
-     *                                         or empty for default
1364
-     * @param EE_Datetime[]  $all_datetimes    All Datetimes on the event or empty for default.
1365
-     * @param bool           $default          Whether default row being generated or not.
1366
-     * @param EE_Ticket[]    $all_tickets      This is an array of all tickets attached to the event
1367
-     *                                         (or empty in the case of defaults)
1368
-     * @return string
1369
-     * @throws InvalidArgumentException
1370
-     * @throws InvalidInterfaceException
1371
-     * @throws InvalidDataTypeException
1372
-     * @throws DomainException
1373
-     * @throws EE_Error
1374
-     * @throws ReflectionException
1375
-     */
1376
-    protected function _get_ticket_row(
1377
-        int $ticket_row,
1378
-        ?EE_Ticket $ticket,
1379
-        array $ticket_datetimes,
1380
-        array $all_datetimes,
1381
-        bool $default = false,
1382
-        array $all_tickets = []
1383
-    ): string {
1384
-        // if $ticket is not an instance of EE_Ticket then force default to true.
1385
-        $default = ! $ticket instanceof EE_Ticket ? true : $default;
1386
-        $prices  = ! empty($ticket) && ! $default
1387
-            ? $ticket->get_many_related(
1388
-                'Price',
1389
-                ['default_where_conditions' => 'none', 'order_by' => ['PRC_order' => 'ASC']]
1390
-            )
1391
-            : [];
1392
-        // if there is only one price (which would be the base price)
1393
-        // or NO prices and this ticket is a default ticket,
1394
-        // let's just make sure there are no cached default prices on the object.
1395
-        // This is done by not including any query_params.
1396
-        if ($ticket instanceof EE_Ticket && $ticket->is_default() && (count($prices) === 1 || empty($prices))) {
1397
-            $prices = $ticket->prices();
1398
-        }
1399
-        // check if we're dealing with a default ticket in which case
1400
-        // we don't want any starting_ticket_datetime_row values set
1401
-        // (otherwise there won't be any new relationships created for tickets based off of the default ticket).
1402
-        // This will future proof in case there is ever any behaviour change between what the primary_key defaults to.
1403
-        $default_datetime = $default || ($ticket instanceof EE_Ticket && $ticket->is_default());
1404
-        $ticket_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[ $ticket->ID() ])
1405
-            ? $ticket_datetimes[ $ticket->ID() ]
1406
-            : [];
1407
-        $ticket_subtotal  = $default ? 0 : $ticket->get_ticket_subtotal();
1408
-        $base_price       = $default ? null : $ticket->base_price();
1409
-        $count_price_mods = EEM_Price::instance()->get_all_default_prices(true);
1410
-        // breaking out complicated condition for ticket_status
1411
-        if ($default) {
1412
-            $ticket_status_class = ' tkt-status-' . EE_Ticket::onsale;
1413
-        } else {
1414
-            $ticket_status_class = $ticket->is_default()
1415
-                ? ' tkt-status-' . EE_Ticket::onsale
1416
-                : ' tkt-status-' . $ticket->ticket_status();
1417
-        }
1418
-        // breaking out complicated condition for TKT_taxable
1419
-        if ($default) {
1420
-            $TKT_taxable = '';
1421
-        } else {
1422
-            $TKT_taxable = $ticket->taxable()
1423
-                ? 'checked'
1424
-                : '';
1425
-        }
1426
-        if ($default) {
1427
-            $TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1428
-        } elseif ($ticket->is_default()) {
1429
-            $TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1430
-        } else {
1431
-            $TKT_status = $ticket->ticket_status(true);
1432
-        }
1433
-        if ($default) {
1434
-            $TKT_min = '';
1435
-        } else {
1436
-            $TKT_min = $ticket->min();
1437
-            if ($TKT_min === -1 || $TKT_min === 0) {
1438
-                $TKT_min = '';
1439
-            }
1440
-        }
1441
-        $template_args                 = [
1442
-            'tkt_row'                       => $default ? 'TICKETNUM' : $ticket_row,
1443
-            'TKT_order'                     => $default ? 'TICKETNUM' : $ticket_row,
1444
-            // on initial page load this will always be the correct order.
1445
-            'tkt_status_class'              => $ticket_status_class,
1446
-            'display_edit_tkt_row'          => 'display:none;',
1447
-            'edit_tkt_expanded'             => '',
1448
-            'edit_tickets_name'             => $default ? 'TICKETNAMEATTR' : 'edit_tickets',
1449
-            'TKT_name'                      => $default ? '' : $ticket->get_f('TKT_name'),
1450
-            'TKT_start_date'                => $default
1451
-                ? ''
1452
-                : $ticket->get_date('TKT_start_date', $this->_date_time_format),
1453
-            'TKT_end_date'                  => $default
1454
-                ? ''
1455
-                : $ticket->get_date('TKT_end_date', $this->_date_time_format),
1456
-            'TKT_status'                    => $TKT_status,
1457
-            'TKT_price'                     => $default
1458
-                ? ''
1459
-                : EEH_Template::format_currency(
1460
-                    $ticket->get_ticket_total_with_taxes(),
1461
-                    false,
1462
-                    false
1463
-                ),
1464
-            'TKT_price_code'                => EE_Registry::instance()->CFG->currency->code,
1465
-            'TKT_price_amount'              => $default ? 0 : $ticket_subtotal,
1466
-            'TKT_qty'                       => $default
1467
-                ? ''
1468
-                : $ticket->get_pretty('TKT_qty', 'symbol'),
1469
-            'TKT_qty_for_input'             => $default
1470
-                ? ''
1471
-                : $ticket->get_pretty('TKT_qty', 'input'),
1472
-            'TKT_uses'                      => $default
1473
-                ? ''
1474
-                : $ticket->get_pretty('TKT_uses', 'input'),
1475
-            'TKT_min'                       => $TKT_min,
1476
-            'TKT_max'                       => $default
1477
-                ? ''
1478
-                : $ticket->get_pretty('TKT_max', 'input'),
1479
-            'TKT_sold'                      => $default ? 0 : $ticket->tickets_sold(),
1480
-            'TKT_reserved'                  => $default ? 0 : $ticket->reserved(),
1481
-            'TKT_registrations'             => $default
1482
-                ? 0
1483
-                : $ticket->count_registrations(
1484
-                    [
1485
-                        [
1486
-                            'STS_ID' => [
1487
-                                '!=',
1488
-                                EEM_Registration::status_id_incomplete,
1489
-                            ],
1490
-                        ],
1491
-                    ]
1492
-                ),
1493
-            'TKT_ID'                        => $default ? 0 : $ticket->ID(),
1494
-            'TKT_description'               => $default ? '' : $ticket->get_f('TKT_description'),
1495
-            'TKT_is_default'                => $default ? 0 : $ticket->is_default(),
1496
-            'TKT_required'                  => $default ? 0 : $ticket->required(),
1497
-            'TKT_is_default_selector'       => '',
1498
-            'ticket_price_rows'             => '',
1499
-            'TKT_base_price'                => $default || ! $base_price instanceof EE_Price
1500
-                ? ''
1501
-                : $base_price->get_pretty('PRC_amount', 'localized_float'),
1502
-            'TKT_base_price_ID'             => $default || ! $base_price instanceof EE_Price ? 0 : $base_price->ID(),
1503
-            'show_price_modifier'           => count($prices) > 1 || ($default && $count_price_mods > 0)
1504
-                ? ''
1505
-                : 'display:none;',
1506
-            'show_price_mod_button'         => count($prices) > 1
1507
-                                               || ($default && $count_price_mods > 0)
1508
-                                               || (! $default && $ticket->deleted())
1509
-                ? 'display:none;'
1510
-                : '',
1511
-            'total_price_rows'              => count($prices) > 1 ? count($prices) : 1,
1512
-            'ticket_datetimes_list'         => $default ? '<li class="hidden"></li>' : '',
1513
-            'starting_ticket_datetime_rows' => $default || $default_datetime ? '' : implode(',', $ticket_datetimes),
1514
-            'ticket_datetime_rows'          => $default ? '' : implode(',', $ticket_datetimes),
1515
-            'existing_ticket_price_ids'     => $default ? '' : implode(',', array_keys($prices)),
1516
-            'ticket_template_id'            => $default ? 0 : $ticket->get('TTM_ID'),
1517
-            'TKT_taxable'                   => $TKT_taxable,
1518
-            'display_subtotal'              => $ticket instanceof EE_Ticket && $ticket->taxable()
1519
-                ? ''
1520
-                : 'display:none;',
1521
-            'price_currency_symbol'         => EE_Registry::instance()->CFG->currency->sign,
1522
-            'TKT_subtotal_amount_display'   => EEH_Template::format_currency(
1523
-                $ticket_subtotal,
1524
-                false,
1525
-                false
1526
-            ),
1527
-            'TKT_subtotal_amount'           => $ticket_subtotal,
1528
-            'tax_rows'                      => $this->_get_tax_rows($ticket_row, $ticket),
1529
-            'disabled'                      => $ticket instanceof EE_Ticket && $ticket->deleted(),
1530
-            'ticket_archive_class'          => $ticket instanceof EE_Ticket && $ticket->deleted()
1531
-                ? ' ticket-archived'
1532
-                : '',
1533
-            'trash_icon'                    => $ticket instanceof EE_Ticket
1534
-                                               && $ticket->deleted()
1535
-                                               && ! $ticket->is_permanently_deleteable()
1536
-                ? 'dashicons dashicons-lock '
1537
-                : 'trash-icon dashicons dashicons-post-trash clickable',
1538
-            'clone_icon'                    => $ticket instanceof EE_Ticket && $ticket->deleted()
1539
-                ? ''
1540
-                : 'clone-icon ee-icon ee-icon-clone clickable',
1541
-        ];
1542
-        $template_args['trash_hidden'] = count($all_tickets) === 1
1543
-                                         && $template_args['trash_icon'] !== 'dashicons dashicons-lock'
1544
-            ? 'display:none'
1545
-            : '';
1546
-        // handle rows that should NOT be empty
1547
-        if (empty($template_args['TKT_start_date'])) {
1548
-            // if empty then the start date will be now.
1549
-            $template_args['TKT_start_date']   = date(
1550
-                $this->_date_time_format,
1551
-                current_time('timestamp')
1552
-            );
1553
-            $template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1554
-        }
1555
-        if (empty($template_args['TKT_end_date'])) {
1556
-            // get the earliest datetime (if present);
1557
-            $earliest_datetime = $this->_adminpage_obj->get_cpt_model_obj()->ID() > 0
1558
-                ? $this->_adminpage_obj->get_cpt_model_obj()->get_first_related(
1559
-                    'Datetime',
1560
-                    ['order_by' => ['DTT_EVT_start' => 'ASC']]
1561
-                )
1562
-                : null;
1563
-            if (! empty($earliest_datetime)) {
1564
-                $template_args['TKT_end_date'] = $earliest_datetime->get_datetime(
1565
-                    'DTT_EVT_start',
1566
-                    $this->_date_time_format
1567
-                );
1568
-            } else {
1569
-                // default so let's just use what's been set for the default date-time which is 30 days from now.
1570
-                $template_args['TKT_end_date'] = date(
1571
-                    $this->_date_time_format,
1572
-                    mktime(
1573
-                        24,
1574
-                        0,
1575
-                        0,
1576
-                        date('m'),
1577
-                        date('d') + 29,
1578
-                        date('Y')
1579
-                    )
1580
-                );
1581
-            }
1582
-            $template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1583
-        }
1584
-        // generate ticket_datetime items
1585
-        if (! $default) {
1586
-            $datetime_row = 1;
1587
-            foreach ($all_datetimes as $datetime) {
1588
-                $template_args['ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
1589
-                    $datetime_row,
1590
-                    $ticket_row,
1591
-                    $datetime,
1592
-                    $ticket,
1593
-                    $ticket_datetimes,
1594
-                    $default
1595
-                );
1596
-                $datetime_row++;
1597
-            }
1598
-        }
1599
-        $price_row = 1;
1600
-        foreach ($prices as $price) {
1601
-            if (! $price instanceof EE_Price) {
1602
-                continue;
1603
-            }
1604
-            if ($price->is_base_price()) {
1605
-                $price_row++;
1606
-                continue;
1607
-            }
1608
-
1609
-            $show_trash  = ! ((count($prices) > 1 && $price_row === 1) || count($prices) === 1);
1610
-            $show_create = ! (count($prices) > 1 && count($prices) !== $price_row);
1611
-
1612
-            $template_args['ticket_price_rows'] .= $this->_get_ticket_price_row(
1613
-                $ticket_row,
1614
-                $price_row,
1615
-                $price,
1616
-                $default,
1617
-                $ticket,
1618
-                $show_trash,
1619
-                $show_create
1620
-            );
1621
-            $price_row++;
1622
-        }
1623
-        // filter $template_args
1624
-        $template_args = apply_filters(
1625
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_row__template_args',
1626
-            $template_args,
1627
-            $ticket_row,
1628
-            $ticket,
1629
-            $ticket_datetimes,
1630
-            $all_datetimes,
1631
-            $default,
1632
-            $all_tickets,
1633
-            $this->_is_creating_event
1634
-        );
1635
-        return EEH_Template::display_template(
1636
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_row.template.php',
1637
-            $template_args,
1638
-            true
1639
-        );
1640
-    }
1641
-
1642
-
1643
-    /**
1644
-     * @param int            $ticket_row
1645
-     * @param EE_Ticket|null $ticket
1646
-     * @return string
1647
-     * @throws DomainException
1648
-     * @throws EE_Error
1649
-     * @throws ReflectionException
1650
-     */
1651
-    protected function _get_tax_rows(int $ticket_row, ?EE_Ticket $ticket): string
1652
-    {
1653
-        $tax_rows = '';
1654
-        /** @var EE_Price[] $taxes */
1655
-        $taxes = empty($ticket) ? EE_Taxes::get_taxes_for_admin() : $ticket->get_ticket_taxes_for_admin();
1656
-        foreach ($taxes as $tax) {
1657
-            $tax_added     = $this->_get_tax_added($tax, $ticket);
1658
-            $template_args = [
1659
-                'display_tax'       => ! empty($ticket) && $ticket->get('TKT_taxable')
1660
-                    ? ''
1661
-                    : 'display:none;',
1662
-                'tax_id'            => $tax->ID(),
1663
-                'tkt_row'           => $ticket_row,
1664
-                'tax_label'         => $tax->get('PRC_name'),
1665
-                'tax_added'         => $tax_added,
1666
-                'tax_added_display' => EEH_Template::format_currency($tax_added, false, false),
1667
-                'tax_amount'        => $tax->get('PRC_amount'),
1668
-            ];
1669
-            $template_args = apply_filters(
1670
-                'FHEE__espresso_events_Pricing_Hooks___get_tax_rows__template_args',
1671
-                $template_args,
1672
-                $ticket_row,
1673
-                $ticket,
1674
-                $this->_is_creating_event
1675
-            );
1676
-            $tax_rows      .= EEH_Template::display_template(
1677
-                PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_tax_row.template.php',
1678
-                $template_args,
1679
-                true
1680
-            );
1681
-        }
1682
-        return $tax_rows;
1683
-    }
1684
-
1685
-
1686
-    /**
1687
-     * @param EE_Price       $tax
1688
-     * @param EE_Ticket|null $ticket
1689
-     * @return float|int
1690
-     * @throws EE_Error
1691
-     * @throws ReflectionException
1692
-     */
1693
-    protected function _get_tax_added(EE_Price $tax, ?EE_Ticket $ticket)
1694
-    {
1695
-        $subtotal = empty($ticket) ? 0 : $ticket->get_ticket_subtotal();
1696
-        return $subtotal * $tax->get('PRC_amount') / 100;
1697
-    }
1698
-
1699
-
1700
-    /**
1701
-     * @param int            $ticket_row
1702
-     * @param int            $price_row
1703
-     * @param EE_Price|null  $price
1704
-     * @param bool           $default
1705
-     * @param EE_Ticket|null $ticket
1706
-     * @param bool           $show_trash
1707
-     * @param bool           $show_create
1708
-     * @return string
1709
-     * @throws InvalidArgumentException
1710
-     * @throws InvalidInterfaceException
1711
-     * @throws InvalidDataTypeException
1712
-     * @throws DomainException
1713
-     * @throws EE_Error
1714
-     * @throws ReflectionException
1715
-     */
1716
-    protected function _get_ticket_price_row(
1717
-        int $ticket_row,
1718
-        int $price_row,
1719
-        ?EE_Price $price,
1720
-        bool $default,
1721
-        ?EE_Ticket $ticket,
1722
-        bool $show_trash = true,
1723
-        bool $show_create = true
1724
-    ): string {
1725
-        $send_disabled = ! empty($ticket) && $ticket->get('TKT_deleted');
1726
-        $template_args = [
1727
-            'tkt_row'               => $default && empty($ticket)
1728
-                ? 'TICKETNUM'
1729
-                : $ticket_row,
1730
-            'PRC_order'             => $default && empty($price)
1731
-                ? 'PRICENUM'
1732
-                : $price_row,
1733
-            'edit_prices_name'      => $default && empty($price)
1734
-                ? 'PRICENAMEATTR'
1735
-                : 'edit_prices',
1736
-            'price_type_selector'   => $default && empty($price)
1737
-                ? $this->_get_base_price_template($ticket_row, $price_row, $price, true)
1738
-                : $this->_get_price_type_selector(
1739
-                    $ticket_row,
1740
-                    $price_row,
1741
-                    $price,
1742
-                    $default,
1743
-                    $send_disabled
1744
-                ),
1745
-            'PRC_ID'                => $default && empty($price)
1746
-                ? 0
1747
-                : $price->ID(),
1748
-            'PRC_is_default'        => $default && empty($price)
1749
-                ? 0
1750
-                : $price->get('PRC_is_default'),
1751
-            'PRC_name'              => $default && empty($price)
1752
-                ? ''
1753
-                : $price->get('PRC_name'),
1754
-            'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1755
-            'show_plus_or_minus'    => $default && empty($price)
1756
-                ? ''
1757
-                : 'display:none;',
1758
-            'show_plus'             => ($default && empty($price)) || ($price->is_discount() || $price->is_base_price())
1759
-                ? 'display:none;'
1760
-                : '',
1761
-            'show_minus'            => ($default && empty($price)) || ! $price->is_discount()
1762
-                ? 'display:none;'
1763
-                : '',
1764
-            'show_currency_symbol'  => ($default && empty($price)) || $price->is_percent()
1765
-                ? 'display:none'
1766
-                : '',
1767
-            'PRC_amount'            => $default && empty($price)
1768
-                ? 0
1769
-                : $price->get_pretty('PRC_amount', 'localized_float'),
1770
-            'show_percentage'       => ($default && empty($price)) || ! $price->is_percent()
1771
-                ? 'display:none;'
1772
-                : '',
1773
-            'show_trash_icon'       => $show_trash
1774
-                ? ''
1775
-                : ' style="display:none;"',
1776
-            'show_create_button'    => $show_create
1777
-                ? ''
1778
-                : ' style="display:none;"',
1779
-            'PRC_desc'              => $default && empty($price)
1780
-                ? ''
1781
-                : $price->get('PRC_desc'),
1782
-            'disabled'              => ! empty($ticket) && $ticket->get('TKT_deleted'),
1783
-        ];
1784
-        $template_args = apply_filters(
1785
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_price_row__template_args',
1786
-            $template_args,
1787
-            $ticket_row,
1788
-            $price_row,
1789
-            $price,
1790
-            $default,
1791
-            $ticket,
1792
-            $show_trash,
1793
-            $show_create,
1794
-            $this->_is_creating_event
1795
-        );
1796
-        return EEH_Template::display_template(
1797
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_price_row.template.php',
1798
-            $template_args,
1799
-            true
1800
-        );
1801
-    }
1802
-
1803
-
1804
-    /**
1805
-     * @param int           $ticket_row
1806
-     * @param int           $price_row
1807
-     * @param EE_Price|null $price
1808
-     * @param bool          $default
1809
-     * @param bool          $disabled
1810
-     * @return string
1811
-     * @throws ReflectionException
1812
-     * @throws InvalidArgumentException
1813
-     * @throws InvalidInterfaceException
1814
-     * @throws InvalidDataTypeException
1815
-     * @throws DomainException
1816
-     * @throws EE_Error
1817
-     */
1818
-    protected function _get_price_type_selector(
1819
-        int $ticket_row,
1820
-        int $price_row,
1821
-        ?EE_Price $price,
1822
-        bool $default,
1823
-        bool $disabled = false
1824
-    ): string {
1825
-        if ($price->is_base_price()) {
1826
-            return $this->_get_base_price_template(
1827
-                $ticket_row,
1828
-                $price_row,
1829
-                $price,
1830
-                $default
1831
-            );
1832
-        }
1833
-        return $this->_get_price_modifier_template(
1834
-            $ticket_row,
1835
-            $price_row,
1836
-            $price,
1837
-            $default,
1838
-            $disabled
1839
-        );
1840
-    }
1841
-
1842
-
1843
-    /**
1844
-     * @param int           $ticket_row
1845
-     * @param int           $price_row
1846
-     * @param EE_Price|null $price
1847
-     * @param bool          $default
1848
-     * @return string
1849
-     * @throws DomainException
1850
-     * @throws EE_Error
1851
-     * @throws ReflectionException
1852
-     */
1853
-    protected function _get_base_price_template(
1854
-        int $ticket_row,
1855
-        int $price_row,
1856
-        ?EE_Price $price,
1857
-        bool $default
1858
-    ): string {
1859
-        $template_args = [
1860
-            'tkt_row'                   => $default ? 'TICKETNUM' : $ticket_row,
1861
-            'PRC_order'                 => $default && empty($price) ? 'PRICENUM' : $price_row,
1862
-            'PRT_ID'                    => $default && empty($price) ? 1 : $price->get('PRT_ID'),
1863
-            'PRT_name'                  => esc_html__('Price', 'event_espresso'),
1864
-            'price_selected_operator'   => '+',
1865
-            'price_selected_is_percent' => 0,
1866
-        ];
1867
-        $template_args = apply_filters(
1868
-            'FHEE__espresso_events_Pricing_Hooks___get_base_price_template__template_args',
1869
-            $template_args,
1870
-            $ticket_row,
1871
-            $price_row,
1872
-            $price,
1873
-            $default,
1874
-            $this->_is_creating_event
1875
-        );
1876
-        return EEH_Template::display_template(
1877
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_type_base.template.php',
1878
-            $template_args,
1879
-            true
1880
-        );
1881
-    }
1882
-
1883
-
1884
-    /**
1885
-     * @param int           $ticket_row
1886
-     * @param int           $price_row
1887
-     * @param EE_Price|null $price
1888
-     * @param bool          $default
1889
-     * @param bool          $disabled
1890
-     * @return string
1891
-     * @throws ReflectionException
1892
-     * @throws InvalidArgumentException
1893
-     * @throws InvalidInterfaceException
1894
-     * @throws InvalidDataTypeException
1895
-     * @throws DomainException
1896
-     * @throws EE_Error
1897
-     */
1898
-    protected function _get_price_modifier_template(
1899
-        int $ticket_row,
1900
-        int $price_row,
1901
-        ?EE_Price $price,
1902
-        bool $default,
1903
-        bool $disabled = false
1904
-    ): string {
1905
-        $select_name = $default && ! $price instanceof EE_Price
1906
-            ? 'edit_prices[TICKETNUM][PRICENUM][PRT_ID]'
1907
-            : 'edit_prices[' . esc_attr($ticket_row) . '][' . esc_attr($price_row) . '][PRT_ID]';
1908
-        /** @var EEM_Price_Type $price_type_model */
1909
-        $price_type_model       = EE_Registry::instance()->load_model('Price_Type');
1910
-        $price_types            = $price_type_model->get_all(
1911
-            [
1912
-                [
1913
-                    'OR' => [
1914
-                        'PBT_ID'  => '2',
1915
-                        'PBT_ID*' => '3',
1916
-                    ],
1917
-                ],
1918
-            ]
1919
-        );
1920
-        $all_price_types        = $default && ! $price instanceof EE_Price
1921
-            ? [esc_html__('Select Modifier', 'event_espresso')]
1922
-            : [];
1923
-        $selected_price_type_id = $default && ! $price instanceof EE_Price ? 0 : $price->type();
1924
-        $price_option_spans     = '';
1925
-        // setup price types for selector
1926
-        foreach ($price_types as $price_type) {
1927
-            if (! $price_type instanceof EE_Price_Type) {
1928
-                continue;
1929
-            }
1930
-            $all_price_types[ $price_type->ID() ] = $price_type->get('PRT_name');
1931
-            // while we're in the loop let's setup the option spans used by js
1932
-            $span_args          = [
1933
-                'PRT_ID'         => $price_type->ID(),
1934
-                'PRT_operator'   => $price_type->is_discount() ? '-' : '+',
1935
-                'PRT_is_percent' => $price_type->get('PRT_is_percent') ? 1 : 0,
1936
-            ];
1937
-            $price_option_spans .= EEH_Template::display_template(
1938
-                PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_option_span.template.php',
1939
-                $span_args,
1940
-                true
1941
-            );
1942
-        }
1943
-
1944
-        $select_name = $disabled
1945
-            ? 'archive_price[' . $ticket_row . '][' . $price_row . '][PRT_ID]'
1946
-            : $select_name;
1947
-
1948
-        $select_input = new EE_Select_Input(
1949
-            $all_price_types,
1950
-            [
1951
-                'default'               => $selected_price_type_id,
1952
-                'html_name'             => $select_name,
1953
-                'html_class'            => 'edit-price-PRT_ID',
1954
-                'other_html_attributes' => $disabled ? 'style="width:auto;" disabled' : 'style="width:auto;"',
1955
-            ]
1956
-        );
1957
-
1958
-        $price_selected_operator   = $price instanceof EE_Price && $price->is_discount() ? '-' : '+';
1959
-        $price_selected_operator   = $default && ! $price instanceof EE_Price ? '' : $price_selected_operator;
1960
-        $price_selected_is_percent = $price instanceof EE_Price && $price->is_percent() ? 1 : 0;
1961
-        $price_selected_is_percent = $default && ! $price instanceof EE_Price ? '' : $price_selected_is_percent;
1962
-        $template_args             = [
1963
-            'tkt_row'                   => $default ? 'TICKETNUM' : $ticket_row,
1964
-            'PRC_order'                 => $default && ! $price instanceof EE_Price ? 'PRICENUM' : $price_row,
1965
-            'price_modifier_selector'   => $select_input->get_html_for_input(),
1966
-            'main_name'                 => $select_name,
1967
-            'selected_price_type_id'    => $selected_price_type_id,
1968
-            'price_option_spans'        => $price_option_spans,
1969
-            'price_selected_operator'   => $price_selected_operator,
1970
-            'price_selected_is_percent' => $price_selected_is_percent,
1971
-            'disabled'                  => $disabled,
1972
-        ];
1973
-        $template_args             = apply_filters(
1974
-            'FHEE__espresso_events_Pricing_Hooks___get_price_modifier_template__template_args',
1975
-            $template_args,
1976
-            $ticket_row,
1977
-            $price_row,
1978
-            $price,
1979
-            $default,
1980
-            $disabled,
1981
-            $this->_is_creating_event
1982
-        );
1983
-        return EEH_Template::display_template(
1984
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_modifier_selector.template.php',
1985
-            $template_args,
1986
-            true
1987
-        );
1988
-    }
1989
-
1990
-
1991
-    /**
1992
-     * @param int              $datetime_row
1993
-     * @param int              $ticket_row
1994
-     * @param EE_Datetime|null $datetime
1995
-     * @param EE_Ticket|null   $ticket
1996
-     * @param array            $ticket_datetimes
1997
-     * @param bool             $default
1998
-     * @return string
1999
-     * @throws DomainException
2000
-     * @throws EE_Error
2001
-     * @throws ReflectionException
2002
-     */
2003
-    protected function _get_ticket_datetime_list_item(
2004
-        int $datetime_row,
2005
-        int $ticket_row,
2006
-        ?EE_Datetime $datetime,
2007
-        ?EE_Ticket $ticket,
2008
-        array $ticket_datetimes = [],
2009
-        bool $default = false
2010
-    ): string {
2011
-        $ticket_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[ $ticket->ID() ])
2012
-            ? $ticket_datetimes[ $ticket->ID() ]
2013
-            : [];
2014
-        $template_args    = [
2015
-            'dtt_row'                  => $default && ! $datetime instanceof EE_Datetime
2016
-                ? 'DTTNUM'
2017
-                : $datetime_row,
2018
-            'tkt_row'                  => $default
2019
-                ? 'TICKETNUM'
2020
-                : $ticket_row,
2021
-            'ticket_datetime_selected' => in_array($datetime_row, $ticket_datetimes, true)
2022
-                ? ' ticket-selected'
2023
-                : '',
2024
-            'ticket_datetime_checked'  => in_array($datetime_row, $ticket_datetimes, true)
2025
-                ? ' checked'
2026
-                : '',
2027
-            'DTT_name'                 => $default && empty($datetime)
2028
-                ? 'DTTNAME'
2029
-                : $datetime->get_dtt_display_name(true),
2030
-            'tkt_status_class'         => '',
2031
-        ];
2032
-        $template_args    = apply_filters(
2033
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_datetime_list_item__template_args',
2034
-            $template_args,
2035
-            $datetime_row,
2036
-            $ticket_row,
2037
-            $datetime,
2038
-            $ticket,
2039
-            $ticket_datetimes,
2040
-            $default,
2041
-            $this->_is_creating_event
2042
-        );
2043
-        return EEH_Template::display_template(
2044
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_datetimes_list_item.template.php',
2045
-            $template_args,
2046
-            true
2047
-        );
2048
-    }
2049
-
2050
-
2051
-    /**
2052
-     * @param array $all_datetimes
2053
-     * @param array $all_tickets
2054
-     * @return string
2055
-     * @throws ReflectionException
2056
-     * @throws InvalidArgumentException
2057
-     * @throws InvalidInterfaceException
2058
-     * @throws InvalidDataTypeException
2059
-     * @throws DomainException
2060
-     * @throws EE_Error
2061
-     */
2062
-    protected function _get_ticket_js_structure(array $all_datetimes = [], array $all_tickets = []): string
2063
-    {
2064
-        $template_args = [
2065
-            'default_datetime_edit_row' => $this->_get_dtt_edit_row(
2066
-                'DTTNUM',
2067
-                null,
2068
-                true,
2069
-                $all_datetimes
2070
-            ),
2071
-            'default_ticket_row'        => $this->_get_ticket_row(
2072
-                'TICKETNUM',
2073
-                null,
2074
-                [],
2075
-                [],
2076
-                true
2077
-            ),
2078
-            'default_price_row'         => $this->_get_ticket_price_row(
2079
-                'TICKETNUM',
2080
-                'PRICENUM',
2081
-                null,
2082
-                true,
2083
-                null
2084
-            ),
2085
-
2086
-            'default_price_rows'                       => '',
2087
-            'default_base_price_amount'                => 0,
2088
-            'default_base_price_name'                  => '',
2089
-            'default_base_price_description'           => '',
2090
-            'default_price_modifier_selector_row'      => $this->_get_price_modifier_template(
2091
-                'TICKETNUM',
2092
-                'PRICENUM',
2093
-                null,
2094
-                true
2095
-            ),
2096
-            'default_available_tickets_for_datetime'   => $this->_get_dtt_attached_tickets_row(
2097
-                'DTTNUM',
2098
-                null,
2099
-                [],
2100
-                [],
2101
-                true
2102
-            ),
2103
-            'existing_available_datetime_tickets_list' => '',
2104
-            'existing_available_ticket_datetimes_list' => '',
2105
-            'new_available_datetime_ticket_list_item'  => $this->_get_datetime_tickets_list_item(
2106
-                'DTTNUM',
2107
-                'TICKETNUM',
2108
-                null,
2109
-                null,
2110
-                [],
2111
-                true
2112
-            ),
2113
-            'new_available_ticket_datetime_list_item'  => $this->_get_ticket_datetime_list_item(
2114
-                'DTTNUM',
2115
-                'TICKETNUM',
2116
-                null,
2117
-                null,
2118
-                [],
2119
-                true
2120
-            ),
2121
-        ];
2122
-        $ticket_row    = 1;
2123
-        foreach ($all_tickets as $ticket) {
2124
-            $template_args['existing_available_datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
2125
-                'DTTNUM',
2126
-                $ticket_row,
2127
-                null,
2128
-                $ticket,
2129
-                [],
2130
-                true
2131
-            );
2132
-            $ticket_row++;
2133
-        }
2134
-        $datetime_row = 1;
2135
-        foreach ($all_datetimes as $datetime) {
2136
-            $template_args['existing_available_ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
2137
-                $datetime_row,
2138
-                'TICKETNUM',
2139
-                $datetime,
2140
-                null,
2141
-                [],
2142
-                true
2143
-            );
2144
-            $datetime_row++;
2145
-        }
2146
-        /** @var EEM_Price $price_model */
2147
-        $price_model    = EE_Registry::instance()->load_model('Price');
2148
-        $default_prices = $price_model->get_all_default_prices();
2149
-        $price_row      = 1;
2150
-        foreach ($default_prices as $price) {
2151
-            if (! $price instanceof EE_Price) {
2152
-                continue;
2153
-            }
2154
-            if ($price->is_base_price()) {
2155
-                $template_args['default_base_price_amount']      = $price->get_pretty(
2156
-                    'PRC_amount',
2157
-                    'localized_float'
2158
-                );
2159
-                $template_args['default_base_price_name']        = $price->get('PRC_name');
2160
-                $template_args['default_base_price_description'] = $price->get('PRC_desc');
2161
-                $price_row++;
2162
-                continue;
2163
-            }
2164
-
2165
-            $show_trash  = ! ((count($default_prices) > 1 && $price_row === 1) || count($default_prices) === 1);
2166
-            $show_create = ! (count($default_prices) > 1 && count($default_prices) !== $price_row);
2167
-
2168
-            $template_args['default_price_rows'] .= $this->_get_ticket_price_row(
2169
-                'TICKETNUM',
2170
-                $price_row,
2171
-                $price,
2172
-                true,
2173
-                null,
2174
-                $show_trash,
2175
-                $show_create
2176
-            );
2177
-            $price_row++;
2178
-        }
2179
-        $template_args = apply_filters(
2180
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_js_structure__template_args',
2181
-            $template_args,
2182
-            $all_datetimes,
2183
-            $all_tickets,
2184
-            $this->_is_creating_event
2185
-        );
2186
-        return EEH_Template::display_template(
2187
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_js_structure.template.php',
2188
-            $template_args,
2189
-            true
2190
-        );
2191
-    }
231
+					],
232
+					'DTT_OVERSELL_WARNING'  => [
233
+						'datetime_ticket' => esc_html__(
234
+							'You cannot add this ticket to this datetime because it has a sold amount that is greater than the amount of spots remaining for this datetime.',
235
+							'event_espresso'
236
+						),
237
+						'ticket_datetime' => esc_html__(
238
+							'You cannot add this datetime to this ticket because the ticket has a sold amount that is greater than the amount of spots remaining on the datetime.',
239
+							'event_espresso'
240
+						),
241
+					],
242
+					'DTT_CONVERTED_FORMATS' => EEH_DTT_Helper::convert_php_to_js_and_moment_date_formats(
243
+						$this->_date_format_strings['date'],
244
+						$this->_date_format_strings['time']
245
+					),
246
+					'DTT_START_OF_WEEK'     => ['dayValue' => (int) get_option('start_of_week')],
247
+				],
248
+			],
249
+		];
250
+	}
251
+
252
+
253
+	/**
254
+	 * @param array $update_callbacks
255
+	 * @return array
256
+	 */
257
+	public function caf_updates(array $update_callbacks): array
258
+	{
259
+		unset($update_callbacks['_default_tickets_update']);
260
+		$update_callbacks['datetime_and_tickets_caf_update'] = [$this, 'datetime_and_tickets_caf_update'];
261
+		return $update_callbacks;
262
+	}
263
+
264
+
265
+	/**
266
+	 * Handles saving everything related to Tickets (datetimes, tickets, prices)
267
+	 *
268
+	 * @param EE_Event $event The Event object we're attaching data to
269
+	 * @param array    $data  The request data from the form
270
+	 * @throws ReflectionException
271
+	 * @throws Exception
272
+	 * @throws InvalidInterfaceException
273
+	 * @throws InvalidDataTypeException
274
+	 * @throws EE_Error
275
+	 * @throws InvalidArgumentException
276
+	 */
277
+	public function datetime_and_tickets_caf_update(EE_Event $event, array $data)
278
+	{
279
+		// first we need to start with datetimes cause they are the "root" items attached to events.
280
+		$saved_datetimes = $this->_update_datetimes($event, $data);
281
+		// next tackle the tickets (and prices?)
282
+		$this->_update_tickets($event, $saved_datetimes, $data);
283
+	}
284
+
285
+
286
+	/**
287
+	 * update event_datetimes
288
+	 *
289
+	 * @param EE_Event $event Event being updated
290
+	 * @param array    $data  the request data from the form
291
+	 * @return EE_Datetime[]
292
+	 * @throws Exception
293
+	 * @throws ReflectionException
294
+	 * @throws InvalidInterfaceException
295
+	 * @throws InvalidDataTypeException
296
+	 * @throws InvalidArgumentException
297
+	 * @throws EE_Error
298
+	 */
299
+	protected function _update_datetimes(EE_Event $event, array $data): array
300
+	{
301
+		$timezone            = $data['timezone_string'] ?? null;
302
+		$saved_datetime_ids  = [];
303
+		$saved_datetime_objs = [];
304
+		if (empty($data['edit_event_datetimes']) || ! is_array($data['edit_event_datetimes'])) {
305
+			throw new InvalidArgumentException(
306
+				esc_html__(
307
+					'The "edit_event_datetimes" array is invalid therefore the event can not be updated.',
308
+					'event_espresso'
309
+				)
310
+			);
311
+		}
312
+		foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
313
+			// trim all values to ensure any excess whitespace is removed.
314
+			$datetime_data                = array_map(
315
+				function ($datetime_data) {
316
+					return is_array($datetime_data) ? $datetime_data : trim($datetime_data);
317
+				},
318
+				$datetime_data
319
+			);
320
+
321
+			$datetime_data['DTT_EVT_end'] = isset($datetime_data['DTT_EVT_end'])
322
+											&& ! empty($datetime_data['DTT_EVT_end'])
323
+				? $datetime_data['DTT_EVT_end']
324
+				: $datetime_data['DTT_EVT_start'];
325
+
326
+			$datetime_values              = [
327
+				'DTT_ID'          => ! empty($datetime_data['DTT_ID'])
328
+					? $datetime_data['DTT_ID']
329
+					: null,
330
+				'DTT_name'        => ! empty($datetime_data['DTT_name'])
331
+					? $datetime_data['DTT_name']
332
+					: '',
333
+				'DTT_description' => ! empty($datetime_data['DTT_description'])
334
+					? $datetime_data['DTT_description']
335
+					: '',
336
+				'DTT_EVT_start'   => $datetime_data['DTT_EVT_start'],
337
+				'DTT_EVT_end'     => $datetime_data['DTT_EVT_end'],
338
+				'DTT_reg_limit'   => empty($datetime_data['DTT_reg_limit'])
339
+					? EE_INF
340
+					: $datetime_data['DTT_reg_limit'],
341
+				'DTT_order'       => ! isset($datetime_data['DTT_order'])
342
+					? $row
343
+					: $datetime_data['DTT_order'],
344
+			];
345
+
346
+			// if we have an id then let's get existing object first and then set the new values.
347
+			// Otherwise we instantiate a new object for save.
348
+			if (! empty($datetime_data['DTT_ID'])) {
349
+				$datetime = EEM_Datetime::instance($timezone)->get_one_by_ID($datetime_data['DTT_ID']);
350
+				// set date and time format according to what is set in this class.
351
+				$datetime->set_date_format($this->_date_format_strings['date']);
352
+				$datetime->set_time_format($this->_date_format_strings['time']);
353
+				foreach ($datetime_values as $field => $value) {
354
+					$datetime->set($field, $value);
355
+				}
356
+
357
+				// make sure the $datetime_id here is saved just in case
358
+				// after the add_relation_to() the autosave replaces it.
359
+				// We need to do this so we dont' TRASH the parent DTT.
360
+				// (save the ID for both key and value to avoid duplications)
361
+				$saved_datetime_ids[ $datetime->ID() ] = $datetime->ID();
362
+			} else {
363
+				$datetime = EE_Datetime::new_instance(
364
+					$datetime_values,
365
+					$timezone,
366
+					[$this->_date_format_strings['date'], $this->_date_format_strings['time']]
367
+				);
368
+				foreach ($datetime_values as $field => $value) {
369
+					$datetime->set($field, $value);
370
+				}
371
+			}
372
+			$datetime->save();
373
+			do_action(
374
+				'AHEE__espresso_events_Pricing_Hooks___update_datetimes_after_save',
375
+				$datetime,
376
+				$row,
377
+				$datetime_data,
378
+				$data
379
+			);
380
+			$datetime = $event->_add_relation_to($datetime, 'Datetime');
381
+			// before going any further make sure our dates are setup correctly
382
+			// so that the end date is always equal or greater than the start date.
383
+			if ($datetime->get_raw('DTT_EVT_start') > $datetime->get_raw('DTT_EVT_end')) {
384
+				$datetime->set('DTT_EVT_end', $datetime->get('DTT_EVT_start'));
385
+				$datetime = EEH_DTT_Helper::date_time_add($datetime, 'DTT_EVT_end', 'days');
386
+				$datetime->save();
387
+			}
388
+			// now we have to make sure we add the new DTT_ID to the $saved_datetime_ids array
389
+			// because it is possible there was a new one created for the autosave.
390
+			// (save the ID for both key and value to avoid duplications)
391
+			$DTT_ID                        = $datetime->ID();
392
+			$saved_datetime_ids[ $DTT_ID ] = $DTT_ID;
393
+			$saved_datetime_objs[ $row ]   = $datetime;
394
+			// @todo if ANY of these updates fail then we want the appropriate global error message.
395
+		}
396
+		$event->save();
397
+		// now we need to REMOVE any datetimes that got deleted.
398
+		// Keep in mind that this process will only kick in for datetimes that don't have any DTT_sold on them.
399
+		// So its safe to permanently delete at this point.
400
+		$old_datetimes = explode(',', $data['datetime_IDs']);
401
+		$old_datetimes = $old_datetimes[0] === '' ? [] : $old_datetimes;
402
+		if (is_array($old_datetimes)) {
403
+			$datetimes_to_delete = array_diff($old_datetimes, $saved_datetime_ids);
404
+			foreach ($datetimes_to_delete as $id) {
405
+				$id = absint($id);
406
+				if (empty($id)) {
407
+					continue;
408
+				}
409
+				$datetime_to_remove = EE_Registry::instance()->load_model('Datetime')->get_one_by_ID($id);
410
+				// remove ticket relationships.
411
+				$related_tickets = $datetime_to_remove->get_many_related('Ticket');
412
+				foreach ($related_tickets as $ticket) {
413
+					$datetime_to_remove->_remove_relation_to($ticket, 'Ticket');
414
+				}
415
+				$event->_remove_relation_to($id, 'Datetime');
416
+				$datetime_to_remove->refresh_cache_of_related_objects();
417
+			}
418
+		}
419
+		return $saved_datetime_objs;
420
+	}
421
+
422
+
423
+	/**
424
+	 * update tickets
425
+	 *
426
+	 * @param EE_Event      $event           Event object being updated
427
+	 * @param EE_Datetime[] $saved_datetimes an array of datetime ids being updated
428
+	 * @param array         $data            incoming request data
429
+	 * @return EE_Ticket[]
430
+	 * @throws Exception
431
+	 * @throws ReflectionException
432
+	 * @throws InvalidInterfaceException
433
+	 * @throws InvalidDataTypeException
434
+	 * @throws InvalidArgumentException
435
+	 * @throws EE_Error
436
+	 */
437
+	protected function _update_tickets(EE_Event $event, array $saved_datetimes, array $data): array
438
+	{
439
+		$new_ticket = null;
440
+		// stripslashes because WP filtered the $_POST ($data) array to add slashes
441
+		$data          = stripslashes_deep($data);
442
+		$timezone      = $data['timezone_string'] ?? null;
443
+		$saved_tickets = [];
444
+		$old_tickets   = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : [];
445
+		if (empty($data['edit_tickets']) || ! is_array($data['edit_tickets'])) {
446
+			throw new InvalidArgumentException(
447
+				esc_html__(
448
+					'The "edit_tickets" array is invalid therefore the event can not be updated.',
449
+					'event_espresso'
450
+				)
451
+			);
452
+		}
453
+		foreach ($data['edit_tickets'] as $row => $ticket_data) {
454
+			$update_prices = $create_new_TKT = false;
455
+			// figure out what datetimes were added to the ticket
456
+			// and what datetimes were removed from the ticket in the session.
457
+			$starting_ticket_datetime_rows = explode(',', $data['starting_ticket_datetime_rows'][ $row ]);
458
+			$ticket_datetime_rows          = explode(',', $data['ticket_datetime_rows'][ $row ]);
459
+			$datetimes_added               = array_diff($ticket_datetime_rows, $starting_ticket_datetime_rows);
460
+			$datetimes_removed             = array_diff($starting_ticket_datetime_rows, $ticket_datetime_rows);
461
+			// trim inputs to ensure any excess whitespace is removed.
462
+			$ticket_data = array_map(
463
+				function ($ticket_data) {
464
+					return is_array($ticket_data) ? $ticket_data : trim($ticket_data);
465
+				},
466
+				$ticket_data
467
+			);
468
+			// note we are doing conversions to floats here instead of allowing EE_Money_Field to handle
469
+			// because we're doing calculations prior to using the models.
470
+			// note incoming ['TKT_price'] value is already in standard notation (via js).
471
+			$ticket_price = isset($ticket_data['TKT_price'])
472
+				? round((float) $ticket_data['TKT_price'], 3)
473
+				: 0;
474
+			// note incoming base price needs converted from localized value.
475
+			$base_price = isset($ticket_data['TKT_base_price'])
476
+				? EEH_Money::convert_to_float_from_localized_money($ticket_data['TKT_base_price'])
477
+				: 0;
478
+			// if ticket price == 0 and $base_price != 0 then ticket price == base_price
479
+			$ticket_price  = $ticket_price === 0 && $base_price !== 0
480
+				? $base_price
481
+				: $ticket_price;
482
+			$base_price_id = $ticket_data['TKT_base_price_ID'] ?? 0;
483
+			$price_rows    = is_array($data['edit_prices']) && isset($data['edit_prices'][ $row ])
484
+				? $data['edit_prices'][ $row ]
485
+				: [];
486
+			$now           = null;
487
+			if (empty($ticket_data['TKT_start_date'])) {
488
+				// lets' use now in the set timezone.
489
+				$now                           = new DateTime('now', new DateTimeZone($event->get_timezone()));
490
+				$ticket_data['TKT_start_date'] = $now->format($this->_date_time_format);
491
+			}
492
+			if (empty($ticket_data['TKT_end_date'])) {
493
+				/**
494
+				 * set the TKT_end_date to the first datetime attached to the ticket.
495
+				 */
496
+				$first_datetime              = $saved_datetimes[ reset($ticket_datetime_rows) ];
497
+				$ticket_data['TKT_end_date'] = $first_datetime->start_date_and_time($this->_date_time_format);
498
+			}
499
+			$TKT_values = [
500
+				'TKT_ID'          => ! empty($ticket_data['TKT_ID']) ? $ticket_data['TKT_ID'] : null,
501
+				'TTM_ID'          => ! empty($ticket_data['TTM_ID']) ? $ticket_data['TTM_ID'] : 0,
502
+				'TKT_name'        => ! empty($ticket_data['TKT_name']) ? $ticket_data['TKT_name'] : '',
503
+				'TKT_description' => ! empty($ticket_data['TKT_description'])
504
+									 && $ticket_data['TKT_description'] !== esc_html__(
505
+										 'You can modify this description',
506
+										 'event_espresso'
507
+									 )
508
+					? $ticket_data['TKT_description']
509
+					: '',
510
+				'TKT_start_date'  => $ticket_data['TKT_start_date'],
511
+				'TKT_end_date'    => $ticket_data['TKT_end_date'],
512
+				'TKT_qty'         => ! isset($ticket_data['TKT_qty']) || $ticket_data['TKT_qty'] === ''
513
+					? EE_INF
514
+					: $ticket_data['TKT_qty'],
515
+				'TKT_uses'        => ! isset($ticket_data['TKT_uses']) || $ticket_data['TKT_uses'] === ''
516
+					? EE_INF
517
+					: $ticket_data['TKT_uses'],
518
+				'TKT_min'         => empty($ticket_data['TKT_min']) ? 0 : $ticket_data['TKT_min'],
519
+				'TKT_max'         => empty($ticket_data['TKT_max']) ? EE_INF : $ticket_data['TKT_max'],
520
+				'TKT_row'         => $row,
521
+				'TKT_order'       => $ticket_data['TKT_order'] ?? 0,
522
+				'TKT_taxable'     => ! empty($ticket_data['TKT_taxable']) ? 1 : 0,
523
+				'TKT_required'    => ! empty($ticket_data['TKT_required']) ? 1 : 0,
524
+				'TKT_price'       => $ticket_price,
525
+			];
526
+			// if this is a default TKT, then we need to set the TKT_ID to 0 and update accordingly,
527
+			// which means in turn that the prices will become new prices as well.
528
+			if (isset($ticket_data['TKT_is_default']) && $ticket_data['TKT_is_default']) {
529
+				$TKT_values['TKT_ID']         = 0;
530
+				$TKT_values['TKT_is_default'] = 0;
531
+				$update_prices                = true;
532
+			}
533
+			// if we have a TKT_ID then we need to get that existing TKT_obj and update it
534
+			// we actually do our saves ahead of doing any add_relations to
535
+			// because its entirely possible that this ticket wasn't removed or added to any datetime in the session
536
+			// but DID have it's items modified.
537
+			// keep in mind that if the TKT has been sold (and we have changed pricing information),
538
+			// then we won't be updating the ticket but instead a new ticket will be created and the old one archived.
539
+			if (absint($TKT_values['TKT_ID'])) {
540
+				$ticket = EEM_Ticket::instance($timezone)->get_one_by_ID($ticket_data['TKT_ID']);
541
+				if ($ticket instanceof EE_Ticket) {
542
+					$ticket = $this->_update_ticket_datetimes(
543
+						$ticket,
544
+						$saved_datetimes,
545
+						$datetimes_added,
546
+						$datetimes_removed
547
+					);
548
+					// are there any registrations using this ticket ?
549
+					$tickets_sold = $ticket->count_related(
550
+						'Registration',
551
+						[
552
+							[
553
+								'STS_ID' => ['NOT IN', [EEM_Registration::status_id_incomplete]],
554
+							],
555
+						]
556
+					);
557
+					// set ticket formats
558
+					$ticket->set_date_format($this->_date_format_strings['date']);
559
+					$ticket->set_time_format($this->_date_format_strings['time']);
560
+					// let's just check the total price for the existing ticket
561
+					// and determine if it matches the new total price.
562
+					// if they are different then we create a new ticket (if tickets sold)
563
+					// if they aren't different then we go ahead and modify existing ticket.
564
+					$create_new_TKT = $tickets_sold > 0 && $ticket_price !== $ticket->price() && ! $ticket->deleted();
565
+					// set new values
566
+					foreach ($TKT_values as $field => $value) {
567
+						if ($field === 'TKT_qty') {
568
+							$ticket->set_qty($value);
569
+						} else {
570
+							$ticket->set($field, $value);
571
+						}
572
+					}
573
+					// if $create_new_TKT is false then we can safely update the existing ticket.
574
+					// Otherwise we have to create a new ticket.
575
+					if ($create_new_TKT) {
576
+						$new_ticket = $this->_duplicate_ticket(
577
+							$ticket,
578
+							$price_rows,
579
+							$ticket_price,
580
+							$base_price,
581
+							$base_price_id
582
+						);
583
+					}
584
+				}
585
+			} else {
586
+				// no TKT_id so a new TKT
587
+				$ticket = EE_Ticket::new_instance(
588
+					$TKT_values,
589
+					$timezone,
590
+					[$this->_date_format_strings['date'], $this->_date_format_strings['time']]
591
+				);
592
+				if ($ticket instanceof EE_Ticket) {
593
+					// make sure ticket has an ID of setting relations won't work
594
+					$ticket->save();
595
+					$ticket        = $this->_update_ticket_datetimes(
596
+						$ticket,
597
+						$saved_datetimes,
598
+						$datetimes_added,
599
+						$datetimes_removed
600
+					);
601
+					$update_prices = true;
602
+				}
603
+			}
604
+			// make sure any current values have been saved.
605
+			// $ticket->save();
606
+			// before going any further make sure our dates are setup correctly
607
+			// so that the end date is always equal or greater than the start date.
608
+			if ($ticket->get_raw('TKT_start_date') > $ticket->get_raw('TKT_end_date')) {
609
+				$ticket->set('TKT_end_date', $ticket->get('TKT_start_date'));
610
+				$ticket = EEH_DTT_Helper::date_time_add($ticket, 'TKT_end_date', 'days');
611
+			}
612
+			// let's make sure the base price is handled
613
+			$ticket = ! $create_new_TKT
614
+				? $this->_add_prices_to_ticket(
615
+					[],
616
+					$ticket,
617
+					$update_prices,
618
+					$base_price,
619
+					$base_price_id
620
+				)
621
+				: $ticket;
622
+			// add/update price_modifiers
623
+			$ticket = ! $create_new_TKT
624
+				? $this->_add_prices_to_ticket($price_rows, $ticket, $update_prices)
625
+				: $ticket;
626
+			// need to make sue that the TKT_price is accurate after saving the prices.
627
+			$ticket->ensure_TKT_Price_correct();
628
+			// handle CREATING a default ticket from the incoming ticket but ONLY if this isn't an autosave.
629
+			if (! defined('DOING_AUTOSAVE') && ! empty($ticket_data['TKT_is_default_selector'])) {
630
+				$new_default = clone $ticket;
631
+				$new_default->set('TKT_ID', 0);
632
+				$new_default->set('TKT_is_default', 1);
633
+				$new_default->set('TKT_row', 1);
634
+				$new_default->set('TKT_price', $ticket_price);
635
+				// remove any datetime relations cause we DON'T want datetime relations attached
636
+				// (note this is just removing the cached relations in the object)
637
+				$new_default->_remove_relations('Datetime');
638
+				// @todo we need to add the current attached prices as new prices to the new default ticket.
639
+				$new_default = $this->_add_prices_to_ticket(
640
+					$price_rows,
641
+					$new_default,
642
+					true
643
+				);
644
+				// don't forget the base price!
645
+				$new_default = $this->_add_prices_to_ticket(
646
+					[],
647
+					$new_default,
648
+					true,
649
+					$base_price,
650
+					$base_price_id
651
+				);
652
+				$new_default->save();
653
+				do_action(
654
+					'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_default_ticket',
655
+					$new_default,
656
+					$row,
657
+					$ticket,
658
+					$data
659
+				);
660
+			}
661
+			// DO ALL datetime relationships for both current tickets and any archived tickets
662
+			// for the given datetime that are related to the current ticket.
663
+			// TODO... not sure exactly how we're going to do this considering we don't know
664
+			// what current ticket the archived tickets are related to
665
+			// (and TKT_parent is used for autosaves so that's not a field we can reliably use).
666
+			// let's assign any tickets that have been setup to the saved_tickets tracker
667
+			// save existing TKT
668
+			$ticket->save();
669
+			if ($create_new_TKT && $new_ticket instanceof EE_Ticket) {
670
+				// save new TKT
671
+				$new_ticket->save();
672
+				// add new ticket to array
673
+				$saved_tickets[ $new_ticket->ID() ] = $new_ticket;
674
+				do_action(
675
+					'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_ticket',
676
+					$new_ticket,
677
+					$row,
678
+					$ticket_data,
679
+					$data
680
+				);
681
+			} else {
682
+				// add ticket to saved tickets
683
+				$saved_tickets[ $ticket->ID() ] = $ticket;
684
+				do_action(
685
+					'AHEE__espresso_events_Pricing_Hooks___update_tkts_update_ticket',
686
+					$ticket,
687
+					$row,
688
+					$ticket_data,
689
+					$data
690
+				);
691
+			}
692
+		}
693
+		// now we need to handle tickets actually "deleted permanently".
694
+		// There are cases where we'd want this to happen
695
+		// (i.e. autosaves are happening and then in between autosaves the user trashes a ticket).
696
+		// Or a draft event was saved and in the process of editing a ticket is trashed.
697
+		// No sense in keeping all the related data in the db!
698
+		$old_tickets     = isset($old_tickets[0]) && $old_tickets[0] === '' ? [] : $old_tickets;
699
+		$tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
700
+		foreach ($tickets_removed as $id) {
701
+			$id = absint($id);
702
+			// get the ticket for this id
703
+			$ticket_to_remove = EE_Registry::instance()->load_model('Ticket')->get_one_by_ID($id);
704
+			// if this ticket is a default ticket we leave it alone cause it won't be attached to the datetime
705
+			if ($ticket_to_remove->get('TKT_is_default')) {
706
+				continue;
707
+			}
708
+			// if this ticket has any registrations attached so then we just ARCHIVE
709
+			// because we don't actually permanently delete these tickets.
710
+			if ($ticket_to_remove->count_related('Registration') > 0) {
711
+				$ticket_to_remove->delete();
712
+				continue;
713
+			}
714
+			// need to get all the related datetimes on this ticket and remove from every single one of them
715
+			// (remember this process can ONLY kick off if there are NO tickets_sold)
716
+			$datetimes = $ticket_to_remove->get_many_related('Datetime');
717
+			foreach ($datetimes as $datetime) {
718
+				$ticket_to_remove->_remove_relation_to($datetime, 'Datetime');
719
+			}
720
+			// need to do the same for prices (except these prices can also be deleted because again,
721
+			// tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
722
+			$ticket_to_remove->delete_related_permanently('Price');
723
+			do_action('AHEE__espresso_events_Pricing_Hooks___update_tkts_delete_ticket', $ticket_to_remove);
724
+			// finally let's delete this ticket
725
+			// (which should not be blocked at this point b/c we've removed all our relationships)
726
+			$ticket_to_remove->delete_permanently();
727
+		}
728
+		return $saved_tickets;
729
+	}
730
+
731
+
732
+	/**
733
+	 * @access  protected
734
+	 * @param EE_Ticket     $ticket
735
+	 * @param EE_Datetime[] $saved_datetimes
736
+	 * @param int[]         $added_datetimes
737
+	 * @param int[]         $removed_datetimes
738
+	 * @return EE_Ticket
739
+	 * @throws EE_Error
740
+	 * @throws ReflectionException
741
+	 */
742
+	protected function _update_ticket_datetimes(
743
+		EE_Ticket $ticket,
744
+		array $saved_datetimes = [],
745
+		array $added_datetimes = [],
746
+		array $removed_datetimes = []
747
+	): EE_Ticket {
748
+		// to start we have to add the ticket to all the datetimes its supposed to be with,
749
+		// and removing the ticket from datetimes it got removed from.
750
+		// first let's add datetimes
751
+		if (! empty($added_datetimes) && is_array($added_datetimes)) {
752
+			foreach ($added_datetimes as $row_id) {
753
+				if (isset($saved_datetimes[ $row_id ]) && $saved_datetimes[ $row_id ] instanceof EE_Datetime) {
754
+					$ticket->_add_relation_to($saved_datetimes[ $row_id ], 'Datetime');
755
+				}
756
+			}
757
+		}
758
+		// then remove datetimes
759
+		if (! empty($removed_datetimes) && is_array($removed_datetimes)) {
760
+			foreach ($removed_datetimes as $row_id) {
761
+				// its entirely possible that a datetime got deleted (instead of just removed from relationship.
762
+				// So make sure we skip over this if the datetime isn't in the $saved_datetimes array)
763
+				if (isset($saved_datetimes[ $row_id ]) && $saved_datetimes[ $row_id ] instanceof EE_Datetime) {
764
+					$ticket->_remove_relation_to($saved_datetimes[ $row_id ], 'Datetime');
765
+				}
766
+			}
767
+		}
768
+		// cap ticket qty by datetime reg limits
769
+		$ticket->set_qty(min($ticket->qty(), $ticket->qty('reg_limit')));
770
+		return $ticket;
771
+	}
772
+
773
+
774
+	/**
775
+	 * @access  protected
776
+	 * @param EE_Ticket $ticket
777
+	 * @param array     $price_rows
778
+	 * @param int|float $ticket_price
779
+	 * @param int|float $base_price
780
+	 * @param int       $base_price_id
781
+	 * @return EE_Ticket
782
+	 * @throws ReflectionException
783
+	 * @throws InvalidArgumentException
784
+	 * @throws InvalidInterfaceException
785
+	 * @throws InvalidDataTypeException
786
+	 * @throws EE_Error
787
+	 */
788
+	protected function _duplicate_ticket(
789
+		EE_Ticket $ticket,
790
+		array $price_rows = [],
791
+		$ticket_price = 0,
792
+		$base_price = 0,
793
+		int $base_price_id = 0
794
+	): EE_Ticket {
795
+		// create new ticket that's a copy of the existing
796
+		// except a new id of course (and not archived)
797
+		// AND has the new TKT_price associated with it.
798
+		$new_ticket = clone $ticket;
799
+		$new_ticket->set('TKT_ID', 0);
800
+		$new_ticket->set_deleted(0);
801
+		$new_ticket->set_price($ticket_price);
802
+		$new_ticket->set_sold(0);
803
+		// let's get a new ID for this ticket
804
+		$new_ticket->save();
805
+		// we also need to make sure this new ticket gets the same datetime attachments as the archived ticket
806
+		$datetimes_on_existing = $ticket->datetimes();
807
+		$new_ticket            = $this->_update_ticket_datetimes(
808
+			$new_ticket,
809
+			$datetimes_on_existing,
810
+			array_keys($datetimes_on_existing)
811
+		);
812
+		// $ticket will get archived later b/c we are NOT adding it to the saved_tickets array.
813
+		// if existing $ticket has sold amount, then we need to adjust the qty for the new TKT to = the remaining
814
+		// available.
815
+		if ($ticket->sold() > 0) {
816
+			$new_qty = $ticket->qty() - $ticket->sold();
817
+			$new_ticket->set_qty($new_qty);
818
+		}
819
+		// now we update the prices just for this ticket
820
+		$new_ticket = $this->_add_prices_to_ticket($price_rows, $new_ticket, true);
821
+		// and we update the base price
822
+		return $this->_add_prices_to_ticket(
823
+			[],
824
+			$new_ticket,
825
+			true,
826
+			$base_price,
827
+			$base_price_id
828
+		);
829
+	}
830
+
831
+
832
+	/**
833
+	 * This attaches a list of given prices to a ticket.
834
+	 * Note we dont' have to worry about ever removing relationships (or archiving prices) because if there is a change
835
+	 * in price information on a ticket, a new ticket is created anyways so the archived ticket will retain the old
836
+	 * price info and prices are automatically "archived" via the ticket.
837
+	 *
838
+	 * @access  private
839
+	 * @param array     $prices        Array of prices from the form.
840
+	 * @param EE_Ticket $ticket        EE_Ticket object that prices are being attached to.
841
+	 * @param bool      $new_prices    Whether attach existing incoming prices or create new ones.
842
+	 * @param int|bool  $base_price    if FALSE then NOT doing a base price add.
843
+	 * @param int|bool  $base_price_id if present then this is the base_price_id being updated.
844
+	 * @return EE_Ticket
845
+	 * @throws ReflectionException
846
+	 * @throws InvalidArgumentException
847
+	 * @throws InvalidInterfaceException
848
+	 * @throws InvalidDataTypeException
849
+	 * @throws EE_Error
850
+	 */
851
+	protected function _add_prices_to_ticket(
852
+		array $prices,
853
+		EE_Ticket $ticket,
854
+		bool $new_prices = false,
855
+		$base_price = false,
856
+		$base_price_id = false
857
+	): EE_Ticket {
858
+		// let's just get any current prices that may exist on the given ticket
859
+		// so we can remove any prices that got trashed in this session.
860
+		$current_prices_on_ticket = $base_price !== false
861
+			? $ticket->base_price(true)
862
+			: $ticket->price_modifiers();
863
+		$updated_prices           = [];
864
+		// if $base_price ! FALSE then updating a base price.
865
+		if ($base_price !== false) {
866
+			$prices[1] = [
867
+				'PRC_ID'     => $new_prices || $base_price_id === 1 ? null : $base_price_id,
868
+				'PRT_ID'     => 1,
869
+				'PRC_amount' => $base_price,
870
+				'PRC_name'   => $ticket->get('TKT_name'),
871
+				'PRC_desc'   => $ticket->get('TKT_description'),
872
+			];
873
+		}
874
+		// possibly need to save ticket
875
+		if (! $ticket->ID()) {
876
+			$ticket->save();
877
+		}
878
+		foreach ($prices as $row => $prc) {
879
+			$prt_id = ! empty($prc['PRT_ID']) ? $prc['PRT_ID'] : null;
880
+			if (empty($prt_id)) {
881
+				continue;
882
+			} //prices MUST have a price type id.
883
+			$PRC_values = [
884
+				'PRC_ID'         => ! empty($prc['PRC_ID']) ? $prc['PRC_ID'] : null,
885
+				'PRT_ID'         => $prt_id,
886
+				'PRC_amount'     => ! empty($prc['PRC_amount']) ? $prc['PRC_amount'] : 0,
887
+				'PRC_name'       => ! empty($prc['PRC_name']) ? $prc['PRC_name'] : '',
888
+				'PRC_desc'       => ! empty($prc['PRC_desc']) ? $prc['PRC_desc'] : '',
889
+				'PRC_is_default' => false,
890
+				// make sure we set PRC_is_default to false for all ticket saves from event_editor
891
+				'PRC_order'      => $row,
892
+			];
893
+			if ($new_prices || empty($PRC_values['PRC_ID'])) {
894
+				$PRC_values['PRC_ID'] = 0;
895
+				$price                = EE_Registry::instance()->load_class(
896
+					'Price',
897
+					[$PRC_values],
898
+					false,
899
+					false
900
+				);
901
+			} else {
902
+				$price = EE_Registry::instance()->load_model('Price')->get_one_by_ID($prc['PRC_ID']);
903
+				// update this price with new values
904
+				foreach ($PRC_values as $field => $value) {
905
+					$price->set($field, $value);
906
+				}
907
+			}
908
+			$price->save();
909
+			$updated_prices[ $price->ID() ] = $price;
910
+			$ticket->_add_relation_to($price, 'Price');
911
+		}
912
+		// now let's remove any prices that got removed from the ticket
913
+		if (! empty($current_prices_on_ticket)) {
914
+			$current          = array_keys($current_prices_on_ticket);
915
+			$updated          = array_keys($updated_prices);
916
+			$prices_to_remove = array_diff($current, $updated);
917
+			if (! empty($prices_to_remove)) {
918
+				foreach ($prices_to_remove as $prc_id) {
919
+					$p = $current_prices_on_ticket[ $prc_id ];
920
+					$ticket->_remove_relation_to($p, 'Price');
921
+					// delete permanently the price
922
+					$p->delete_permanently();
923
+				}
924
+			}
925
+		}
926
+		return $ticket;
927
+	}
928
+
929
+
930
+	/**
931
+	 * @throws ReflectionException
932
+	 * @throws InvalidArgumentException
933
+	 * @throws InvalidInterfaceException
934
+	 * @throws InvalidDataTypeException
935
+	 * @throws DomainException
936
+	 * @throws EE_Error
937
+	 */
938
+	public function pricing_metabox()
939
+	{
940
+		$existing_datetime_ids = $existing_ticket_ids = $datetime_tickets = $ticket_datetimes = [];
941
+		$event                 = $this->_adminpage_obj->get_cpt_model_obj();
942
+
943
+		// set is_creating_event property.
944
+		$EVT_ID                   = $event->ID();
945
+		$this->_is_creating_event = empty($this->_req_data['post']);
946
+
947
+		// default main template args
948
+		$main_template_args = [
949
+			'event_datetime_help_link' => EEH_Template::get_help_tab_link(
950
+				'event_editor_event_datetimes_help_tab',
951
+				$this->_adminpage_obj->page_slug,
952
+				$this->_adminpage_obj->get_req_action()
953
+			),
954
+
955
+			// todo need to add a filter to the template for the help text
956
+			// in the Events_Admin_Page core file so we can add further help
957
+			'add_new_dtt_help_link'    => EEH_Template::get_help_tab_link(
958
+				'add_new_dtt_info',
959
+				$this->_adminpage_obj->page_slug,
960
+				$this->_adminpage_obj->get_req_action()
961
+			),
962
+			// todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
963
+			'datetime_rows'            => '',
964
+			'show_tickets_container'   => '',
965
+			'ticket_rows'              => '',
966
+			'ee_collapsible_status'    => ' ee-collapsible-open',
967
+		];
968
+		$timezone           = $event instanceof EE_Event ? $event->timezone_string() : null;
969
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
970
+
971
+		/**
972
+		 * 1. Start with retrieving Datetimes
973
+		 * 2. For each datetime get related tickets
974
+		 * 3. For each ticket get related prices
975
+		 */
976
+		/** @var EEM_Datetime $datetime_model */
977
+		$datetime_model                       = EE_Registry::instance()->load_model('Datetime', [$timezone]);
978
+		$datetimes                            = $datetime_model->get_all_event_dates($EVT_ID);
979
+		$main_template_args['total_dtt_rows'] = count($datetimes);
980
+
981
+		/**
982
+		 * @see https://events.codebasehq.com/projects/event-espresso/tickets/9486
983
+		 * for why we are counting $datetime_row and then setting that on the Datetime object
984
+		 */
985
+		$datetime_row = 1;
986
+		foreach ($datetimes as $datetime) {
987
+			$DTT_ID = $datetime->get('DTT_ID');
988
+			$datetime->set('DTT_order', $datetime_row);
989
+			$existing_datetime_ids[] = $DTT_ID;
990
+			// tickets attached
991
+			$related_tickets = $datetime->ID() > 0
992
+				? $datetime->get_many_related(
993
+					'Ticket',
994
+					[
995
+						[
996
+							'OR' => ['TKT_deleted' => 1, 'TKT_deleted*' => 0],
997
+						],
998
+						'default_where_conditions' => 'none',
999
+						'order_by'                 => ['TKT_order' => 'ASC'],
1000
+					]
1001
+				)
1002
+				: [];
1003
+			// if there are no related tickets this is likely a new event OR auto-draft
1004
+			// event so we need to generate the default tickets because datetimes
1005
+			// ALWAYS have at least one related ticket!!.  EXCEPT, we dont' do this if there is already more than one
1006
+			// datetime on the event.
1007
+			if (empty($related_tickets) && count($datetimes) < 2) {
1008
+				/** @var EEM_Ticket $ticket_model */
1009
+				$ticket_model    = EE_Registry::instance()->load_model('Ticket');
1010
+				$related_tickets = $ticket_model->get_all_default_tickets();
1011
+				// this should be ordered by TKT_ID, so let's grab the first default ticket
1012
+				// (which will be the main default) and ensure it has any default prices added to it (but do NOT save).
1013
+				$default_prices      = EEM_Price::instance()->get_all_default_prices();
1014
+				$main_default_ticket = reset($related_tickets);
1015
+				if ($main_default_ticket instanceof EE_Ticket) {
1016
+					foreach ($default_prices as $default_price) {
1017
+						if ($default_price instanceof EE_Price && $default_price->is_base_price()) {
1018
+							continue;
1019
+						}
1020
+						$main_default_ticket->cache('Price', $default_price);
1021
+					}
1022
+				}
1023
+			}
1024
+			// we can't actually setup rows in this loop yet cause we don't know all
1025
+			// the unique tickets for this event yet (tickets are linked through all datetimes).
1026
+			// So we're going to temporarily cache some of that information.
1027
+			// loop through and setup the ticket rows and make sure the order is set.
1028
+			foreach ($related_tickets as $ticket) {
1029
+				$TKT_ID     = $ticket->get('TKT_ID');
1030
+				$ticket_row = $ticket->get('TKT_row');
1031
+				// we only want unique tickets in our final display!!
1032
+				if (! in_array($TKT_ID, $existing_ticket_ids, true)) {
1033
+					$existing_ticket_ids[] = $TKT_ID;
1034
+					$all_tickets[]         = $ticket;
1035
+				}
1036
+				// temporary cache of this ticket info for this datetime for later processing of datetime rows.
1037
+				$datetime_tickets[ $DTT_ID ][] = $ticket_row;
1038
+				// temporary cache of this datetime info for this ticket for later processing of ticket rows.
1039
+				if (
1040
+					! isset($ticket_datetimes[ $TKT_ID ])
1041
+					|| ! in_array($datetime_row, $ticket_datetimes[ $TKT_ID ], true)
1042
+				) {
1043
+					$ticket_datetimes[ $TKT_ID ][] = $datetime_row;
1044
+				}
1045
+			}
1046
+			$datetime_row++;
1047
+		}
1048
+		$main_template_args['total_ticket_rows']     = count($existing_ticket_ids);
1049
+		$main_template_args['existing_ticket_ids']   = implode(',', $existing_ticket_ids);
1050
+		$main_template_args['existing_datetime_ids'] = implode(',', $existing_datetime_ids);
1051
+		// sort $all_tickets by order
1052
+		usort(
1053
+			$all_tickets,
1054
+			function (EE_Ticket $a, EE_Ticket $b) {
1055
+				$a_order = (int) $a->get('TKT_order');
1056
+				$b_order = (int) $b->get('TKT_order');
1057
+				if ($a_order === $b_order) {
1058
+					return 0;
1059
+				}
1060
+				return ($a_order < $b_order) ? -1 : 1;
1061
+			}
1062
+		);
1063
+		// k NOW we have all the data we need for setting up the datetime rows
1064
+		// and ticket rows so we start our datetime loop again.
1065
+		$datetime_row = 1;
1066
+		foreach ($datetimes as $datetime) {
1067
+			$main_template_args['datetime_rows'] .= $this->_get_datetime_row(
1068
+				$datetime_row,
1069
+				$datetime,
1070
+				$datetime_tickets,
1071
+				$all_tickets,
1072
+				false,
1073
+				$datetimes
1074
+			);
1075
+			$datetime_row++;
1076
+		}
1077
+		// then loop through all tickets for the ticket rows.
1078
+		$ticket_row = 1;
1079
+		foreach ($all_tickets as $ticket) {
1080
+			$main_template_args['ticket_rows'] .= $this->_get_ticket_row(
1081
+				$ticket_row,
1082
+				$ticket,
1083
+				$ticket_datetimes,
1084
+				$datetimes,
1085
+				false,
1086
+				$all_tickets
1087
+			);
1088
+			$ticket_row++;
1089
+		}
1090
+		$main_template_args['ticket_js_structure'] = $this->_get_ticket_js_structure($datetimes, $all_tickets);
1091
+
1092
+		$status_change_notice = LoaderFactory::getLoader()->getShared(
1093
+			'EventEspresso\core\domain\services\admin\notices\status_change\StatusChangeNotice'
1094
+		);
1095
+
1096
+		$main_template_args['status_change_notice'] = $status_change_notice->display(
1097
+			'__event-editor',
1098
+			'espresso-events'
1099
+		);
1100
+
1101
+		EEH_Template::display_template(
1102
+			PRICING_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php',
1103
+			$main_template_args
1104
+		);
1105
+	}
1106
+
1107
+
1108
+	/**
1109
+	 * @param int         $datetime_row
1110
+	 * @param EE_Datetime $datetime
1111
+	 * @param array       $datetime_tickets
1112
+	 * @param array       $all_tickets
1113
+	 * @param bool        $default
1114
+	 * @param array       $all_datetimes
1115
+	 * @return string
1116
+	 * @throws DomainException
1117
+	 * @throws EE_Error
1118
+	 * @throws ReflectionException
1119
+	 */
1120
+	protected function _get_datetime_row(
1121
+		int $datetime_row,
1122
+		EE_Datetime $datetime,
1123
+		array $datetime_tickets = [],
1124
+		array $all_tickets = [],
1125
+		bool $default = false,
1126
+		array $all_datetimes = []
1127
+	): string {
1128
+		return EEH_Template::display_template(
1129
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_row_wrapper.template.php',
1130
+			[
1131
+				'dtt_edit_row'             => $this->_get_dtt_edit_row(
1132
+					$datetime_row,
1133
+					$datetime,
1134
+					$default,
1135
+					$all_datetimes
1136
+				),
1137
+				'dtt_attached_tickets_row' => $this->_get_dtt_attached_tickets_row(
1138
+					$datetime_row,
1139
+					$datetime,
1140
+					$datetime_tickets,
1141
+					$all_tickets,
1142
+					$default
1143
+				),
1144
+				'dtt_row'                  => $default ? 'DTTNUM' : $datetime_row,
1145
+			],
1146
+			true
1147
+		);
1148
+	}
1149
+
1150
+
1151
+	/**
1152
+	 * This method is used to generate a datetime fields  edit row.
1153
+	 * The same row is used to generate a row with valid DTT objects
1154
+	 * and the default row that is used as the skeleton by the js.
1155
+	 *
1156
+	 * @param int              $datetime_row  The row number for the row being generated.
1157
+	 * @param EE_Datetime|null $datetime
1158
+	 * @param bool             $default       Whether a default row is being generated or not.
1159
+	 * @param EE_Datetime[]    $all_datetimes This is the array of all datetimes used in the editor.
1160
+	 * @return string
1161
+	 * @throws EE_Error
1162
+	 * @throws ReflectionException
1163
+	 */
1164
+	protected function _get_dtt_edit_row(
1165
+		int $datetime_row,
1166
+		?EE_Datetime $datetime,
1167
+		bool $default,
1168
+		array $all_datetimes
1169
+	): string {
1170
+		// if the incoming $datetime object is NOT an instance of EE_Datetime then force default to true.
1171
+		$default                     = ! $datetime instanceof EE_Datetime ? true : $default;
1172
+		$template_args               = [
1173
+			'dtt_row'              => $default ? 'DTTNUM' : $datetime_row,
1174
+			'event_datetimes_name' => $default ? 'DTTNAMEATTR' : 'edit_event_datetimes',
1175
+			'edit_dtt_expanded'    => '',
1176
+			'DTT_ID'               => $default ? '' : $datetime->ID(),
1177
+			'DTT_name'             => $default ? '' : $datetime->get_f('DTT_name'),
1178
+			'DTT_description'      => $default ? '' : $datetime->get_f('DTT_description'),
1179
+			'DTT_EVT_start'        => $default ? '' : $datetime->start_date($this->_date_time_format),
1180
+			'DTT_EVT_end'          => $default ? '' : $datetime->end_date($this->_date_time_format),
1181
+			'DTT_reg_limit'        => $default
1182
+				? ''
1183
+				: $datetime->get_pretty(
1184
+					'DTT_reg_limit',
1185
+					'input'
1186
+				),
1187
+			'DTT_order'            => $default ? 'DTTNUM' : $datetime_row,
1188
+			'dtt_sold'             => $default ? '0' : $datetime->get('DTT_sold'),
1189
+			'dtt_reserved'         => $default ? '0' : $datetime->reserved(),
1190
+			'clone_icon'           => ! empty($datetime) && $datetime->get('DTT_sold') > 0
1191
+				? ''
1192
+				: 'clone-icon ee-icon ee-icon-clone clickable',
1193
+			'trash_icon'           => ! empty($datetime) && $datetime->get('DTT_sold') > 0
1194
+				? 'dashicons dashicons-lock'
1195
+				: 'trash-icon dashicons dashicons-post-trash clickable',
1196
+			'reg_list_url'         => $default || ! $datetime->event() instanceof EE_Event
1197
+				? ''
1198
+				: EE_Admin_Page::add_query_args_and_nonce(
1199
+					['event_id' => $datetime->event()->ID(), 'datetime_id' => $datetime->ID()],
1200
+					REG_ADMIN_URL
1201
+				),
1202
+		];
1203
+		$template_args['show_trash'] = count($all_datetimes) === 1
1204
+									   && $template_args['trash_icon'] !== 'dashicons dashicons-lock'
1205
+			? 'display:none'
1206
+			: '';
1207
+		// allow filtering of template args at this point.
1208
+		$template_args = apply_filters(
1209
+			'FHEE__espresso_events_Pricing_Hooks___get_dtt_edit_row__template_args',
1210
+			$template_args,
1211
+			$datetime_row,
1212
+			$datetime,
1213
+			$default,
1214
+			$all_datetimes,
1215
+			$this->_is_creating_event
1216
+		);
1217
+		return EEH_Template::display_template(
1218
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_edit_row.template.php',
1219
+			$template_args,
1220
+			true
1221
+		);
1222
+	}
1223
+
1224
+
1225
+	/**
1226
+	 * @param int         $datetime_row
1227
+	 * @param EE_Datetime $datetime
1228
+	 * @param array       $datetime_tickets
1229
+	 * @param array       $all_tickets
1230
+	 * @param bool        $default
1231
+	 * @return string
1232
+	 * @throws DomainException
1233
+	 * @throws EE_Error
1234
+	 * @throws ReflectionException
1235
+	 */
1236
+	protected function _get_dtt_attached_tickets_row(
1237
+		int $datetime_row,
1238
+		EE_Datetime $datetime,
1239
+		array $datetime_tickets = [],
1240
+		array $all_tickets = [],
1241
+		bool $default = false
1242
+	): string {
1243
+		$template_args = [
1244
+			'dtt_row'                           => $default ? 'DTTNUM' : $datetime_row,
1245
+			'event_datetimes_name'              => $default ? 'DTTNAMEATTR' : 'edit_event_datetimes',
1246
+			'DTT_description'                   => $default ? '' : $datetime->get_f('DTT_description'),
1247
+			'datetime_tickets_list'             => $default ? '<li class="hidden"></li>' : '',
1248
+			'show_tickets_row'                  => 'display:none;',
1249
+			'add_new_datetime_ticket_help_link' => EEH_Template::get_help_tab_link(
1250
+				'add_new_ticket_via_datetime',
1251
+				$this->_adminpage_obj->page_slug,
1252
+				$this->_adminpage_obj->get_req_action()
1253
+			),
1254
+			// todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
1255
+			'DTT_ID'                            => $default ? '' : $datetime->ID(),
1256
+		];
1257
+		// need to setup the list items (but only if this isn't a default skeleton setup)
1258
+		if (! $default) {
1259
+			$ticket_row = 1;
1260
+			foreach ($all_tickets as $ticket) {
1261
+				$template_args['datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
1262
+					$datetime_row,
1263
+					$ticket_row,
1264
+					$datetime,
1265
+					$ticket,
1266
+					$datetime_tickets,
1267
+					$default
1268
+				);
1269
+				$ticket_row++;
1270
+			}
1271
+		}
1272
+		// filter template args at this point
1273
+		$template_args = apply_filters(
1274
+			'FHEE__espresso_events_Pricing_Hooks___get_dtt_attached_ticket_row__template_args',
1275
+			$template_args,
1276
+			$datetime_row,
1277
+			$datetime,
1278
+			$datetime_tickets,
1279
+			$all_tickets,
1280
+			$default,
1281
+			$this->_is_creating_event
1282
+		);
1283
+		return EEH_Template::display_template(
1284
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_attached_tickets_row.template.php',
1285
+			$template_args,
1286
+			true
1287
+		);
1288
+	}
1289
+
1290
+
1291
+	/**
1292
+	 * @param int              $datetime_row
1293
+	 * @param int              $ticket_row
1294
+	 * @param EE_Datetime|null $datetime
1295
+	 * @param EE_Ticket|null   $ticket
1296
+	 * @param array            $datetime_tickets
1297
+	 * @param bool             $default
1298
+	 * @return string
1299
+	 * @throws EE_Error
1300
+	 * @throws ReflectionException
1301
+	 */
1302
+	protected function _get_datetime_tickets_list_item(
1303
+		int $datetime_row,
1304
+		int $ticket_row,
1305
+		?EE_Datetime $datetime,
1306
+		?EE_Ticket $ticket,
1307
+		array $datetime_tickets = [],
1308
+		bool $default = false
1309
+	): string {
1310
+		$datetime_tickets = $datetime instanceof EE_Datetime && isset($datetime_tickets[ $datetime->ID() ])
1311
+			? $datetime_tickets[ $datetime->ID() ]
1312
+			: [];
1313
+		$display_row      = $ticket instanceof EE_Ticket ? $ticket->get('TKT_row') : 0;
1314
+		$no_ticket        = $default && empty($ticket);
1315
+		$template_args    = [
1316
+			'dtt_row'                 => $default
1317
+				? 'DTTNUM'
1318
+				: $datetime_row,
1319
+			'tkt_row'                 => $no_ticket
1320
+				? 'TICKETNUM'
1321
+				: $ticket_row,
1322
+			'datetime_ticket_checked' => in_array($display_row, $datetime_tickets, true)
1323
+				? ' checked'
1324
+				: '',
1325
+			'ticket_selected'         => in_array($display_row, $datetime_tickets, true)
1326
+				? ' ticket-selected'
1327
+				: '',
1328
+			'TKT_name'                => $no_ticket
1329
+				? 'TKTNAME'
1330
+				: $ticket->get('TKT_name'),
1331
+			'tkt_status_class'        => $no_ticket || $this->_is_creating_event
1332
+				? ' tkt-status-' . EE_Ticket::onsale
1333
+				: ' tkt-status-' . $ticket->ticket_status(),
1334
+		];
1335
+		// filter template args
1336
+		$template_args = apply_filters(
1337
+			'FHEE__espresso_events_Pricing_Hooks___get_datetime_tickets_list_item__template_args',
1338
+			$template_args,
1339
+			$datetime_row,
1340
+			$ticket_row,
1341
+			$datetime,
1342
+			$ticket,
1343
+			$datetime_tickets,
1344
+			$default,
1345
+			$this->_is_creating_event
1346
+		);
1347
+		return EEH_Template::display_template(
1348
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_dtt_tickets_list.template.php',
1349
+			$template_args,
1350
+			true
1351
+		);
1352
+	}
1353
+
1354
+
1355
+	/**
1356
+	 * This generates the ticket row for tickets.
1357
+	 * This same method is used to generate both the actual rows and the js skeleton row
1358
+	 * (when default === true)
1359
+	 *
1360
+	 * @param int            $ticket_row       Represents the row number being generated.
1361
+	 * @param EE_Ticket|null $ticket
1362
+	 * @param EE_Datetime[]  $ticket_datetimes Either an array of all datetimes on all tickets indexed by each ticket
1363
+	 *                                         or empty for default
1364
+	 * @param EE_Datetime[]  $all_datetimes    All Datetimes on the event or empty for default.
1365
+	 * @param bool           $default          Whether default row being generated or not.
1366
+	 * @param EE_Ticket[]    $all_tickets      This is an array of all tickets attached to the event
1367
+	 *                                         (or empty in the case of defaults)
1368
+	 * @return string
1369
+	 * @throws InvalidArgumentException
1370
+	 * @throws InvalidInterfaceException
1371
+	 * @throws InvalidDataTypeException
1372
+	 * @throws DomainException
1373
+	 * @throws EE_Error
1374
+	 * @throws ReflectionException
1375
+	 */
1376
+	protected function _get_ticket_row(
1377
+		int $ticket_row,
1378
+		?EE_Ticket $ticket,
1379
+		array $ticket_datetimes,
1380
+		array $all_datetimes,
1381
+		bool $default = false,
1382
+		array $all_tickets = []
1383
+	): string {
1384
+		// if $ticket is not an instance of EE_Ticket then force default to true.
1385
+		$default = ! $ticket instanceof EE_Ticket ? true : $default;
1386
+		$prices  = ! empty($ticket) && ! $default
1387
+			? $ticket->get_many_related(
1388
+				'Price',
1389
+				['default_where_conditions' => 'none', 'order_by' => ['PRC_order' => 'ASC']]
1390
+			)
1391
+			: [];
1392
+		// if there is only one price (which would be the base price)
1393
+		// or NO prices and this ticket is a default ticket,
1394
+		// let's just make sure there are no cached default prices on the object.
1395
+		// This is done by not including any query_params.
1396
+		if ($ticket instanceof EE_Ticket && $ticket->is_default() && (count($prices) === 1 || empty($prices))) {
1397
+			$prices = $ticket->prices();
1398
+		}
1399
+		// check if we're dealing with a default ticket in which case
1400
+		// we don't want any starting_ticket_datetime_row values set
1401
+		// (otherwise there won't be any new relationships created for tickets based off of the default ticket).
1402
+		// This will future proof in case there is ever any behaviour change between what the primary_key defaults to.
1403
+		$default_datetime = $default || ($ticket instanceof EE_Ticket && $ticket->is_default());
1404
+		$ticket_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[ $ticket->ID() ])
1405
+			? $ticket_datetimes[ $ticket->ID() ]
1406
+			: [];
1407
+		$ticket_subtotal  = $default ? 0 : $ticket->get_ticket_subtotal();
1408
+		$base_price       = $default ? null : $ticket->base_price();
1409
+		$count_price_mods = EEM_Price::instance()->get_all_default_prices(true);
1410
+		// breaking out complicated condition for ticket_status
1411
+		if ($default) {
1412
+			$ticket_status_class = ' tkt-status-' . EE_Ticket::onsale;
1413
+		} else {
1414
+			$ticket_status_class = $ticket->is_default()
1415
+				? ' tkt-status-' . EE_Ticket::onsale
1416
+				: ' tkt-status-' . $ticket->ticket_status();
1417
+		}
1418
+		// breaking out complicated condition for TKT_taxable
1419
+		if ($default) {
1420
+			$TKT_taxable = '';
1421
+		} else {
1422
+			$TKT_taxable = $ticket->taxable()
1423
+				? 'checked'
1424
+				: '';
1425
+		}
1426
+		if ($default) {
1427
+			$TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1428
+		} elseif ($ticket->is_default()) {
1429
+			$TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1430
+		} else {
1431
+			$TKT_status = $ticket->ticket_status(true);
1432
+		}
1433
+		if ($default) {
1434
+			$TKT_min = '';
1435
+		} else {
1436
+			$TKT_min = $ticket->min();
1437
+			if ($TKT_min === -1 || $TKT_min === 0) {
1438
+				$TKT_min = '';
1439
+			}
1440
+		}
1441
+		$template_args                 = [
1442
+			'tkt_row'                       => $default ? 'TICKETNUM' : $ticket_row,
1443
+			'TKT_order'                     => $default ? 'TICKETNUM' : $ticket_row,
1444
+			// on initial page load this will always be the correct order.
1445
+			'tkt_status_class'              => $ticket_status_class,
1446
+			'display_edit_tkt_row'          => 'display:none;',
1447
+			'edit_tkt_expanded'             => '',
1448
+			'edit_tickets_name'             => $default ? 'TICKETNAMEATTR' : 'edit_tickets',
1449
+			'TKT_name'                      => $default ? '' : $ticket->get_f('TKT_name'),
1450
+			'TKT_start_date'                => $default
1451
+				? ''
1452
+				: $ticket->get_date('TKT_start_date', $this->_date_time_format),
1453
+			'TKT_end_date'                  => $default
1454
+				? ''
1455
+				: $ticket->get_date('TKT_end_date', $this->_date_time_format),
1456
+			'TKT_status'                    => $TKT_status,
1457
+			'TKT_price'                     => $default
1458
+				? ''
1459
+				: EEH_Template::format_currency(
1460
+					$ticket->get_ticket_total_with_taxes(),
1461
+					false,
1462
+					false
1463
+				),
1464
+			'TKT_price_code'                => EE_Registry::instance()->CFG->currency->code,
1465
+			'TKT_price_amount'              => $default ? 0 : $ticket_subtotal,
1466
+			'TKT_qty'                       => $default
1467
+				? ''
1468
+				: $ticket->get_pretty('TKT_qty', 'symbol'),
1469
+			'TKT_qty_for_input'             => $default
1470
+				? ''
1471
+				: $ticket->get_pretty('TKT_qty', 'input'),
1472
+			'TKT_uses'                      => $default
1473
+				? ''
1474
+				: $ticket->get_pretty('TKT_uses', 'input'),
1475
+			'TKT_min'                       => $TKT_min,
1476
+			'TKT_max'                       => $default
1477
+				? ''
1478
+				: $ticket->get_pretty('TKT_max', 'input'),
1479
+			'TKT_sold'                      => $default ? 0 : $ticket->tickets_sold(),
1480
+			'TKT_reserved'                  => $default ? 0 : $ticket->reserved(),
1481
+			'TKT_registrations'             => $default
1482
+				? 0
1483
+				: $ticket->count_registrations(
1484
+					[
1485
+						[
1486
+							'STS_ID' => [
1487
+								'!=',
1488
+								EEM_Registration::status_id_incomplete,
1489
+							],
1490
+						],
1491
+					]
1492
+				),
1493
+			'TKT_ID'                        => $default ? 0 : $ticket->ID(),
1494
+			'TKT_description'               => $default ? '' : $ticket->get_f('TKT_description'),
1495
+			'TKT_is_default'                => $default ? 0 : $ticket->is_default(),
1496
+			'TKT_required'                  => $default ? 0 : $ticket->required(),
1497
+			'TKT_is_default_selector'       => '',
1498
+			'ticket_price_rows'             => '',
1499
+			'TKT_base_price'                => $default || ! $base_price instanceof EE_Price
1500
+				? ''
1501
+				: $base_price->get_pretty('PRC_amount', 'localized_float'),
1502
+			'TKT_base_price_ID'             => $default || ! $base_price instanceof EE_Price ? 0 : $base_price->ID(),
1503
+			'show_price_modifier'           => count($prices) > 1 || ($default && $count_price_mods > 0)
1504
+				? ''
1505
+				: 'display:none;',
1506
+			'show_price_mod_button'         => count($prices) > 1
1507
+											   || ($default && $count_price_mods > 0)
1508
+											   || (! $default && $ticket->deleted())
1509
+				? 'display:none;'
1510
+				: '',
1511
+			'total_price_rows'              => count($prices) > 1 ? count($prices) : 1,
1512
+			'ticket_datetimes_list'         => $default ? '<li class="hidden"></li>' : '',
1513
+			'starting_ticket_datetime_rows' => $default || $default_datetime ? '' : implode(',', $ticket_datetimes),
1514
+			'ticket_datetime_rows'          => $default ? '' : implode(',', $ticket_datetimes),
1515
+			'existing_ticket_price_ids'     => $default ? '' : implode(',', array_keys($prices)),
1516
+			'ticket_template_id'            => $default ? 0 : $ticket->get('TTM_ID'),
1517
+			'TKT_taxable'                   => $TKT_taxable,
1518
+			'display_subtotal'              => $ticket instanceof EE_Ticket && $ticket->taxable()
1519
+				? ''
1520
+				: 'display:none;',
1521
+			'price_currency_symbol'         => EE_Registry::instance()->CFG->currency->sign,
1522
+			'TKT_subtotal_amount_display'   => EEH_Template::format_currency(
1523
+				$ticket_subtotal,
1524
+				false,
1525
+				false
1526
+			),
1527
+			'TKT_subtotal_amount'           => $ticket_subtotal,
1528
+			'tax_rows'                      => $this->_get_tax_rows($ticket_row, $ticket),
1529
+			'disabled'                      => $ticket instanceof EE_Ticket && $ticket->deleted(),
1530
+			'ticket_archive_class'          => $ticket instanceof EE_Ticket && $ticket->deleted()
1531
+				? ' ticket-archived'
1532
+				: '',
1533
+			'trash_icon'                    => $ticket instanceof EE_Ticket
1534
+											   && $ticket->deleted()
1535
+											   && ! $ticket->is_permanently_deleteable()
1536
+				? 'dashicons dashicons-lock '
1537
+				: 'trash-icon dashicons dashicons-post-trash clickable',
1538
+			'clone_icon'                    => $ticket instanceof EE_Ticket && $ticket->deleted()
1539
+				? ''
1540
+				: 'clone-icon ee-icon ee-icon-clone clickable',
1541
+		];
1542
+		$template_args['trash_hidden'] = count($all_tickets) === 1
1543
+										 && $template_args['trash_icon'] !== 'dashicons dashicons-lock'
1544
+			? 'display:none'
1545
+			: '';
1546
+		// handle rows that should NOT be empty
1547
+		if (empty($template_args['TKT_start_date'])) {
1548
+			// if empty then the start date will be now.
1549
+			$template_args['TKT_start_date']   = date(
1550
+				$this->_date_time_format,
1551
+				current_time('timestamp')
1552
+			);
1553
+			$template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1554
+		}
1555
+		if (empty($template_args['TKT_end_date'])) {
1556
+			// get the earliest datetime (if present);
1557
+			$earliest_datetime = $this->_adminpage_obj->get_cpt_model_obj()->ID() > 0
1558
+				? $this->_adminpage_obj->get_cpt_model_obj()->get_first_related(
1559
+					'Datetime',
1560
+					['order_by' => ['DTT_EVT_start' => 'ASC']]
1561
+				)
1562
+				: null;
1563
+			if (! empty($earliest_datetime)) {
1564
+				$template_args['TKT_end_date'] = $earliest_datetime->get_datetime(
1565
+					'DTT_EVT_start',
1566
+					$this->_date_time_format
1567
+				);
1568
+			} else {
1569
+				// default so let's just use what's been set for the default date-time which is 30 days from now.
1570
+				$template_args['TKT_end_date'] = date(
1571
+					$this->_date_time_format,
1572
+					mktime(
1573
+						24,
1574
+						0,
1575
+						0,
1576
+						date('m'),
1577
+						date('d') + 29,
1578
+						date('Y')
1579
+					)
1580
+				);
1581
+			}
1582
+			$template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1583
+		}
1584
+		// generate ticket_datetime items
1585
+		if (! $default) {
1586
+			$datetime_row = 1;
1587
+			foreach ($all_datetimes as $datetime) {
1588
+				$template_args['ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
1589
+					$datetime_row,
1590
+					$ticket_row,
1591
+					$datetime,
1592
+					$ticket,
1593
+					$ticket_datetimes,
1594
+					$default
1595
+				);
1596
+				$datetime_row++;
1597
+			}
1598
+		}
1599
+		$price_row = 1;
1600
+		foreach ($prices as $price) {
1601
+			if (! $price instanceof EE_Price) {
1602
+				continue;
1603
+			}
1604
+			if ($price->is_base_price()) {
1605
+				$price_row++;
1606
+				continue;
1607
+			}
1608
+
1609
+			$show_trash  = ! ((count($prices) > 1 && $price_row === 1) || count($prices) === 1);
1610
+			$show_create = ! (count($prices) > 1 && count($prices) !== $price_row);
1611
+
1612
+			$template_args['ticket_price_rows'] .= $this->_get_ticket_price_row(
1613
+				$ticket_row,
1614
+				$price_row,
1615
+				$price,
1616
+				$default,
1617
+				$ticket,
1618
+				$show_trash,
1619
+				$show_create
1620
+			);
1621
+			$price_row++;
1622
+		}
1623
+		// filter $template_args
1624
+		$template_args = apply_filters(
1625
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_row__template_args',
1626
+			$template_args,
1627
+			$ticket_row,
1628
+			$ticket,
1629
+			$ticket_datetimes,
1630
+			$all_datetimes,
1631
+			$default,
1632
+			$all_tickets,
1633
+			$this->_is_creating_event
1634
+		);
1635
+		return EEH_Template::display_template(
1636
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_row.template.php',
1637
+			$template_args,
1638
+			true
1639
+		);
1640
+	}
1641
+
1642
+
1643
+	/**
1644
+	 * @param int            $ticket_row
1645
+	 * @param EE_Ticket|null $ticket
1646
+	 * @return string
1647
+	 * @throws DomainException
1648
+	 * @throws EE_Error
1649
+	 * @throws ReflectionException
1650
+	 */
1651
+	protected function _get_tax_rows(int $ticket_row, ?EE_Ticket $ticket): string
1652
+	{
1653
+		$tax_rows = '';
1654
+		/** @var EE_Price[] $taxes */
1655
+		$taxes = empty($ticket) ? EE_Taxes::get_taxes_for_admin() : $ticket->get_ticket_taxes_for_admin();
1656
+		foreach ($taxes as $tax) {
1657
+			$tax_added     = $this->_get_tax_added($tax, $ticket);
1658
+			$template_args = [
1659
+				'display_tax'       => ! empty($ticket) && $ticket->get('TKT_taxable')
1660
+					? ''
1661
+					: 'display:none;',
1662
+				'tax_id'            => $tax->ID(),
1663
+				'tkt_row'           => $ticket_row,
1664
+				'tax_label'         => $tax->get('PRC_name'),
1665
+				'tax_added'         => $tax_added,
1666
+				'tax_added_display' => EEH_Template::format_currency($tax_added, false, false),
1667
+				'tax_amount'        => $tax->get('PRC_amount'),
1668
+			];
1669
+			$template_args = apply_filters(
1670
+				'FHEE__espresso_events_Pricing_Hooks___get_tax_rows__template_args',
1671
+				$template_args,
1672
+				$ticket_row,
1673
+				$ticket,
1674
+				$this->_is_creating_event
1675
+			);
1676
+			$tax_rows      .= EEH_Template::display_template(
1677
+				PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_tax_row.template.php',
1678
+				$template_args,
1679
+				true
1680
+			);
1681
+		}
1682
+		return $tax_rows;
1683
+	}
1684
+
1685
+
1686
+	/**
1687
+	 * @param EE_Price       $tax
1688
+	 * @param EE_Ticket|null $ticket
1689
+	 * @return float|int
1690
+	 * @throws EE_Error
1691
+	 * @throws ReflectionException
1692
+	 */
1693
+	protected function _get_tax_added(EE_Price $tax, ?EE_Ticket $ticket)
1694
+	{
1695
+		$subtotal = empty($ticket) ? 0 : $ticket->get_ticket_subtotal();
1696
+		return $subtotal * $tax->get('PRC_amount') / 100;
1697
+	}
1698
+
1699
+
1700
+	/**
1701
+	 * @param int            $ticket_row
1702
+	 * @param int            $price_row
1703
+	 * @param EE_Price|null  $price
1704
+	 * @param bool           $default
1705
+	 * @param EE_Ticket|null $ticket
1706
+	 * @param bool           $show_trash
1707
+	 * @param bool           $show_create
1708
+	 * @return string
1709
+	 * @throws InvalidArgumentException
1710
+	 * @throws InvalidInterfaceException
1711
+	 * @throws InvalidDataTypeException
1712
+	 * @throws DomainException
1713
+	 * @throws EE_Error
1714
+	 * @throws ReflectionException
1715
+	 */
1716
+	protected function _get_ticket_price_row(
1717
+		int $ticket_row,
1718
+		int $price_row,
1719
+		?EE_Price $price,
1720
+		bool $default,
1721
+		?EE_Ticket $ticket,
1722
+		bool $show_trash = true,
1723
+		bool $show_create = true
1724
+	): string {
1725
+		$send_disabled = ! empty($ticket) && $ticket->get('TKT_deleted');
1726
+		$template_args = [
1727
+			'tkt_row'               => $default && empty($ticket)
1728
+				? 'TICKETNUM'
1729
+				: $ticket_row,
1730
+			'PRC_order'             => $default && empty($price)
1731
+				? 'PRICENUM'
1732
+				: $price_row,
1733
+			'edit_prices_name'      => $default && empty($price)
1734
+				? 'PRICENAMEATTR'
1735
+				: 'edit_prices',
1736
+			'price_type_selector'   => $default && empty($price)
1737
+				? $this->_get_base_price_template($ticket_row, $price_row, $price, true)
1738
+				: $this->_get_price_type_selector(
1739
+					$ticket_row,
1740
+					$price_row,
1741
+					$price,
1742
+					$default,
1743
+					$send_disabled
1744
+				),
1745
+			'PRC_ID'                => $default && empty($price)
1746
+				? 0
1747
+				: $price->ID(),
1748
+			'PRC_is_default'        => $default && empty($price)
1749
+				? 0
1750
+				: $price->get('PRC_is_default'),
1751
+			'PRC_name'              => $default && empty($price)
1752
+				? ''
1753
+				: $price->get('PRC_name'),
1754
+			'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1755
+			'show_plus_or_minus'    => $default && empty($price)
1756
+				? ''
1757
+				: 'display:none;',
1758
+			'show_plus'             => ($default && empty($price)) || ($price->is_discount() || $price->is_base_price())
1759
+				? 'display:none;'
1760
+				: '',
1761
+			'show_minus'            => ($default && empty($price)) || ! $price->is_discount()
1762
+				? 'display:none;'
1763
+				: '',
1764
+			'show_currency_symbol'  => ($default && empty($price)) || $price->is_percent()
1765
+				? 'display:none'
1766
+				: '',
1767
+			'PRC_amount'            => $default && empty($price)
1768
+				? 0
1769
+				: $price->get_pretty('PRC_amount', 'localized_float'),
1770
+			'show_percentage'       => ($default && empty($price)) || ! $price->is_percent()
1771
+				? 'display:none;'
1772
+				: '',
1773
+			'show_trash_icon'       => $show_trash
1774
+				? ''
1775
+				: ' style="display:none;"',
1776
+			'show_create_button'    => $show_create
1777
+				? ''
1778
+				: ' style="display:none;"',
1779
+			'PRC_desc'              => $default && empty($price)
1780
+				? ''
1781
+				: $price->get('PRC_desc'),
1782
+			'disabled'              => ! empty($ticket) && $ticket->get('TKT_deleted'),
1783
+		];
1784
+		$template_args = apply_filters(
1785
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_price_row__template_args',
1786
+			$template_args,
1787
+			$ticket_row,
1788
+			$price_row,
1789
+			$price,
1790
+			$default,
1791
+			$ticket,
1792
+			$show_trash,
1793
+			$show_create,
1794
+			$this->_is_creating_event
1795
+		);
1796
+		return EEH_Template::display_template(
1797
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_price_row.template.php',
1798
+			$template_args,
1799
+			true
1800
+		);
1801
+	}
1802
+
1803
+
1804
+	/**
1805
+	 * @param int           $ticket_row
1806
+	 * @param int           $price_row
1807
+	 * @param EE_Price|null $price
1808
+	 * @param bool          $default
1809
+	 * @param bool          $disabled
1810
+	 * @return string
1811
+	 * @throws ReflectionException
1812
+	 * @throws InvalidArgumentException
1813
+	 * @throws InvalidInterfaceException
1814
+	 * @throws InvalidDataTypeException
1815
+	 * @throws DomainException
1816
+	 * @throws EE_Error
1817
+	 */
1818
+	protected function _get_price_type_selector(
1819
+		int $ticket_row,
1820
+		int $price_row,
1821
+		?EE_Price $price,
1822
+		bool $default,
1823
+		bool $disabled = false
1824
+	): string {
1825
+		if ($price->is_base_price()) {
1826
+			return $this->_get_base_price_template(
1827
+				$ticket_row,
1828
+				$price_row,
1829
+				$price,
1830
+				$default
1831
+			);
1832
+		}
1833
+		return $this->_get_price_modifier_template(
1834
+			$ticket_row,
1835
+			$price_row,
1836
+			$price,
1837
+			$default,
1838
+			$disabled
1839
+		);
1840
+	}
1841
+
1842
+
1843
+	/**
1844
+	 * @param int           $ticket_row
1845
+	 * @param int           $price_row
1846
+	 * @param EE_Price|null $price
1847
+	 * @param bool          $default
1848
+	 * @return string
1849
+	 * @throws DomainException
1850
+	 * @throws EE_Error
1851
+	 * @throws ReflectionException
1852
+	 */
1853
+	protected function _get_base_price_template(
1854
+		int $ticket_row,
1855
+		int $price_row,
1856
+		?EE_Price $price,
1857
+		bool $default
1858
+	): string {
1859
+		$template_args = [
1860
+			'tkt_row'                   => $default ? 'TICKETNUM' : $ticket_row,
1861
+			'PRC_order'                 => $default && empty($price) ? 'PRICENUM' : $price_row,
1862
+			'PRT_ID'                    => $default && empty($price) ? 1 : $price->get('PRT_ID'),
1863
+			'PRT_name'                  => esc_html__('Price', 'event_espresso'),
1864
+			'price_selected_operator'   => '+',
1865
+			'price_selected_is_percent' => 0,
1866
+		];
1867
+		$template_args = apply_filters(
1868
+			'FHEE__espresso_events_Pricing_Hooks___get_base_price_template__template_args',
1869
+			$template_args,
1870
+			$ticket_row,
1871
+			$price_row,
1872
+			$price,
1873
+			$default,
1874
+			$this->_is_creating_event
1875
+		);
1876
+		return EEH_Template::display_template(
1877
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_type_base.template.php',
1878
+			$template_args,
1879
+			true
1880
+		);
1881
+	}
1882
+
1883
+
1884
+	/**
1885
+	 * @param int           $ticket_row
1886
+	 * @param int           $price_row
1887
+	 * @param EE_Price|null $price
1888
+	 * @param bool          $default
1889
+	 * @param bool          $disabled
1890
+	 * @return string
1891
+	 * @throws ReflectionException
1892
+	 * @throws InvalidArgumentException
1893
+	 * @throws InvalidInterfaceException
1894
+	 * @throws InvalidDataTypeException
1895
+	 * @throws DomainException
1896
+	 * @throws EE_Error
1897
+	 */
1898
+	protected function _get_price_modifier_template(
1899
+		int $ticket_row,
1900
+		int $price_row,
1901
+		?EE_Price $price,
1902
+		bool $default,
1903
+		bool $disabled = false
1904
+	): string {
1905
+		$select_name = $default && ! $price instanceof EE_Price
1906
+			? 'edit_prices[TICKETNUM][PRICENUM][PRT_ID]'
1907
+			: 'edit_prices[' . esc_attr($ticket_row) . '][' . esc_attr($price_row) . '][PRT_ID]';
1908
+		/** @var EEM_Price_Type $price_type_model */
1909
+		$price_type_model       = EE_Registry::instance()->load_model('Price_Type');
1910
+		$price_types            = $price_type_model->get_all(
1911
+			[
1912
+				[
1913
+					'OR' => [
1914
+						'PBT_ID'  => '2',
1915
+						'PBT_ID*' => '3',
1916
+					],
1917
+				],
1918
+			]
1919
+		);
1920
+		$all_price_types        = $default && ! $price instanceof EE_Price
1921
+			? [esc_html__('Select Modifier', 'event_espresso')]
1922
+			: [];
1923
+		$selected_price_type_id = $default && ! $price instanceof EE_Price ? 0 : $price->type();
1924
+		$price_option_spans     = '';
1925
+		// setup price types for selector
1926
+		foreach ($price_types as $price_type) {
1927
+			if (! $price_type instanceof EE_Price_Type) {
1928
+				continue;
1929
+			}
1930
+			$all_price_types[ $price_type->ID() ] = $price_type->get('PRT_name');
1931
+			// while we're in the loop let's setup the option spans used by js
1932
+			$span_args          = [
1933
+				'PRT_ID'         => $price_type->ID(),
1934
+				'PRT_operator'   => $price_type->is_discount() ? '-' : '+',
1935
+				'PRT_is_percent' => $price_type->get('PRT_is_percent') ? 1 : 0,
1936
+			];
1937
+			$price_option_spans .= EEH_Template::display_template(
1938
+				PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_option_span.template.php',
1939
+				$span_args,
1940
+				true
1941
+			);
1942
+		}
1943
+
1944
+		$select_name = $disabled
1945
+			? 'archive_price[' . $ticket_row . '][' . $price_row . '][PRT_ID]'
1946
+			: $select_name;
1947
+
1948
+		$select_input = new EE_Select_Input(
1949
+			$all_price_types,
1950
+			[
1951
+				'default'               => $selected_price_type_id,
1952
+				'html_name'             => $select_name,
1953
+				'html_class'            => 'edit-price-PRT_ID',
1954
+				'other_html_attributes' => $disabled ? 'style="width:auto;" disabled' : 'style="width:auto;"',
1955
+			]
1956
+		);
1957
+
1958
+		$price_selected_operator   = $price instanceof EE_Price && $price->is_discount() ? '-' : '+';
1959
+		$price_selected_operator   = $default && ! $price instanceof EE_Price ? '' : $price_selected_operator;
1960
+		$price_selected_is_percent = $price instanceof EE_Price && $price->is_percent() ? 1 : 0;
1961
+		$price_selected_is_percent = $default && ! $price instanceof EE_Price ? '' : $price_selected_is_percent;
1962
+		$template_args             = [
1963
+			'tkt_row'                   => $default ? 'TICKETNUM' : $ticket_row,
1964
+			'PRC_order'                 => $default && ! $price instanceof EE_Price ? 'PRICENUM' : $price_row,
1965
+			'price_modifier_selector'   => $select_input->get_html_for_input(),
1966
+			'main_name'                 => $select_name,
1967
+			'selected_price_type_id'    => $selected_price_type_id,
1968
+			'price_option_spans'        => $price_option_spans,
1969
+			'price_selected_operator'   => $price_selected_operator,
1970
+			'price_selected_is_percent' => $price_selected_is_percent,
1971
+			'disabled'                  => $disabled,
1972
+		];
1973
+		$template_args             = apply_filters(
1974
+			'FHEE__espresso_events_Pricing_Hooks___get_price_modifier_template__template_args',
1975
+			$template_args,
1976
+			$ticket_row,
1977
+			$price_row,
1978
+			$price,
1979
+			$default,
1980
+			$disabled,
1981
+			$this->_is_creating_event
1982
+		);
1983
+		return EEH_Template::display_template(
1984
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_modifier_selector.template.php',
1985
+			$template_args,
1986
+			true
1987
+		);
1988
+	}
1989
+
1990
+
1991
+	/**
1992
+	 * @param int              $datetime_row
1993
+	 * @param int              $ticket_row
1994
+	 * @param EE_Datetime|null $datetime
1995
+	 * @param EE_Ticket|null   $ticket
1996
+	 * @param array            $ticket_datetimes
1997
+	 * @param bool             $default
1998
+	 * @return string
1999
+	 * @throws DomainException
2000
+	 * @throws EE_Error
2001
+	 * @throws ReflectionException
2002
+	 */
2003
+	protected function _get_ticket_datetime_list_item(
2004
+		int $datetime_row,
2005
+		int $ticket_row,
2006
+		?EE_Datetime $datetime,
2007
+		?EE_Ticket $ticket,
2008
+		array $ticket_datetimes = [],
2009
+		bool $default = false
2010
+	): string {
2011
+		$ticket_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[ $ticket->ID() ])
2012
+			? $ticket_datetimes[ $ticket->ID() ]
2013
+			: [];
2014
+		$template_args    = [
2015
+			'dtt_row'                  => $default && ! $datetime instanceof EE_Datetime
2016
+				? 'DTTNUM'
2017
+				: $datetime_row,
2018
+			'tkt_row'                  => $default
2019
+				? 'TICKETNUM'
2020
+				: $ticket_row,
2021
+			'ticket_datetime_selected' => in_array($datetime_row, $ticket_datetimes, true)
2022
+				? ' ticket-selected'
2023
+				: '',
2024
+			'ticket_datetime_checked'  => in_array($datetime_row, $ticket_datetimes, true)
2025
+				? ' checked'
2026
+				: '',
2027
+			'DTT_name'                 => $default && empty($datetime)
2028
+				? 'DTTNAME'
2029
+				: $datetime->get_dtt_display_name(true),
2030
+			'tkt_status_class'         => '',
2031
+		];
2032
+		$template_args    = apply_filters(
2033
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_datetime_list_item__template_args',
2034
+			$template_args,
2035
+			$datetime_row,
2036
+			$ticket_row,
2037
+			$datetime,
2038
+			$ticket,
2039
+			$ticket_datetimes,
2040
+			$default,
2041
+			$this->_is_creating_event
2042
+		);
2043
+		return EEH_Template::display_template(
2044
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_datetimes_list_item.template.php',
2045
+			$template_args,
2046
+			true
2047
+		);
2048
+	}
2049
+
2050
+
2051
+	/**
2052
+	 * @param array $all_datetimes
2053
+	 * @param array $all_tickets
2054
+	 * @return string
2055
+	 * @throws ReflectionException
2056
+	 * @throws InvalidArgumentException
2057
+	 * @throws InvalidInterfaceException
2058
+	 * @throws InvalidDataTypeException
2059
+	 * @throws DomainException
2060
+	 * @throws EE_Error
2061
+	 */
2062
+	protected function _get_ticket_js_structure(array $all_datetimes = [], array $all_tickets = []): string
2063
+	{
2064
+		$template_args = [
2065
+			'default_datetime_edit_row' => $this->_get_dtt_edit_row(
2066
+				'DTTNUM',
2067
+				null,
2068
+				true,
2069
+				$all_datetimes
2070
+			),
2071
+			'default_ticket_row'        => $this->_get_ticket_row(
2072
+				'TICKETNUM',
2073
+				null,
2074
+				[],
2075
+				[],
2076
+				true
2077
+			),
2078
+			'default_price_row'         => $this->_get_ticket_price_row(
2079
+				'TICKETNUM',
2080
+				'PRICENUM',
2081
+				null,
2082
+				true,
2083
+				null
2084
+			),
2085
+
2086
+			'default_price_rows'                       => '',
2087
+			'default_base_price_amount'                => 0,
2088
+			'default_base_price_name'                  => '',
2089
+			'default_base_price_description'           => '',
2090
+			'default_price_modifier_selector_row'      => $this->_get_price_modifier_template(
2091
+				'TICKETNUM',
2092
+				'PRICENUM',
2093
+				null,
2094
+				true
2095
+			),
2096
+			'default_available_tickets_for_datetime'   => $this->_get_dtt_attached_tickets_row(
2097
+				'DTTNUM',
2098
+				null,
2099
+				[],
2100
+				[],
2101
+				true
2102
+			),
2103
+			'existing_available_datetime_tickets_list' => '',
2104
+			'existing_available_ticket_datetimes_list' => '',
2105
+			'new_available_datetime_ticket_list_item'  => $this->_get_datetime_tickets_list_item(
2106
+				'DTTNUM',
2107
+				'TICKETNUM',
2108
+				null,
2109
+				null,
2110
+				[],
2111
+				true
2112
+			),
2113
+			'new_available_ticket_datetime_list_item'  => $this->_get_ticket_datetime_list_item(
2114
+				'DTTNUM',
2115
+				'TICKETNUM',
2116
+				null,
2117
+				null,
2118
+				[],
2119
+				true
2120
+			),
2121
+		];
2122
+		$ticket_row    = 1;
2123
+		foreach ($all_tickets as $ticket) {
2124
+			$template_args['existing_available_datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
2125
+				'DTTNUM',
2126
+				$ticket_row,
2127
+				null,
2128
+				$ticket,
2129
+				[],
2130
+				true
2131
+			);
2132
+			$ticket_row++;
2133
+		}
2134
+		$datetime_row = 1;
2135
+		foreach ($all_datetimes as $datetime) {
2136
+			$template_args['existing_available_ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
2137
+				$datetime_row,
2138
+				'TICKETNUM',
2139
+				$datetime,
2140
+				null,
2141
+				[],
2142
+				true
2143
+			);
2144
+			$datetime_row++;
2145
+		}
2146
+		/** @var EEM_Price $price_model */
2147
+		$price_model    = EE_Registry::instance()->load_model('Price');
2148
+		$default_prices = $price_model->get_all_default_prices();
2149
+		$price_row      = 1;
2150
+		foreach ($default_prices as $price) {
2151
+			if (! $price instanceof EE_Price) {
2152
+				continue;
2153
+			}
2154
+			if ($price->is_base_price()) {
2155
+				$template_args['default_base_price_amount']      = $price->get_pretty(
2156
+					'PRC_amount',
2157
+					'localized_float'
2158
+				);
2159
+				$template_args['default_base_price_name']        = $price->get('PRC_name');
2160
+				$template_args['default_base_price_description'] = $price->get('PRC_desc');
2161
+				$price_row++;
2162
+				continue;
2163
+			}
2164
+
2165
+			$show_trash  = ! ((count($default_prices) > 1 && $price_row === 1) || count($default_prices) === 1);
2166
+			$show_create = ! (count($default_prices) > 1 && count($default_prices) !== $price_row);
2167
+
2168
+			$template_args['default_price_rows'] .= $this->_get_ticket_price_row(
2169
+				'TICKETNUM',
2170
+				$price_row,
2171
+				$price,
2172
+				true,
2173
+				null,
2174
+				$show_trash,
2175
+				$show_create
2176
+			);
2177
+			$price_row++;
2178
+		}
2179
+		$template_args = apply_filters(
2180
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_js_structure__template_args',
2181
+			$template_args,
2182
+			$all_datetimes,
2183
+			$all_tickets,
2184
+			$this->_is_creating_event
2185
+		);
2186
+		return EEH_Template::display_template(
2187
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_js_structure.template.php',
2188
+			$template_args,
2189
+			true
2190
+		);
2191
+	}
2192 2192
 }
Please login to merge, or discard this patch.