Completed
Branch master (876dd2)
by
unknown
02:51
created
core/db_classes/EE_Export.class.php 1 patch
Indentation   +780 added lines, -780 removed lines patch added patch discarded remove patch
@@ -17,784 +17,784 @@
 block discarded – undo
17 17
  */
18 18
 class EE_Export
19 19
 {
20
-    const option_prefix = 'ee_report_job_';
21
-
22
-
23
-    // instance of the EE_Export object
24
-    private static $_instance = null;
25
-
26
-    // instance of the EE_CSV object
27
-    /**
28
-     *
29
-     * @var EE_CSV
30
-     */
31
-    public $EE_CSV = null;
32
-
33
-
34
-    private $_req_data = array();
35
-
36
-
37
-    /**
38
-     *        private constructor to prevent direct creation
39
-     *
40
-     * @Constructor
41
-     * @access private
42
-     * @param array $request_data
43
-     */
44
-    private function __construct($request_data = array())
45
-    {
46
-        $this->_req_data = $request_data;
47
-        $this->today = date("Y-m-d", time());
48
-        require_once(EE_CLASSES . 'EE_CSV.class.php');
49
-        $this->EE_CSV = EE_CSV::instance();
50
-    }
51
-
52
-
53
-    /**
54
-     *        @ singleton method used to instantiate class object
55
-     *        @ access public
56
-     *
57
-     * @param array $request_data
58
-     * @return \EE_Export
59
-     */
60
-    public static function instance($request_data = array())
61
-    {
62
-        // check if class object is instantiated
63
-        if (self::$_instance === null or ! is_object(self::$_instance) or ! (self::$_instance instanceof EE_Export)) {
64
-            self::$_instance = new self($request_data);
65
-        }
66
-        return self::$_instance;
67
-    }
68
-
69
-
70
-    /**
71
-     * @Export Event Espresso data - routes export requests
72
-     * @access public
73
-     * @return void | bool
74
-     */
75
-    public function export()
76
-    {
77
-        // in case of bulk exports, the "actual" action will be in action2, but first check regular action for "export" keyword
78
-        if (isset($this->_req_data['action']) && strpos($this->_req_data['action'], 'export') === false) {
79
-            // check if action2 has export action
80
-            if (isset($this->_req_data['action2']) && strpos($this->_req_data['action2'], 'export') !== false) {
81
-                // whoop! there it is!
82
-                $this->_req_data['action'] = $this->_req_data['action2'];
83
-            }
84
-        }
85
-
86
-        $this->_req_data['export'] = isset($this->_req_data['export']) ? $this->_req_data['export'] : '';
87
-
88
-        switch ($this->_req_data['export']) {
89
-            case 'report':
90
-                switch ($this->_req_data['action']) {
91
-                    case "event":
92
-                    case "export_events":
93
-                    case 'all_event_data':
94
-                        $this->export_all_event_data();
95
-                        break;
96
-
97
-                    case 'registrations_report_for_event':
98
-                        $this->report_registrations_for_event($this->_req_data['EVT_ID']);
99
-                        break;
100
-
101
-                    case 'attendees':
102
-                        $this->export_attendees();
103
-                        break;
104
-
105
-                    case 'categories':
106
-                        $this->export_categories();
107
-                        break;
108
-
109
-                    default:
110
-                        EE_Error::add_error(
111
-                            esc_html__('An error occurred! The requested export report could not be found.', 'event_espresso'),
112
-                            __FILE__,
113
-                            __FUNCTION__,
114
-                            __LINE__
115
-                        );
116
-                        return false;
117
-                        break;
118
-                }
119
-                break; // end of switch export : report
120
-            default:
121
-                break;
122
-        } // end of switch export
123
-
124
-        exit;
125
-    }
126
-
127
-    /**
128
-     * Downloads a CSV file with all the columns, but no data. This should be used for importing
129
-     *
130
-     * @return void kills execution
131
-     * @throws EE_Error
132
-     * @throws ReflectionException
133
-     */
134
-    public function export_sample()
135
-    {
136
-        $event = EEM_Event::instance()->get_one();
137
-        $this->_req_data['EVT_ID'] = $event->ID();
138
-        $this->export_all_event_data();
139
-    }
140
-
141
-
142
-    /**
143
-     * @Export data for ALL events
144
-     * @access public
145
-     * @return void
146
-     * @throws EE_Error
147
-     * @throws ReflectionException
148
-     */
149
-    public function export_all_event_data()
150
-    {
151
-        // are any Event IDs set?
152
-        $event_query_params = array();
153
-        $related_models_query_params = array();
154
-        $related_through_reg_query_params = array();
155
-        $datetime_ticket_query_params = array();
156
-        $price_query_params = array();
157
-        $price_type_query_params = array();
158
-        $term_query_params = array();
159
-        $state_country_query_params = array();
160
-        $question_group_query_params = array();
161
-        $question_query_params = array();
162
-        if (isset($this->_req_data['EVT_ID'])) {
163
-            // do we have an array of IDs ?
164
-
165
-            if (is_array($this->_req_data['EVT_ID'])) {
166
-                $EVT_IDs = array_map('sanitize_text_field', $this->_req_data['EVT_ID']);
167
-                $value_to_equal = array('IN', $EVT_IDs);
168
-                $filename = 'events';
169
-            } else {
170
-                // generate regular where = clause
171
-                $EVT_ID = absint($this->_req_data['EVT_ID']);
172
-                $value_to_equal = $EVT_ID;
173
-                $event = EE_Registry::instance()->load_model('Event')->get_one_by_ID($EVT_ID);
174
-
175
-                $filename = 'event-' . ($event instanceof EE_Event ? $event->slug() : esc_html__('unknown', 'event_espresso'));
176
-            }
177
-            $event_query_params[0]['EVT_ID'] = $value_to_equal;
178
-            $related_models_query_params[0]['Event.EVT_ID'] = $value_to_equal;
179
-            $related_through_reg_query_params[0]['Registration.EVT_ID'] = $value_to_equal;
180
-            $datetime_ticket_query_params[0]['Datetime.EVT_ID'] = $value_to_equal;
181
-            $price_query_params[0]['Ticket.Datetime.EVT_ID'] = $value_to_equal;
182
-            $price_type_query_params[0]['Price.Ticket.Datetime.EVT_ID'] = $value_to_equal;
183
-            $term_query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $value_to_equal;
184
-            $state_country_query_params[0]['Venue.Event.EVT_ID'] = $value_to_equal;
185
-            $question_group_query_params[0]['Event.EVT_ID'] = $value_to_equal;
186
-            $question_query_params[0]['Question_Group.Event.EVT_ID'] = $value_to_equal;
187
-        } else {
188
-            $filename = 'all-events';
189
-        }
190
-
191
-
192
-        // array in the format:  table name =>  query where clause
193
-        $models_to_export = array(
194
-            'Event'                   => $event_query_params,
195
-            'Datetime'                => $related_models_query_params,
196
-            'Ticket_Template'         => $price_query_params,
197
-            'Ticket'                  => $datetime_ticket_query_params,
198
-            'Datetime_Ticket'         => $datetime_ticket_query_params,
199
-            'Price_Type'              => $price_type_query_params,
200
-            'Price'                   => $price_query_params,
201
-            'Ticket_Price'            => $price_query_params,
202
-            'Term'                    => $term_query_params,
203
-            'Term_Taxonomy'           => $related_models_query_params,
204
-            'Term_Relationship'       => $related_models_query_params, // model has NO primary key...
205
-            'Country'                 => $state_country_query_params,
206
-            'State'                   => $state_country_query_params,
207
-            'Venue'                   => $related_models_query_params,
208
-            'Event_Venue'             => $related_models_query_params,
209
-            'Question_Group'          => $question_group_query_params,
210
-            'Event_Question_Group'    => $question_group_query_params,
211
-            'Question'                => $question_query_params,
212
-            'Question_Group_Question' => $question_query_params,
213
-            // 'Transaction'=>$related_through_reg_query_params,
214
-            // 'Registration'=>$related_models_query_params,
215
-            // 'Attendee'=>$related_through_reg_query_params,
216
-            // 'Line_Item'=>
217
-
218
-        );
219
-
220
-        $model_data = $this->_get_export_data_for_models($models_to_export);
221
-
222
-        $filename = $this->generate_filename($filename);
223
-
224
-        if (! $this->EE_CSV->export_multiple_model_data_to_csv($filename, $model_data)) {
225
-            EE_Error::add_error(
226
-                esc_html__(
227
-                    "'An error occurred and the Event details could not be exported from the database.'",
228
-                    "event_espresso"
229
-                ),
230
-                __FILE__,
231
-                __FUNCTION__,
232
-                __LINE__
233
-            );
234
-        }
235
-    }
236
-
237
-    public function report_attendees()
238
-    {
239
-        $attendee_rows = EEM_Attendee::instance()->get_all_wpdb_results(
240
-            array(
241
-                'force_join' => array('State', 'Country'),
242
-                'caps'       => EEM_Base::caps_read_admin,
243
-            )
244
-        );
245
-        $csv_data = array();
246
-        foreach ($attendee_rows as $attendee_row) {
247
-            $csv_row = array();
248
-            foreach (EEM_Attendee::instance()->field_settings() as $field_name => $field_obj) {
249
-                if ($field_name == 'STA_ID') {
250
-                    $state_name_field = EEM_State::instance()->field_settings_for('STA_name');
251
-                    $csv_row[ esc_html__('State', 'event_espresso') ] = $attendee_row[ $state_name_field->get_qualified_column(
252
-                    ) ];
253
-                } elseif ($field_name == 'CNT_ISO') {
254
-                    $country_name_field = EEM_Country::instance()->field_settings_for('CNT_name');
255
-                    $csv_row[ esc_html__(
256
-                        'Country',
257
-                        'event_espresso'
258
-                    ) ] = $attendee_row[ $country_name_field->get_qualified_column() ];
259
-                } else {
260
-                    $csv_row[ $field_obj->get_nicename() ] = $attendee_row[ $field_obj->get_qualified_column() ];
261
-                }
262
-            }
263
-            $csv_data[] = $csv_row;
264
-        }
265
-
266
-        $filename = $this->generate_filename('contact-list-report');
267
-
268
-        $handle = $this->EE_CSV->begin_sending_csv($filename);
269
-        $this->EE_CSV->write_data_array_to_csv($handle, $csv_data);
270
-        $this->EE_CSV->end_sending_csv($handle);
271
-    }
272
-
273
-
274
-    /**
275
-     * @Export data for ALL attendees
276
-     * @access public
277
-     * @return void
278
-     * @throws EE_Error
279
-     */
280
-    public function export_attendees()
281
-    {
282
-
283
-        $states_that_have_an_attendee = EEM_State::instance()->get_all(
284
-            array(0 => array('Attendee.ATT_ID' => array('IS NOT NULL')))
285
-        );
286
-        $countries_that_have_an_attendee = EEM_Country::instance()->get_all(
287
-            array(0 => array('Attendee.ATT_ID' => array('IS NOT NULL')))
288
-        );
289
-        // $states_to_export_query_params
290
-        $models_to_export = array(
291
-            'Country'  => array(array('CNT_ISO' => array('IN', array_keys($countries_that_have_an_attendee)))),
292
-            'State'    => array(array('STA_ID' => array('IN', array_keys($states_that_have_an_attendee)))),
293
-            'Attendee' => array(),
294
-        );
295
-
296
-
297
-        $model_data = $this->_get_export_data_for_models($models_to_export);
298
-        $filename = $this->generate_filename('all-attendees');
299
-
300
-        if (! $this->EE_CSV->export_multiple_model_data_to_csv($filename, $model_data)) {
301
-            EE_Error::add_error(
302
-                esc_html__(
303
-                    'An error occurred and the Attendee data could not be exported from the database.',
304
-                    'event_espresso'
305
-                ),
306
-                __FILE__,
307
-                __FUNCTION__,
308
-                __LINE__
309
-            );
310
-        }
311
-    }
312
-
313
-    /**
314
-     * Shortcut for preparing a database result for display
315
-     *
316
-     * @param EEM_Base $model
317
-     * @param string $field_name
318
-     * @param string $raw_db_value
319
-     * @param bool|string $pretty_schema true to display pretty, a string to use a specific "Schema", or false to
320
-     *                                      NOT display pretty
321
-     * @return string
322
-     * @throws EE_Error
323
-     */
324
-    protected function _prepare_value_from_db_for_display($model, $field_name, $raw_db_value, $pretty_schema = true)
325
-    {
326
-        $field_obj = $model->field_settings_for($field_name);
327
-        $value_on_model_obj = $field_obj->prepare_for_set_from_db($raw_db_value);
328
-        if ($field_obj instanceof EE_Datetime_Field) {
329
-            $field_obj->set_date_format(
330
-                EE_CSV::instance()->get_date_format_for_csv($field_obj->get_date_format($pretty_schema)),
331
-                $pretty_schema
332
-            );
333
-            $field_obj->set_time_format(
334
-                EE_CSV::instance()->get_time_format_for_csv($field_obj->get_time_format($pretty_schema)),
335
-                $pretty_schema
336
-            );
337
-        }
338
-        if ($pretty_schema === true) {
339
-            return $field_obj->prepare_for_pretty_echoing($value_on_model_obj);
340
-        } elseif (is_string($pretty_schema)) {
341
-            return $field_obj->prepare_for_pretty_echoing($value_on_model_obj, $pretty_schema);
342
-        } else {
343
-            return $field_obj->prepare_for_get($value_on_model_obj);
344
-        }
345
-    }
346
-
347
-    /**
348
-     * Export a custom CSV of registration info including: A bunch of the reg fields, the time of the event, the price
349
-     * name, and the questions associated with the registrations
350
-     *
351
-     * @param int $event_id
352
-     * @throws EE_Error
353
-     * @throws ReflectionException
354
-     */
355
-    public function report_registrations_for_event($event_id = null)
356
-    {
357
-        $reg_fields_to_include = array(
358
-            'TXN_ID',
359
-            'ATT_ID',
360
-            'REG_ID',
361
-            'REG_date',
362
-            'REG_code',
363
-            'REG_count',
364
-            'REG_final_price',
365
-
366
-        );
367
-        $att_fields_to_include = array(
368
-            'ATT_fname',
369
-            'ATT_lname',
370
-            'ATT_email',
371
-            'ATT_address',
372
-            'ATT_address2',
373
-            'ATT_city',
374
-            'STA_ID',
375
-            'CNT_ISO',
376
-            'ATT_zip',
377
-            'ATT_phone',
378
-        );
379
-
380
-        $registrations_csv_ready_array = array();
381
-        $reg_model = EE_Registry::instance()->load_model('Registration');
382
-        $query_params = apply_filters(
383
-            'FHEE__EE_Export__report_registration_for_event',
384
-            array(
385
-                array(
386
-                    'OR'                 => array(
387
-                        // don't include registrations from failed or abandoned transactions...
388
-                        'Transaction.STS_ID' => array(
389
-                            'NOT IN',
390
-                            array(EEM_Transaction::failed_status_code, EEM_Transaction::abandoned_status_code),
391
-                        ),
392
-                        // unless the registration is approved, in which case include it regardless of transaction status
393
-                        'STS_ID'             => EEM_Registration::status_id_approved,
394
-                    ),
395
-                    'Ticket.TKT_deleted' => array('IN', array(true, false)),
396
-                ),
397
-                'order_by'   => array('Transaction.TXN_ID' => 'asc', 'REG_count' => 'asc'),
398
-                'force_join' => array('Transaction', 'Ticket', 'Attendee'),
399
-                'caps'       => EEM_Base::caps_read_admin,
400
-            ),
401
-            $event_id
402
-        );
403
-        if ($event_id) {
404
-            $query_params[0]['EVT_ID'] = $event_id;
405
-        } else {
406
-            $query_params['force_join'][] = 'Event';
407
-        }
408
-        $registration_rows = $reg_model->get_all_wpdb_results($query_params);
409
-        // get all questions which relate to someone in this group
410
-        $registration_ids = array();
411
-        foreach ($registration_rows as $reg_row) {
412
-            $registration_ids[] = intval($reg_row['Registration.REG_ID']);
413
-        }
414
-        // EEM_Question::instance()->show_next_x_db_queries();
415
-        $questions_for_these_regs_rows = EEM_Question::instance()->get_all_wpdb_results(
416
-            array(array('Answer.REG_ID' => array('IN', $registration_ids)))
417
-        );
418
-        foreach ($registration_rows as $reg_row) {
419
-            if (is_array($reg_row)) {
420
-                $reg_csv_array = array();
421
-                if (! $event_id) {
422
-                    // get the event's name and Id
423
-                    $reg_csv_array[ esc_html__('Event', 'event_espresso') ] = sprintf(
424
-                        esc_html__('%1$s (%2$s)', 'event_espresso'),
425
-                        $this->_prepare_value_from_db_for_display(
426
-                            EEM_Event::instance(),
427
-                            'EVT_name',
428
-                            $reg_row['Event_CPT.post_title']
429
-                        ),
430
-                        $reg_row['Event_CPT.ID']
431
-                    );
432
-                }
433
-                $is_primary_reg = $reg_row['Registration.REG_count'] == '1' ? true : false;
434
-                /*@var $reg_row EE_Registration */
435
-                foreach ($reg_fields_to_include as $field_name) {
436
-                    $field = $reg_model->field_settings_for($field_name);
437
-                    if ($field_name == 'REG_final_price') {
438
-                        $value = $this->_prepare_value_from_db_for_display(
439
-                            $reg_model,
440
-                            $field_name,
441
-                            $reg_row['Registration.REG_final_price'],
442
-                            'localized_float'
443
-                        );
444
-                    } elseif ($field_name == 'REG_count') {
445
-                        $value = sprintf(
446
-                            esc_html__('%s of %s', 'event_espresso'),
447
-                            $this->_prepare_value_from_db_for_display(
448
-                                $reg_model,
449
-                                'REG_count',
450
-                                $reg_row['Registration.REG_count']
451
-                            ),
452
-                            $this->_prepare_value_from_db_for_display(
453
-                                $reg_model,
454
-                                'REG_group_size',
455
-                                $reg_row['Registration.REG_group_size']
456
-                            )
457
-                        );
458
-                    } elseif ($field_name == 'REG_date') {
459
-                        $value = $this->_prepare_value_from_db_for_display(
460
-                            $reg_model,
461
-                            $field_name,
462
-                            $reg_row['Registration.REG_date'],
463
-                            'no_html'
464
-                        );
465
-                    } else {
466
-                        $value = $this->_prepare_value_from_db_for_display(
467
-                            $reg_model,
468
-                            $field_name,
469
-                            $reg_row[ $field->get_qualified_column() ]
470
-                        );
471
-                    }
472
-                    $reg_csv_array[ $this->_get_column_name_for_field($field) ] = $value;
473
-                    if ($field_name == 'REG_final_price') {
474
-                        // add a column named Currency after the final price
475
-                        $reg_csv_array[ esc_html__("Currency", "event_espresso") ] = EE_Config::instance()->currency->code;
476
-                    }
477
-                }
478
-                // get pretty status
479
-                $stati = EEM_Status::instance()->localized_status(
480
-                    array(
481
-                        $reg_row['Registration.STS_ID']     => esc_html__('unknown', 'event_espresso'),
482
-                        $reg_row['TransactionTable.STS_ID'] => esc_html__('unknown', 'event_espresso'),
483
-                    ),
484
-                    false,
485
-                    'sentence'
486
-                );
487
-                $reg_csv_array[ esc_html__(
488
-                    "Registration Status",
489
-                    'event_espresso'
490
-                ) ] = $stati[ $reg_row['Registration.STS_ID'] ];
491
-                // get pretty trnasaction status
492
-                $reg_csv_array[ esc_html__(
493
-                    "Transaction Status",
494
-                    'event_espresso'
495
-                ) ] = $stati[ $reg_row['TransactionTable.STS_ID'] ];
496
-                $reg_csv_array[ esc_html__('Transaction Amount Due', 'event_espresso') ] = $is_primary_reg
497
-                    ? $this->_prepare_value_from_db_for_display(
498
-                        EEM_Transaction::instance(),
499
-                        'TXN_total',
500
-                        $reg_row['TransactionTable.TXN_total'],
501
-                        'localized_float'
502
-                    ) : '0.00';
503
-                $reg_csv_array[ esc_html__('Amount Paid', 'event_espresso') ] = $is_primary_reg
504
-                    ? $this->_prepare_value_from_db_for_display(
505
-                        EEM_Transaction::instance(),
506
-                        'TXN_paid',
507
-                        $reg_row['TransactionTable.TXN_paid'],
508
-                        'localized_float'
509
-                    ) : '0.00';
510
-                $payment_methods = array();
511
-                $gateway_txn_ids_etc = array();
512
-                $payment_times = array();
513
-                if ($is_primary_reg && $reg_row['TransactionTable.TXN_ID']) {
514
-                    $payments_info = EEM_Payment::instance()->get_all_wpdb_results(
515
-                        array(
516
-                            array(
517
-                                'TXN_ID' => $reg_row['TransactionTable.TXN_ID'],
518
-                                'STS_ID' => EEM_Payment::status_id_approved,
519
-                            ),
520
-                            'force_join' => array('Payment_Method'),
521
-                        ),
522
-                        ARRAY_A,
523
-                        'Payment_Method.PMD_admin_name as name, Payment.PAY_txn_id_chq_nmbr as gateway_txn_id, Payment.PAY_timestamp as payment_time'
524
-                    );
525
-                    list($payment_methods, $gateway_txn_ids_etc, $payment_times) = PaymentsInfoCSV::extractPaymentInfo($payments_info);
526
-                }
527
-                $reg_csv_array[ esc_html__('Payment Date(s)', 'event_espresso') ] = implode(',', $payment_times);
528
-                $reg_csv_array[ esc_html__('Payment Method(s)', 'event_espresso') ] = implode(",", $payment_methods);
529
-                $reg_csv_array[ esc_html__('Gateway Transaction ID(s)', 'event_espresso') ] = implode(
530
-                    ',',
531
-                    $gateway_txn_ids_etc
532
-                );
533
-
534
-                // get whether or not the user has checked in
535
-                $reg_csv_array[ esc_html__("Check-Ins", "event_espresso") ] = $reg_model->count_related(
536
-                    $reg_row['Registration.REG_ID'],
537
-                    'Checkin'
538
-                );
539
-                // get ticket of registration and its price
540
-                $ticket_model = EE_Registry::instance()->load_model('Ticket');
541
-                if ($reg_row['Ticket.TKT_ID']) {
542
-                    $ticket_name = $this->_prepare_value_from_db_for_display(
543
-                        $ticket_model,
544
-                        'TKT_name',
545
-                        $reg_row['Ticket.TKT_name']
546
-                    );
547
-                    $datetimes_strings = array();
548
-                    foreach (
549
-                        EEM_Datetime::instance()->get_all_wpdb_results(
550
-                            array(
551
-                            array('Ticket.TKT_ID' => $reg_row['Ticket.TKT_ID']),
552
-                            'order_by'                 => array('DTT_EVT_start' => 'ASC'),
553
-                            'default_where_conditions' => 'none',
554
-                            )
555
-                        ) as $datetime
556
-                    ) {
557
-                        $datetimes_strings[] = $this->_prepare_value_from_db_for_display(
558
-                            EEM_Datetime::instance(),
559
-                            'DTT_EVT_start',
560
-                            $datetime['Datetime.DTT_EVT_start']
561
-                        );
562
-                    }
563
-                } else {
564
-                    $ticket_name = esc_html__('Unknown', 'event_espresso');
565
-                    $datetimes_strings = array(esc_html__('Unknown', 'event_espresso'));
566
-                }
567
-                $reg_csv_array[ $ticket_model->field_settings_for('TKT_name')->get_nicename() ] = $ticket_name;
568
-                $reg_csv_array[ esc_html__("Datetimes of Ticket", "event_espresso") ] = implode(", ", $datetimes_strings);
569
-                // get datetime(s) of registration
570
-
571
-                // add attendee columns
572
-                foreach ($att_fields_to_include as $att_field_name) {
573
-                    $field_obj = EEM_Attendee::instance()->field_settings_for($att_field_name);
574
-                    if ($reg_row['Attendee_CPT.ID']) {
575
-                        if ($att_field_name == 'STA_ID') {
576
-                            $value = EEM_State::instance()->get_var(
577
-                                array(array('STA_ID' => $reg_row['Attendee_Meta.STA_ID'])),
578
-                                'STA_name'
579
-                            );
580
-                        } elseif ($att_field_name == 'CNT_ISO') {
581
-                            $value = EEM_Country::instance()->get_var(
582
-                                array(array('CNT_ISO' => $reg_row['Attendee_Meta.CNT_ISO'])),
583
-                                'CNT_name'
584
-                            );
585
-                        } else {
586
-                            $value = $this->_prepare_value_from_db_for_display(
587
-                                EEM_Attendee::instance(),
588
-                                $att_field_name,
589
-                                $reg_row[ $field_obj->get_qualified_column() ]
590
-                            );
591
-                        }
592
-                    } else {
593
-                        $value = '';
594
-                    }
595
-
596
-                    $reg_csv_array[ $this->_get_column_name_for_field($field_obj) ] = $value;
597
-                }
598
-
599
-                // make sure each registration has the same questions in the same order
600
-                foreach ($questions_for_these_regs_rows as $question_row) {
601
-                    if (! isset($reg_csv_array[ $question_row['Question.QST_admin_label'] ])) {
602
-                        $reg_csv_array[ $question_row['Question.QST_admin_label'] ] = null;
603
-                    }
604
-                }
605
-                // now fill out the questions THEY answered
606
-                foreach (
607
-                    EEM_Answer::instance()->get_all_wpdb_results(
608
-                        array(array('REG_ID' => $reg_row['Registration.REG_ID']), 'force_join' => array('Question'))
609
-                    ) as $answer_row
610
-                ) {
611
-                    /* @var $answer EE_Answer */
612
-                    if ($answer_row['Question.QST_ID']) {
613
-                        $question_label = $this->_prepare_value_from_db_for_display(
614
-                            EEM_Question::instance(),
615
-                            'QST_admin_label',
616
-                            $answer_row['Question.QST_admin_label']
617
-                        );
618
-                    } else {
619
-                        $question_label = sprintf(esc_html__('Question $s', 'event_espresso'), $answer_row['Answer.QST_ID']);
620
-                    }
621
-                    if (isset($answer_row['Question.QST_type']) && $answer_row['Question.QST_type'] == EEM_Question::QST_type_state) {
622
-                        $reg_csv_array[ $question_label ] = EEM_State::instance()->get_state_name_by_ID(
623
-                            $answer_row['Answer.ANS_value']
624
-                        );
625
-                    } else {
626
-                        $reg_csv_array[ $question_label ] = $this->_prepare_value_from_db_for_display(
627
-                            EEM_Answer::instance(),
628
-                            'ANS_value',
629
-                            $answer_row['Answer.ANS_value']
630
-                        );
631
-                    }
632
-                }
633
-                $registrations_csv_ready_array[] = apply_filters(
634
-                    'FHEE__EventEspressoBatchRequest__JobHandlers__RegistrationsReport__reg_csv_array',
635
-                    $reg_csv_array,
636
-                    $reg_row
637
-                );
638
-            }
639
-        }
640
-
641
-        // if we couldn't export anything, we want to at least show the column headers
642
-        if (empty($registrations_csv_ready_array)) {
643
-            $reg_csv_array = array();
644
-            $model_and_fields_to_include = array(
645
-                'Registration' => $reg_fields_to_include,
646
-                'Attendee'     => $att_fields_to_include,
647
-            );
648
-            foreach ($model_and_fields_to_include as $model_name => $field_list) {
649
-                $model = EE_Registry::instance()->load_model($model_name);
650
-                foreach ($field_list as $field_name) {
651
-                    $field = $model->field_settings_for($field_name);
652
-                    $reg_csv_array[ $this->_get_column_name_for_field(
653
-                        $field
654
-                    ) ] = null;// $registration->get($field->get_name());
655
-                }
656
-            }
657
-            $registrations_csv_ready_array [] = $reg_csv_array;
658
-        }
659
-        if ($event_id) {
660
-            $event_slug = EEM_Event::instance()->get_var(array(array('EVT_ID' => $event_id)), 'EVT_slug');
661
-            if (! $event_slug) {
662
-                $event_slug = esc_html__('unknown', 'event_espresso');
663
-            }
664
-        } else {
665
-            $event_slug = esc_html__('all', 'event_espresso');
666
-        }
667
-        $filename = sprintf("registrations-for-%s", $event_slug);
668
-
669
-        $handle = $this->EE_CSV->begin_sending_csv($filename);
670
-        $this->EE_CSV->write_data_array_to_csv($handle, $registrations_csv_ready_array);
671
-        $this->EE_CSV->end_sending_csv($handle);
672
-    }
673
-
674
-    /**
675
-     * Gets the 'normal' column named for fields
676
-     *
677
-     * @param EE_Model_Field_Base $field
678
-     * @return string
679
-     * @throws EE_Error
680
-     */
681
-    protected function _get_column_name_for_field(EE_Model_Field_Base $field)
682
-    {
683
-        return $field->get_nicename() . "[" . $field->get_name() . "]";
684
-    }
685
-
686
-
687
-    /**
688
-     * @Export data for ALL events
689
-     * @access public
690
-     * @return void
691
-     */
692
-    public function export_categories()
693
-    {
694
-        // are any Event IDs set?
695
-        $query_params = array();
696
-        if (isset($this->_req_data['EVT_CAT_ID'])) {
697
-            // do we have an array of IDs ?
698
-            if (is_array($this->_req_data['EVT_CAT_ID'])) {
699
-                // generate an "IN (CSV)" where clause
700
-                $EVT_CAT_IDs = array_map('sanitize_text_field', $this->_req_data['EVT_CAT_ID']);
701
-                $filename = 'event-categories';
702
-                $query_params[0]['term_taxonomy_id'] = array('IN', $EVT_CAT_IDs);
703
-            } else {
704
-                // generate regular where = clause
705
-                $EVT_CAT_ID = absint($this->_req_data['EVT_CAT_ID']);
706
-                $filename = 'event-category#' . $EVT_CAT_ID;
707
-                $query_params[0]['term_taxonomy_id'] = $EVT_CAT_ID;
708
-            }
709
-        } else {
710
-            // no IDs means we will d/l the entire table
711
-            $filename = 'all-categories';
712
-        }
713
-
714
-        $tables_to_export = array(
715
-            'Term_Taxonomy' => $query_params,
716
-        );
717
-
718
-        $table_data = $this->_get_export_data_for_models($tables_to_export);
719
-        $filename = $this->generate_filename($filename);
720
-
721
-        if (! $this->EE_CSV->export_multiple_model_data_to_csv($filename, $table_data)) {
722
-            EE_Error::add_error(
723
-                esc_html__(
724
-                    'An error occurred and the Category details could not be exported from the database.',
725
-                    'event_espresso'
726
-                ),
727
-                __FILE__,
728
-                __FUNCTION__,
729
-                __LINE__
730
-            );
731
-        }
732
-    }
733
-
734
-
735
-    /**
736
-     * @process export name to create a suitable filename
737
-     * @access  private
738
-     * @param string - export_name
739
-     * @return string on success, FALSE on fail
740
-     */
741
-    private function generate_filename($export_name = '')
742
-    {
743
-        if ($export_name != '') {
744
-            $filename = get_bloginfo('name') . '-' . $export_name;
745
-            $filename = sanitize_key($filename) . '-' . $this->today;
746
-            return $filename;
747
-        } else {
748
-            EE_Error::add_error(esc_html__("No filename was provided", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
749
-        }
750
-        return false;
751
-    }
752
-
753
-
754
-    /**
755
-     * @recursive function for exporting table data and merging the results with the next results
756
-     * @access    private
757
-     * @param array $models_to_export keys are model names (eg 'Event', 'Attendee', etc.) and values are arrays of
758
-     *                                query params @return bool on success, FALSE on fail
759
-     * @throws EE_Error
760
-     * @throws ReflectionException
761
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
762
-     */
763
-    private function _get_export_data_for_models($models_to_export = array())
764
-    {
765
-        $table_data = false;
766
-        if (is_array($models_to_export)) {
767
-            foreach ($models_to_export as $model_name => $query_params) {
768
-                // check for a numerically-indexed array. in that case, $model_name is the value!!
769
-                if (is_int($model_name)) {
770
-                    $model_name = $query_params;
771
-                    $query_params = array();
772
-                }
773
-                $model = EE_Registry::instance()->load_model($model_name);
774
-                $model_objects = $model->get_all($query_params);
775
-
776
-                $table_data[ $model_name ] = array();
777
-                foreach ($model_objects as $model_object) {
778
-                    $model_data_array = array();
779
-                    $fields = $model->field_settings();
780
-                    foreach ($fields as $field) {
781
-                        $column_name = $field->get_nicename() . "[" . $field->get_name() . "]";
782
-                        if ($field instanceof EE_Datetime_Field) {
783
-                            // $field->set_date_format('Y-m-d');
784
-                            // $field->set_time_format('H:i:s');
785
-                            $model_data_array[ $column_name ] = $model_object->get_datetime(
786
-                                $field->get_name(),
787
-                                'Y-m-d',
788
-                                'H:i:s'
789
-                            );
790
-                        } else {
791
-                            $model_data_array[ $column_name ] = $model_object->get($field->get_name());
792
-                        }
793
-                    }
794
-                    $table_data[ $model_name ][] = $model_data_array;
795
-                }
796
-            }
797
-        }
798
-        return $table_data;
799
-    }
20
+	const option_prefix = 'ee_report_job_';
21
+
22
+
23
+	// instance of the EE_Export object
24
+	private static $_instance = null;
25
+
26
+	// instance of the EE_CSV object
27
+	/**
28
+	 *
29
+	 * @var EE_CSV
30
+	 */
31
+	public $EE_CSV = null;
32
+
33
+
34
+	private $_req_data = array();
35
+
36
+
37
+	/**
38
+	 *        private constructor to prevent direct creation
39
+	 *
40
+	 * @Constructor
41
+	 * @access private
42
+	 * @param array $request_data
43
+	 */
44
+	private function __construct($request_data = array())
45
+	{
46
+		$this->_req_data = $request_data;
47
+		$this->today = date("Y-m-d", time());
48
+		require_once(EE_CLASSES . 'EE_CSV.class.php');
49
+		$this->EE_CSV = EE_CSV::instance();
50
+	}
51
+
52
+
53
+	/**
54
+	 *        @ singleton method used to instantiate class object
55
+	 *        @ access public
56
+	 *
57
+	 * @param array $request_data
58
+	 * @return \EE_Export
59
+	 */
60
+	public static function instance($request_data = array())
61
+	{
62
+		// check if class object is instantiated
63
+		if (self::$_instance === null or ! is_object(self::$_instance) or ! (self::$_instance instanceof EE_Export)) {
64
+			self::$_instance = new self($request_data);
65
+		}
66
+		return self::$_instance;
67
+	}
68
+
69
+
70
+	/**
71
+	 * @Export Event Espresso data - routes export requests
72
+	 * @access public
73
+	 * @return void | bool
74
+	 */
75
+	public function export()
76
+	{
77
+		// in case of bulk exports, the "actual" action will be in action2, but first check regular action for "export" keyword
78
+		if (isset($this->_req_data['action']) && strpos($this->_req_data['action'], 'export') === false) {
79
+			// check if action2 has export action
80
+			if (isset($this->_req_data['action2']) && strpos($this->_req_data['action2'], 'export') !== false) {
81
+				// whoop! there it is!
82
+				$this->_req_data['action'] = $this->_req_data['action2'];
83
+			}
84
+		}
85
+
86
+		$this->_req_data['export'] = isset($this->_req_data['export']) ? $this->_req_data['export'] : '';
87
+
88
+		switch ($this->_req_data['export']) {
89
+			case 'report':
90
+				switch ($this->_req_data['action']) {
91
+					case "event":
92
+					case "export_events":
93
+					case 'all_event_data':
94
+						$this->export_all_event_data();
95
+						break;
96
+
97
+					case 'registrations_report_for_event':
98
+						$this->report_registrations_for_event($this->_req_data['EVT_ID']);
99
+						break;
100
+
101
+					case 'attendees':
102
+						$this->export_attendees();
103
+						break;
104
+
105
+					case 'categories':
106
+						$this->export_categories();
107
+						break;
108
+
109
+					default:
110
+						EE_Error::add_error(
111
+							esc_html__('An error occurred! The requested export report could not be found.', 'event_espresso'),
112
+							__FILE__,
113
+							__FUNCTION__,
114
+							__LINE__
115
+						);
116
+						return false;
117
+						break;
118
+				}
119
+				break; // end of switch export : report
120
+			default:
121
+				break;
122
+		} // end of switch export
123
+
124
+		exit;
125
+	}
126
+
127
+	/**
128
+	 * Downloads a CSV file with all the columns, but no data. This should be used for importing
129
+	 *
130
+	 * @return void kills execution
131
+	 * @throws EE_Error
132
+	 * @throws ReflectionException
133
+	 */
134
+	public function export_sample()
135
+	{
136
+		$event = EEM_Event::instance()->get_one();
137
+		$this->_req_data['EVT_ID'] = $event->ID();
138
+		$this->export_all_event_data();
139
+	}
140
+
141
+
142
+	/**
143
+	 * @Export data for ALL events
144
+	 * @access public
145
+	 * @return void
146
+	 * @throws EE_Error
147
+	 * @throws ReflectionException
148
+	 */
149
+	public function export_all_event_data()
150
+	{
151
+		// are any Event IDs set?
152
+		$event_query_params = array();
153
+		$related_models_query_params = array();
154
+		$related_through_reg_query_params = array();
155
+		$datetime_ticket_query_params = array();
156
+		$price_query_params = array();
157
+		$price_type_query_params = array();
158
+		$term_query_params = array();
159
+		$state_country_query_params = array();
160
+		$question_group_query_params = array();
161
+		$question_query_params = array();
162
+		if (isset($this->_req_data['EVT_ID'])) {
163
+			// do we have an array of IDs ?
164
+
165
+			if (is_array($this->_req_data['EVT_ID'])) {
166
+				$EVT_IDs = array_map('sanitize_text_field', $this->_req_data['EVT_ID']);
167
+				$value_to_equal = array('IN', $EVT_IDs);
168
+				$filename = 'events';
169
+			} else {
170
+				// generate regular where = clause
171
+				$EVT_ID = absint($this->_req_data['EVT_ID']);
172
+				$value_to_equal = $EVT_ID;
173
+				$event = EE_Registry::instance()->load_model('Event')->get_one_by_ID($EVT_ID);
174
+
175
+				$filename = 'event-' . ($event instanceof EE_Event ? $event->slug() : esc_html__('unknown', 'event_espresso'));
176
+			}
177
+			$event_query_params[0]['EVT_ID'] = $value_to_equal;
178
+			$related_models_query_params[0]['Event.EVT_ID'] = $value_to_equal;
179
+			$related_through_reg_query_params[0]['Registration.EVT_ID'] = $value_to_equal;
180
+			$datetime_ticket_query_params[0]['Datetime.EVT_ID'] = $value_to_equal;
181
+			$price_query_params[0]['Ticket.Datetime.EVT_ID'] = $value_to_equal;
182
+			$price_type_query_params[0]['Price.Ticket.Datetime.EVT_ID'] = $value_to_equal;
183
+			$term_query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $value_to_equal;
184
+			$state_country_query_params[0]['Venue.Event.EVT_ID'] = $value_to_equal;
185
+			$question_group_query_params[0]['Event.EVT_ID'] = $value_to_equal;
186
+			$question_query_params[0]['Question_Group.Event.EVT_ID'] = $value_to_equal;
187
+		} else {
188
+			$filename = 'all-events';
189
+		}
190
+
191
+
192
+		// array in the format:  table name =>  query where clause
193
+		$models_to_export = array(
194
+			'Event'                   => $event_query_params,
195
+			'Datetime'                => $related_models_query_params,
196
+			'Ticket_Template'         => $price_query_params,
197
+			'Ticket'                  => $datetime_ticket_query_params,
198
+			'Datetime_Ticket'         => $datetime_ticket_query_params,
199
+			'Price_Type'              => $price_type_query_params,
200
+			'Price'                   => $price_query_params,
201
+			'Ticket_Price'            => $price_query_params,
202
+			'Term'                    => $term_query_params,
203
+			'Term_Taxonomy'           => $related_models_query_params,
204
+			'Term_Relationship'       => $related_models_query_params, // model has NO primary key...
205
+			'Country'                 => $state_country_query_params,
206
+			'State'                   => $state_country_query_params,
207
+			'Venue'                   => $related_models_query_params,
208
+			'Event_Venue'             => $related_models_query_params,
209
+			'Question_Group'          => $question_group_query_params,
210
+			'Event_Question_Group'    => $question_group_query_params,
211
+			'Question'                => $question_query_params,
212
+			'Question_Group_Question' => $question_query_params,
213
+			// 'Transaction'=>$related_through_reg_query_params,
214
+			// 'Registration'=>$related_models_query_params,
215
+			// 'Attendee'=>$related_through_reg_query_params,
216
+			// 'Line_Item'=>
217
+
218
+		);
219
+
220
+		$model_data = $this->_get_export_data_for_models($models_to_export);
221
+
222
+		$filename = $this->generate_filename($filename);
223
+
224
+		if (! $this->EE_CSV->export_multiple_model_data_to_csv($filename, $model_data)) {
225
+			EE_Error::add_error(
226
+				esc_html__(
227
+					"'An error occurred and the Event details could not be exported from the database.'",
228
+					"event_espresso"
229
+				),
230
+				__FILE__,
231
+				__FUNCTION__,
232
+				__LINE__
233
+			);
234
+		}
235
+	}
236
+
237
+	public function report_attendees()
238
+	{
239
+		$attendee_rows = EEM_Attendee::instance()->get_all_wpdb_results(
240
+			array(
241
+				'force_join' => array('State', 'Country'),
242
+				'caps'       => EEM_Base::caps_read_admin,
243
+			)
244
+		);
245
+		$csv_data = array();
246
+		foreach ($attendee_rows as $attendee_row) {
247
+			$csv_row = array();
248
+			foreach (EEM_Attendee::instance()->field_settings() as $field_name => $field_obj) {
249
+				if ($field_name == 'STA_ID') {
250
+					$state_name_field = EEM_State::instance()->field_settings_for('STA_name');
251
+					$csv_row[ esc_html__('State', 'event_espresso') ] = $attendee_row[ $state_name_field->get_qualified_column(
252
+					) ];
253
+				} elseif ($field_name == 'CNT_ISO') {
254
+					$country_name_field = EEM_Country::instance()->field_settings_for('CNT_name');
255
+					$csv_row[ esc_html__(
256
+						'Country',
257
+						'event_espresso'
258
+					) ] = $attendee_row[ $country_name_field->get_qualified_column() ];
259
+				} else {
260
+					$csv_row[ $field_obj->get_nicename() ] = $attendee_row[ $field_obj->get_qualified_column() ];
261
+				}
262
+			}
263
+			$csv_data[] = $csv_row;
264
+		}
265
+
266
+		$filename = $this->generate_filename('contact-list-report');
267
+
268
+		$handle = $this->EE_CSV->begin_sending_csv($filename);
269
+		$this->EE_CSV->write_data_array_to_csv($handle, $csv_data);
270
+		$this->EE_CSV->end_sending_csv($handle);
271
+	}
272
+
273
+
274
+	/**
275
+	 * @Export data for ALL attendees
276
+	 * @access public
277
+	 * @return void
278
+	 * @throws EE_Error
279
+	 */
280
+	public function export_attendees()
281
+	{
282
+
283
+		$states_that_have_an_attendee = EEM_State::instance()->get_all(
284
+			array(0 => array('Attendee.ATT_ID' => array('IS NOT NULL')))
285
+		);
286
+		$countries_that_have_an_attendee = EEM_Country::instance()->get_all(
287
+			array(0 => array('Attendee.ATT_ID' => array('IS NOT NULL')))
288
+		);
289
+		// $states_to_export_query_params
290
+		$models_to_export = array(
291
+			'Country'  => array(array('CNT_ISO' => array('IN', array_keys($countries_that_have_an_attendee)))),
292
+			'State'    => array(array('STA_ID' => array('IN', array_keys($states_that_have_an_attendee)))),
293
+			'Attendee' => array(),
294
+		);
295
+
296
+
297
+		$model_data = $this->_get_export_data_for_models($models_to_export);
298
+		$filename = $this->generate_filename('all-attendees');
299
+
300
+		if (! $this->EE_CSV->export_multiple_model_data_to_csv($filename, $model_data)) {
301
+			EE_Error::add_error(
302
+				esc_html__(
303
+					'An error occurred and the Attendee data could not be exported from the database.',
304
+					'event_espresso'
305
+				),
306
+				__FILE__,
307
+				__FUNCTION__,
308
+				__LINE__
309
+			);
310
+		}
311
+	}
312
+
313
+	/**
314
+	 * Shortcut for preparing a database result for display
315
+	 *
316
+	 * @param EEM_Base $model
317
+	 * @param string $field_name
318
+	 * @param string $raw_db_value
319
+	 * @param bool|string $pretty_schema true to display pretty, a string to use a specific "Schema", or false to
320
+	 *                                      NOT display pretty
321
+	 * @return string
322
+	 * @throws EE_Error
323
+	 */
324
+	protected function _prepare_value_from_db_for_display($model, $field_name, $raw_db_value, $pretty_schema = true)
325
+	{
326
+		$field_obj = $model->field_settings_for($field_name);
327
+		$value_on_model_obj = $field_obj->prepare_for_set_from_db($raw_db_value);
328
+		if ($field_obj instanceof EE_Datetime_Field) {
329
+			$field_obj->set_date_format(
330
+				EE_CSV::instance()->get_date_format_for_csv($field_obj->get_date_format($pretty_schema)),
331
+				$pretty_schema
332
+			);
333
+			$field_obj->set_time_format(
334
+				EE_CSV::instance()->get_time_format_for_csv($field_obj->get_time_format($pretty_schema)),
335
+				$pretty_schema
336
+			);
337
+		}
338
+		if ($pretty_schema === true) {
339
+			return $field_obj->prepare_for_pretty_echoing($value_on_model_obj);
340
+		} elseif (is_string($pretty_schema)) {
341
+			return $field_obj->prepare_for_pretty_echoing($value_on_model_obj, $pretty_schema);
342
+		} else {
343
+			return $field_obj->prepare_for_get($value_on_model_obj);
344
+		}
345
+	}
346
+
347
+	/**
348
+	 * Export a custom CSV of registration info including: A bunch of the reg fields, the time of the event, the price
349
+	 * name, and the questions associated with the registrations
350
+	 *
351
+	 * @param int $event_id
352
+	 * @throws EE_Error
353
+	 * @throws ReflectionException
354
+	 */
355
+	public function report_registrations_for_event($event_id = null)
356
+	{
357
+		$reg_fields_to_include = array(
358
+			'TXN_ID',
359
+			'ATT_ID',
360
+			'REG_ID',
361
+			'REG_date',
362
+			'REG_code',
363
+			'REG_count',
364
+			'REG_final_price',
365
+
366
+		);
367
+		$att_fields_to_include = array(
368
+			'ATT_fname',
369
+			'ATT_lname',
370
+			'ATT_email',
371
+			'ATT_address',
372
+			'ATT_address2',
373
+			'ATT_city',
374
+			'STA_ID',
375
+			'CNT_ISO',
376
+			'ATT_zip',
377
+			'ATT_phone',
378
+		);
379
+
380
+		$registrations_csv_ready_array = array();
381
+		$reg_model = EE_Registry::instance()->load_model('Registration');
382
+		$query_params = apply_filters(
383
+			'FHEE__EE_Export__report_registration_for_event',
384
+			array(
385
+				array(
386
+					'OR'                 => array(
387
+						// don't include registrations from failed or abandoned transactions...
388
+						'Transaction.STS_ID' => array(
389
+							'NOT IN',
390
+							array(EEM_Transaction::failed_status_code, EEM_Transaction::abandoned_status_code),
391
+						),
392
+						// unless the registration is approved, in which case include it regardless of transaction status
393
+						'STS_ID'             => EEM_Registration::status_id_approved,
394
+					),
395
+					'Ticket.TKT_deleted' => array('IN', array(true, false)),
396
+				),
397
+				'order_by'   => array('Transaction.TXN_ID' => 'asc', 'REG_count' => 'asc'),
398
+				'force_join' => array('Transaction', 'Ticket', 'Attendee'),
399
+				'caps'       => EEM_Base::caps_read_admin,
400
+			),
401
+			$event_id
402
+		);
403
+		if ($event_id) {
404
+			$query_params[0]['EVT_ID'] = $event_id;
405
+		} else {
406
+			$query_params['force_join'][] = 'Event';
407
+		}
408
+		$registration_rows = $reg_model->get_all_wpdb_results($query_params);
409
+		// get all questions which relate to someone in this group
410
+		$registration_ids = array();
411
+		foreach ($registration_rows as $reg_row) {
412
+			$registration_ids[] = intval($reg_row['Registration.REG_ID']);
413
+		}
414
+		// EEM_Question::instance()->show_next_x_db_queries();
415
+		$questions_for_these_regs_rows = EEM_Question::instance()->get_all_wpdb_results(
416
+			array(array('Answer.REG_ID' => array('IN', $registration_ids)))
417
+		);
418
+		foreach ($registration_rows as $reg_row) {
419
+			if (is_array($reg_row)) {
420
+				$reg_csv_array = array();
421
+				if (! $event_id) {
422
+					// get the event's name and Id
423
+					$reg_csv_array[ esc_html__('Event', 'event_espresso') ] = sprintf(
424
+						esc_html__('%1$s (%2$s)', 'event_espresso'),
425
+						$this->_prepare_value_from_db_for_display(
426
+							EEM_Event::instance(),
427
+							'EVT_name',
428
+							$reg_row['Event_CPT.post_title']
429
+						),
430
+						$reg_row['Event_CPT.ID']
431
+					);
432
+				}
433
+				$is_primary_reg = $reg_row['Registration.REG_count'] == '1' ? true : false;
434
+				/*@var $reg_row EE_Registration */
435
+				foreach ($reg_fields_to_include as $field_name) {
436
+					$field = $reg_model->field_settings_for($field_name);
437
+					if ($field_name == 'REG_final_price') {
438
+						$value = $this->_prepare_value_from_db_for_display(
439
+							$reg_model,
440
+							$field_name,
441
+							$reg_row['Registration.REG_final_price'],
442
+							'localized_float'
443
+						);
444
+					} elseif ($field_name == 'REG_count') {
445
+						$value = sprintf(
446
+							esc_html__('%s of %s', 'event_espresso'),
447
+							$this->_prepare_value_from_db_for_display(
448
+								$reg_model,
449
+								'REG_count',
450
+								$reg_row['Registration.REG_count']
451
+							),
452
+							$this->_prepare_value_from_db_for_display(
453
+								$reg_model,
454
+								'REG_group_size',
455
+								$reg_row['Registration.REG_group_size']
456
+							)
457
+						);
458
+					} elseif ($field_name == 'REG_date') {
459
+						$value = $this->_prepare_value_from_db_for_display(
460
+							$reg_model,
461
+							$field_name,
462
+							$reg_row['Registration.REG_date'],
463
+							'no_html'
464
+						);
465
+					} else {
466
+						$value = $this->_prepare_value_from_db_for_display(
467
+							$reg_model,
468
+							$field_name,
469
+							$reg_row[ $field->get_qualified_column() ]
470
+						);
471
+					}
472
+					$reg_csv_array[ $this->_get_column_name_for_field($field) ] = $value;
473
+					if ($field_name == 'REG_final_price') {
474
+						// add a column named Currency after the final price
475
+						$reg_csv_array[ esc_html__("Currency", "event_espresso") ] = EE_Config::instance()->currency->code;
476
+					}
477
+				}
478
+				// get pretty status
479
+				$stati = EEM_Status::instance()->localized_status(
480
+					array(
481
+						$reg_row['Registration.STS_ID']     => esc_html__('unknown', 'event_espresso'),
482
+						$reg_row['TransactionTable.STS_ID'] => esc_html__('unknown', 'event_espresso'),
483
+					),
484
+					false,
485
+					'sentence'
486
+				);
487
+				$reg_csv_array[ esc_html__(
488
+					"Registration Status",
489
+					'event_espresso'
490
+				) ] = $stati[ $reg_row['Registration.STS_ID'] ];
491
+				// get pretty trnasaction status
492
+				$reg_csv_array[ esc_html__(
493
+					"Transaction Status",
494
+					'event_espresso'
495
+				) ] = $stati[ $reg_row['TransactionTable.STS_ID'] ];
496
+				$reg_csv_array[ esc_html__('Transaction Amount Due', 'event_espresso') ] = $is_primary_reg
497
+					? $this->_prepare_value_from_db_for_display(
498
+						EEM_Transaction::instance(),
499
+						'TXN_total',
500
+						$reg_row['TransactionTable.TXN_total'],
501
+						'localized_float'
502
+					) : '0.00';
503
+				$reg_csv_array[ esc_html__('Amount Paid', 'event_espresso') ] = $is_primary_reg
504
+					? $this->_prepare_value_from_db_for_display(
505
+						EEM_Transaction::instance(),
506
+						'TXN_paid',
507
+						$reg_row['TransactionTable.TXN_paid'],
508
+						'localized_float'
509
+					) : '0.00';
510
+				$payment_methods = array();
511
+				$gateway_txn_ids_etc = array();
512
+				$payment_times = array();
513
+				if ($is_primary_reg && $reg_row['TransactionTable.TXN_ID']) {
514
+					$payments_info = EEM_Payment::instance()->get_all_wpdb_results(
515
+						array(
516
+							array(
517
+								'TXN_ID' => $reg_row['TransactionTable.TXN_ID'],
518
+								'STS_ID' => EEM_Payment::status_id_approved,
519
+							),
520
+							'force_join' => array('Payment_Method'),
521
+						),
522
+						ARRAY_A,
523
+						'Payment_Method.PMD_admin_name as name, Payment.PAY_txn_id_chq_nmbr as gateway_txn_id, Payment.PAY_timestamp as payment_time'
524
+					);
525
+					list($payment_methods, $gateway_txn_ids_etc, $payment_times) = PaymentsInfoCSV::extractPaymentInfo($payments_info);
526
+				}
527
+				$reg_csv_array[ esc_html__('Payment Date(s)', 'event_espresso') ] = implode(',', $payment_times);
528
+				$reg_csv_array[ esc_html__('Payment Method(s)', 'event_espresso') ] = implode(",", $payment_methods);
529
+				$reg_csv_array[ esc_html__('Gateway Transaction ID(s)', 'event_espresso') ] = implode(
530
+					',',
531
+					$gateway_txn_ids_etc
532
+				);
533
+
534
+				// get whether or not the user has checked in
535
+				$reg_csv_array[ esc_html__("Check-Ins", "event_espresso") ] = $reg_model->count_related(
536
+					$reg_row['Registration.REG_ID'],
537
+					'Checkin'
538
+				);
539
+				// get ticket of registration and its price
540
+				$ticket_model = EE_Registry::instance()->load_model('Ticket');
541
+				if ($reg_row['Ticket.TKT_ID']) {
542
+					$ticket_name = $this->_prepare_value_from_db_for_display(
543
+						$ticket_model,
544
+						'TKT_name',
545
+						$reg_row['Ticket.TKT_name']
546
+					);
547
+					$datetimes_strings = array();
548
+					foreach (
549
+						EEM_Datetime::instance()->get_all_wpdb_results(
550
+							array(
551
+							array('Ticket.TKT_ID' => $reg_row['Ticket.TKT_ID']),
552
+							'order_by'                 => array('DTT_EVT_start' => 'ASC'),
553
+							'default_where_conditions' => 'none',
554
+							)
555
+						) as $datetime
556
+					) {
557
+						$datetimes_strings[] = $this->_prepare_value_from_db_for_display(
558
+							EEM_Datetime::instance(),
559
+							'DTT_EVT_start',
560
+							$datetime['Datetime.DTT_EVT_start']
561
+						);
562
+					}
563
+				} else {
564
+					$ticket_name = esc_html__('Unknown', 'event_espresso');
565
+					$datetimes_strings = array(esc_html__('Unknown', 'event_espresso'));
566
+				}
567
+				$reg_csv_array[ $ticket_model->field_settings_for('TKT_name')->get_nicename() ] = $ticket_name;
568
+				$reg_csv_array[ esc_html__("Datetimes of Ticket", "event_espresso") ] = implode(", ", $datetimes_strings);
569
+				// get datetime(s) of registration
570
+
571
+				// add attendee columns
572
+				foreach ($att_fields_to_include as $att_field_name) {
573
+					$field_obj = EEM_Attendee::instance()->field_settings_for($att_field_name);
574
+					if ($reg_row['Attendee_CPT.ID']) {
575
+						if ($att_field_name == 'STA_ID') {
576
+							$value = EEM_State::instance()->get_var(
577
+								array(array('STA_ID' => $reg_row['Attendee_Meta.STA_ID'])),
578
+								'STA_name'
579
+							);
580
+						} elseif ($att_field_name == 'CNT_ISO') {
581
+							$value = EEM_Country::instance()->get_var(
582
+								array(array('CNT_ISO' => $reg_row['Attendee_Meta.CNT_ISO'])),
583
+								'CNT_name'
584
+							);
585
+						} else {
586
+							$value = $this->_prepare_value_from_db_for_display(
587
+								EEM_Attendee::instance(),
588
+								$att_field_name,
589
+								$reg_row[ $field_obj->get_qualified_column() ]
590
+							);
591
+						}
592
+					} else {
593
+						$value = '';
594
+					}
595
+
596
+					$reg_csv_array[ $this->_get_column_name_for_field($field_obj) ] = $value;
597
+				}
598
+
599
+				// make sure each registration has the same questions in the same order
600
+				foreach ($questions_for_these_regs_rows as $question_row) {
601
+					if (! isset($reg_csv_array[ $question_row['Question.QST_admin_label'] ])) {
602
+						$reg_csv_array[ $question_row['Question.QST_admin_label'] ] = null;
603
+					}
604
+				}
605
+				// now fill out the questions THEY answered
606
+				foreach (
607
+					EEM_Answer::instance()->get_all_wpdb_results(
608
+						array(array('REG_ID' => $reg_row['Registration.REG_ID']), 'force_join' => array('Question'))
609
+					) as $answer_row
610
+				) {
611
+					/* @var $answer EE_Answer */
612
+					if ($answer_row['Question.QST_ID']) {
613
+						$question_label = $this->_prepare_value_from_db_for_display(
614
+							EEM_Question::instance(),
615
+							'QST_admin_label',
616
+							$answer_row['Question.QST_admin_label']
617
+						);
618
+					} else {
619
+						$question_label = sprintf(esc_html__('Question $s', 'event_espresso'), $answer_row['Answer.QST_ID']);
620
+					}
621
+					if (isset($answer_row['Question.QST_type']) && $answer_row['Question.QST_type'] == EEM_Question::QST_type_state) {
622
+						$reg_csv_array[ $question_label ] = EEM_State::instance()->get_state_name_by_ID(
623
+							$answer_row['Answer.ANS_value']
624
+						);
625
+					} else {
626
+						$reg_csv_array[ $question_label ] = $this->_prepare_value_from_db_for_display(
627
+							EEM_Answer::instance(),
628
+							'ANS_value',
629
+							$answer_row['Answer.ANS_value']
630
+						);
631
+					}
632
+				}
633
+				$registrations_csv_ready_array[] = apply_filters(
634
+					'FHEE__EventEspressoBatchRequest__JobHandlers__RegistrationsReport__reg_csv_array',
635
+					$reg_csv_array,
636
+					$reg_row
637
+				);
638
+			}
639
+		}
640
+
641
+		// if we couldn't export anything, we want to at least show the column headers
642
+		if (empty($registrations_csv_ready_array)) {
643
+			$reg_csv_array = array();
644
+			$model_and_fields_to_include = array(
645
+				'Registration' => $reg_fields_to_include,
646
+				'Attendee'     => $att_fields_to_include,
647
+			);
648
+			foreach ($model_and_fields_to_include as $model_name => $field_list) {
649
+				$model = EE_Registry::instance()->load_model($model_name);
650
+				foreach ($field_list as $field_name) {
651
+					$field = $model->field_settings_for($field_name);
652
+					$reg_csv_array[ $this->_get_column_name_for_field(
653
+						$field
654
+					) ] = null;// $registration->get($field->get_name());
655
+				}
656
+			}
657
+			$registrations_csv_ready_array [] = $reg_csv_array;
658
+		}
659
+		if ($event_id) {
660
+			$event_slug = EEM_Event::instance()->get_var(array(array('EVT_ID' => $event_id)), 'EVT_slug');
661
+			if (! $event_slug) {
662
+				$event_slug = esc_html__('unknown', 'event_espresso');
663
+			}
664
+		} else {
665
+			$event_slug = esc_html__('all', 'event_espresso');
666
+		}
667
+		$filename = sprintf("registrations-for-%s", $event_slug);
668
+
669
+		$handle = $this->EE_CSV->begin_sending_csv($filename);
670
+		$this->EE_CSV->write_data_array_to_csv($handle, $registrations_csv_ready_array);
671
+		$this->EE_CSV->end_sending_csv($handle);
672
+	}
673
+
674
+	/**
675
+	 * Gets the 'normal' column named for fields
676
+	 *
677
+	 * @param EE_Model_Field_Base $field
678
+	 * @return string
679
+	 * @throws EE_Error
680
+	 */
681
+	protected function _get_column_name_for_field(EE_Model_Field_Base $field)
682
+	{
683
+		return $field->get_nicename() . "[" . $field->get_name() . "]";
684
+	}
685
+
686
+
687
+	/**
688
+	 * @Export data for ALL events
689
+	 * @access public
690
+	 * @return void
691
+	 */
692
+	public function export_categories()
693
+	{
694
+		// are any Event IDs set?
695
+		$query_params = array();
696
+		if (isset($this->_req_data['EVT_CAT_ID'])) {
697
+			// do we have an array of IDs ?
698
+			if (is_array($this->_req_data['EVT_CAT_ID'])) {
699
+				// generate an "IN (CSV)" where clause
700
+				$EVT_CAT_IDs = array_map('sanitize_text_field', $this->_req_data['EVT_CAT_ID']);
701
+				$filename = 'event-categories';
702
+				$query_params[0]['term_taxonomy_id'] = array('IN', $EVT_CAT_IDs);
703
+			} else {
704
+				// generate regular where = clause
705
+				$EVT_CAT_ID = absint($this->_req_data['EVT_CAT_ID']);
706
+				$filename = 'event-category#' . $EVT_CAT_ID;
707
+				$query_params[0]['term_taxonomy_id'] = $EVT_CAT_ID;
708
+			}
709
+		} else {
710
+			// no IDs means we will d/l the entire table
711
+			$filename = 'all-categories';
712
+		}
713
+
714
+		$tables_to_export = array(
715
+			'Term_Taxonomy' => $query_params,
716
+		);
717
+
718
+		$table_data = $this->_get_export_data_for_models($tables_to_export);
719
+		$filename = $this->generate_filename($filename);
720
+
721
+		if (! $this->EE_CSV->export_multiple_model_data_to_csv($filename, $table_data)) {
722
+			EE_Error::add_error(
723
+				esc_html__(
724
+					'An error occurred and the Category details could not be exported from the database.',
725
+					'event_espresso'
726
+				),
727
+				__FILE__,
728
+				__FUNCTION__,
729
+				__LINE__
730
+			);
731
+		}
732
+	}
733
+
734
+
735
+	/**
736
+	 * @process export name to create a suitable filename
737
+	 * @access  private
738
+	 * @param string - export_name
739
+	 * @return string on success, FALSE on fail
740
+	 */
741
+	private function generate_filename($export_name = '')
742
+	{
743
+		if ($export_name != '') {
744
+			$filename = get_bloginfo('name') . '-' . $export_name;
745
+			$filename = sanitize_key($filename) . '-' . $this->today;
746
+			return $filename;
747
+		} else {
748
+			EE_Error::add_error(esc_html__("No filename was provided", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
749
+		}
750
+		return false;
751
+	}
752
+
753
+
754
+	/**
755
+	 * @recursive function for exporting table data and merging the results with the next results
756
+	 * @access    private
757
+	 * @param array $models_to_export keys are model names (eg 'Event', 'Attendee', etc.) and values are arrays of
758
+	 *                                query params @return bool on success, FALSE on fail
759
+	 * @throws EE_Error
760
+	 * @throws ReflectionException
761
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
762
+	 */
763
+	private function _get_export_data_for_models($models_to_export = array())
764
+	{
765
+		$table_data = false;
766
+		if (is_array($models_to_export)) {
767
+			foreach ($models_to_export as $model_name => $query_params) {
768
+				// check for a numerically-indexed array. in that case, $model_name is the value!!
769
+				if (is_int($model_name)) {
770
+					$model_name = $query_params;
771
+					$query_params = array();
772
+				}
773
+				$model = EE_Registry::instance()->load_model($model_name);
774
+				$model_objects = $model->get_all($query_params);
775
+
776
+				$table_data[ $model_name ] = array();
777
+				foreach ($model_objects as $model_object) {
778
+					$model_data_array = array();
779
+					$fields = $model->field_settings();
780
+					foreach ($fields as $field) {
781
+						$column_name = $field->get_nicename() . "[" . $field->get_name() . "]";
782
+						if ($field instanceof EE_Datetime_Field) {
783
+							// $field->set_date_format('Y-m-d');
784
+							// $field->set_time_format('H:i:s');
785
+							$model_data_array[ $column_name ] = $model_object->get_datetime(
786
+								$field->get_name(),
787
+								'Y-m-d',
788
+								'H:i:s'
789
+							);
790
+						} else {
791
+							$model_data_array[ $column_name ] = $model_object->get($field->get_name());
792
+						}
793
+					}
794
+					$table_data[ $model_name ][] = $model_data_array;
795
+				}
796
+			}
797
+		}
798
+		return $table_data;
799
+	}
800 800
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Event.class.php 1 patch
Indentation   +1634 added lines, -1634 removed lines patch added patch discarded remove patch
@@ -16,1641 +16,1641 @@
 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
-     * @deprecated
528
-     */
529
-    public function visible_on(): string
530
-    {
531
-        EE_Error::doing_it_wrong(
532
-            __METHOD__,
533
-            esc_html__(
534
-                'This method has been deprecated and there is no replacement for it.',
535
-                'event_espresso'
536
-            ),
537
-            '5.0.0.rc.002'
538
-        );
539
-        return $this->get('EVT_visible_on');
540
-    }
541
-
542
-
543
-    /**
544
-     * @return int
545
-     * @throws EE_Error
546
-     * @throws ReflectionException
547
-     */
548
-    public function wp_user(): int
549
-    {
550
-        return $this->get('EVT_wp_user');
551
-    }
552
-
553
-
554
-    /**
555
-     * @return bool
556
-     * @throws EE_Error
557
-     * @throws ReflectionException
558
-     */
559
-    public function donations(): bool
560
-    {
561
-        return $this->get('EVT_donations');
562
-    }
563
-
564
-
565
-    /**
566
-     * @param int $limit
567
-     * @throws EE_Error
568
-     * @throws ReflectionException
569
-     */
570
-    public function set_additional_limit(int $limit)
571
-    {
572
-        $this->set('EVT_additional_limit', $limit);
573
-    }
574
-
575
-
576
-    /**
577
-     * @param $created
578
-     * @throws EE_Error
579
-     * @throws ReflectionException
580
-     */
581
-    public function set_created($created)
582
-    {
583
-        $this->set('EVT_created', $created);
584
-    }
585
-
586
-
587
-    /**
588
-     * @param $desc
589
-     * @throws EE_Error
590
-     * @throws ReflectionException
591
-     */
592
-    public function set_description($desc)
593
-    {
594
-        $this->set('EVT_desc', $desc);
595
-    }
596
-
597
-
598
-    /**
599
-     * @param $display_desc
600
-     * @throws EE_Error
601
-     * @throws ReflectionException
602
-     */
603
-    public function set_display_description($display_desc)
604
-    {
605
-        $this->set('EVT_display_desc', $display_desc);
606
-    }
607
-
608
-
609
-    /**
610
-     * @param $display_ticket_selector
611
-     * @throws EE_Error
612
-     * @throws ReflectionException
613
-     */
614
-    public function set_display_ticket_selector($display_ticket_selector)
615
-    {
616
-        $this->set('EVT_display_ticket_selector', $display_ticket_selector);
617
-    }
618
-
619
-
620
-    /**
621
-     * @param $external_url
622
-     * @throws EE_Error
623
-     * @throws ReflectionException
624
-     */
625
-    public function set_external_url($external_url)
626
-    {
627
-        $this->set('EVT_external_URL', $external_url);
628
-    }
629
-
630
-
631
-    /**
632
-     * @param $member_only
633
-     * @throws EE_Error
634
-     * @throws ReflectionException
635
-     */
636
-    public function set_member_only($member_only)
637
-    {
638
-        $this->set('EVT_member_only', $member_only);
639
-    }
640
-
641
-
642
-    /**
643
-     * @param $event_phone
644
-     * @throws EE_Error
645
-     * @throws ReflectionException
646
-     */
647
-    public function set_event_phone($event_phone)
648
-    {
649
-        $this->set('EVT_phone', $event_phone);
650
-    }
651
-
652
-
653
-    /**
654
-     * @param $modified
655
-     * @throws EE_Error
656
-     * @throws ReflectionException
657
-     */
658
-    public function set_modified($modified)
659
-    {
660
-        $this->set('EVT_modified', $modified);
661
-    }
662
-
663
-
664
-    /**
665
-     * @param $name
666
-     * @throws EE_Error
667
-     * @throws ReflectionException
668
-     */
669
-    public function set_name($name)
670
-    {
671
-        $this->set('EVT_name', $name);
672
-    }
673
-
674
-
675
-    /**
676
-     * @param $order
677
-     * @throws EE_Error
678
-     * @throws ReflectionException
679
-     */
680
-    public function set_order($order)
681
-    {
682
-        $this->set('EVT_order', $order);
683
-    }
684
-
685
-
686
-    /**
687
-     * @param $short_desc
688
-     * @throws EE_Error
689
-     * @throws ReflectionException
690
-     */
691
-    public function set_short_description($short_desc)
692
-    {
693
-        $this->set('EVT_short_desc', $short_desc);
694
-    }
695
-
696
-
697
-    /**
698
-     * @param $slug
699
-     * @throws EE_Error
700
-     * @throws ReflectionException
701
-     */
702
-    public function set_slug($slug)
703
-    {
704
-        $this->set('EVT_slug', $slug);
705
-    }
706
-
707
-
708
-    /**
709
-     * @param $timezone_string
710
-     * @throws EE_Error
711
-     * @throws ReflectionException
712
-     */
713
-    public function set_timezone_string($timezone_string)
714
-    {
715
-        $this->set('EVT_timezone_string', $timezone_string);
716
-    }
717
-
718
-
719
-    /**
720
-     * @param $visible_on
721
-     * @throws EE_Error
722
-     * @throws ReflectionException
723
-     * @deprecated
724
-     */
725
-    public function set_visible_on($visible_on)
726
-    {
727
-        EE_Error::doing_it_wrong(
728
-            __METHOD__,
729
-            esc_html__(
730
-                'This method has been deprecated and there is no replacement for it.',
731
-                'event_espresso'
732
-            ),
733
-            '5.0.0.rc.002'
734
-        );
735
-        $this->set('EVT_visible_on', $visible_on);
736
-    }
737
-
738
-
739
-    /**
740
-     * @param $wp_user
741
-     * @throws EE_Error
742
-     * @throws ReflectionException
743
-     */
744
-    public function set_wp_user($wp_user)
745
-    {
746
-        $this->set('EVT_wp_user', $wp_user);
747
-    }
748
-
749
-
750
-    /**
751
-     * @param $default_registration_status
752
-     * @throws EE_Error
753
-     * @throws ReflectionException
754
-     */
755
-    public function set_default_registration_status($default_registration_status)
756
-    {
757
-        $this->set('EVT_default_registration_status', $default_registration_status);
758
-    }
759
-
760
-
761
-    /**
762
-     * @param $donations
763
-     * @throws EE_Error
764
-     * @throws ReflectionException
765
-     */
766
-    public function set_donations($donations)
767
-    {
768
-        $this->set('EVT_donations', $donations);
769
-    }
770
-
771
-
772
-    /**
773
-     * Adds a venue to this event
774
-     *
775
-     * @param int|EE_Venue /int $venue_id_or_obj
776
-     * @return EE_Base_Class|EE_Venue
777
-     * @throws EE_Error
778
-     * @throws ReflectionException
779
-     */
780
-    public function add_venue($venue_id_or_obj): EE_Venue
781
-    {
782
-        return $this->_add_relation_to($venue_id_or_obj, 'Venue');
783
-    }
784
-
785
-
786
-    /**
787
-     * Removes a venue from the event
788
-     *
789
-     * @param EE_Venue /int $venue_id_or_obj
790
-     * @return EE_Base_Class|EE_Venue
791
-     * @throws EE_Error
792
-     * @throws ReflectionException
793
-     */
794
-    public function remove_venue($venue_id_or_obj): EE_Venue
795
-    {
796
-        $venue_id_or_obj = ! empty($venue_id_or_obj) ? $venue_id_or_obj : $this->venue();
797
-        return $this->_remove_relation_to($venue_id_or_obj, 'Venue');
798
-    }
799
-
800
-
801
-    /**
802
-     * Gets the venue related to the event. May provide additional $query_params if desired
803
-     *
804
-     * @param array $query_params
805
-     * @return int
806
-     * @throws EE_Error
807
-     * @throws ReflectionException
808
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
809
-     */
810
-    public function venue_ID(array $query_params = []): int
811
-    {
812
-        $venue = $this->get_first_related('Venue', $query_params);
813
-        return $venue instanceof EE_Venue ? $venue->ID() : 0;
814
-    }
815
-
816
-
817
-    /**
818
-     * Gets the venue related to the event. May provide additional $query_params if desired
819
-     *
820
-     * @param array $query_params
821
-     * @return EE_Base_Class|EE_Venue|null
822
-     * @throws EE_Error
823
-     * @throws ReflectionException
824
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
825
-     */
826
-    public function venue(array $query_params = []): ?EE_Venue
827
-    {
828
-        return $this->get_first_related('Venue', $query_params);
829
-    }
830
-
831
-
832
-    /**
833
-     * @param array $query_params
834
-     * @return EE_Base_Class[]|EE_Venue[]
835
-     * @throws EE_Error
836
-     * @throws ReflectionException
837
-     * @deprecated 5.0.0.p
838
-     */
839
-    public function venues(array $query_params = []): array
840
-    {
841
-        $venue = $this->venue($query_params);
842
-        return $venue instanceof EE_Venue ? [$venue] : [];
843
-    }
844
-
845
-
846
-    /**
847
-     * check if event id is present and if event is published
848
-     *
849
-     * @return boolean true yes, false no
850
-     * @throws EE_Error
851
-     * @throws ReflectionException
852
-     */
853
-    private function _has_ID_and_is_published(): bool
854
-    {
855
-        // first check if event id is present and not NULL,
856
-        // then check if this event is published (or any of the equivalent "published" statuses)
857
-        return
858
-            $this->ID() && $this->ID() !== null
859
-            && (
860
-                $this->status() === 'publish'
861
-                || $this->status() === EEM_Event::sold_out
862
-                || $this->status() === EEM_Event::postponed
863
-                || $this->status() === EEM_Event::cancelled
864
-            );
865
-    }
866
-
867
-
868
-    /**
869
-     * This simply compares the internal dates with NOW and determines if the event is upcoming or not.
870
-     *
871
-     * @return boolean true yes, false no
872
-     * @throws EE_Error
873
-     * @throws ReflectionException
874
-     */
875
-    public function is_upcoming(): bool
876
-    {
877
-        // check if event id is present and if this event is published
878
-        if ($this->is_inactive()) {
879
-            return false;
880
-        }
881
-        // set initial value
882
-        $upcoming = false;
883
-        // next let's get all datetimes and loop through them
884
-        $datetimes = $this->datetimes_in_chronological_order();
885
-        foreach ($datetimes as $datetime) {
886
-            if ($datetime instanceof EE_Datetime) {
887
-                // if this dtt is expired then we continue cause one of the other datetimes might be upcoming.
888
-                if ($datetime->is_expired()) {
889
-                    continue;
890
-                }
891
-                // if this dtt is active then we return false.
892
-                if ($datetime->is_active()) {
893
-                    return false;
894
-                }
895
-                // otherwise let's check upcoming status
896
-                $upcoming = $datetime->is_upcoming();
897
-            }
898
-        }
899
-        return $upcoming;
900
-    }
901
-
902
-
903
-    /**
904
-     * @return bool
905
-     * @throws EE_Error
906
-     * @throws ReflectionException
907
-     */
908
-    public function is_active(): bool
909
-    {
910
-        // check if event id is present and if this event is published
911
-        if ($this->is_inactive()) {
912
-            return false;
913
-        }
914
-        // set initial value
915
-        $active = false;
916
-        // next let's get all datetimes and loop through them
917
-        $datetimes = $this->datetimes_in_chronological_order();
918
-        foreach ($datetimes as $datetime) {
919
-            if ($datetime instanceof EE_Datetime) {
920
-                // if this dtt is expired then we continue cause one of the other datetimes might be active.
921
-                if ($datetime->is_expired()) {
922
-                    continue;
923
-                }
924
-                // if this dtt is upcoming then we return false.
925
-                if ($datetime->is_upcoming()) {
926
-                    return false;
927
-                }
928
-                // otherwise let's check active status
929
-                $active = $datetime->is_active();
930
-            }
931
-        }
932
-        return $active;
933
-    }
934
-
935
-
936
-    /**
937
-     * @return bool
938
-     * @throws EE_Error
939
-     * @throws ReflectionException
940
-     */
941
-    public function is_expired(): bool
942
-    {
943
-        // check if event id is present and if this event is published
944
-        if ($this->is_inactive()) {
945
-            return false;
946
-        }
947
-        // set initial value
948
-        $expired = false;
949
-        // first let's get all datetimes and loop through them
950
-        $datetimes = $this->datetimes_in_chronological_order();
951
-        foreach ($datetimes as $datetime) {
952
-            if ($datetime instanceof EE_Datetime) {
953
-                // if this dtt is upcoming or active then we return false.
954
-                if ($datetime->is_upcoming() || $datetime->is_active()) {
955
-                    return false;
956
-                }
957
-                // otherwise let's check active status
958
-                $expired = $datetime->is_expired();
959
-            }
960
-        }
961
-        return $expired;
962
-    }
963
-
964
-
965
-    /**
966
-     * @return bool
967
-     * @throws EE_Error
968
-     * @throws ReflectionException
969
-     */
970
-    public function is_inactive(): bool
971
-    {
972
-        // check if event id is present and if this event is published
973
-        if ($this->_has_ID_and_is_published()) {
974
-            return false;
975
-        }
976
-        return true;
977
-    }
978
-
979
-
980
-    /**
981
-     * calculate spaces remaining based on "saleable" tickets
982
-     *
983
-     * @param array|null $tickets
984
-     * @param bool       $filtered
985
-     * @return int|float
986
-     * @throws EE_Error
987
-     * @throws DomainException
988
-     * @throws UnexpectedEntityException
989
-     * @throws ReflectionException
990
-     */
991
-    public function spaces_remaining(?array $tickets = [], ?bool $filtered = true)
992
-    {
993
-        $this->getAvailableSpacesCalculator()->setActiveTickets($tickets);
994
-        $spaces_remaining = $this->getAvailableSpacesCalculator()->spacesRemaining();
995
-        return $filtered
996
-            ? apply_filters(
997
-                'FHEE_EE_Event__spaces_remaining',
998
-                $spaces_remaining,
999
-                $this,
1000
-                $tickets
1001
-            )
1002
-            : $spaces_remaining;
1003
-    }
1004
-
1005
-
1006
-    /**
1007
-     *    perform_sold_out_status_check
1008
-     *    checks all of this event's datetime  reg_limit - sold values to determine if ANY datetimes have spaces
1009
-     *    available... if NOT, then the event status will get toggled to 'sold_out'
1010
-     *
1011
-     * @return bool    return the ACTUAL sold out state.
1012
-     * @throws EE_Error
1013
-     * @throws DomainException
1014
-     * @throws UnexpectedEntityException
1015
-     * @throws ReflectionException
1016
-     */
1017
-    public function perform_sold_out_status_check(): bool
1018
-    {
1019
-        // get all tickets
1020
-        $tickets     = $this->tickets(
1021
-            [
1022
-                'default_where_conditions' => 'none',
1023
-                'order_by'                 => ['TKT_qty' => 'ASC'],
1024
-            ]
1025
-        );
1026
-        $all_expired = true;
1027
-        foreach ($tickets as $ticket) {
1028
-            if (! $ticket->is_expired()) {
1029
-                $all_expired = false;
1030
-                break;
1031
-            }
1032
-        }
1033
-        // if all the tickets are just expired, then don't update the event status to sold out
1034
-        if ($all_expired) {
1035
-            return true;
1036
-        }
1037
-        $spaces_remaining = $this->spaces_remaining($tickets);
1038
-        if ($spaces_remaining < 1) {
1039
-            if ($this->status() !== EEM_CPT_Base::post_status_private) {
1040
-                $this->set_status(EEM_Event::sold_out);
1041
-                $this->save();
1042
-            }
1043
-            $sold_out = true;
1044
-        } else {
1045
-            $sold_out = false;
1046
-            // was event previously marked as sold out ?
1047
-            if ($this->status() === EEM_Event::sold_out) {
1048
-                // revert status to previous value, if it was set
1049
-                $previous_event_status = $this->get_post_meta('_previous_event_status', true);
1050
-                if ($previous_event_status) {
1051
-                    $this->set_status($previous_event_status);
1052
-                    $this->save();
1053
-                }
1054
-            }
1055
-        }
1056
-        do_action('AHEE__EE_Event__perform_sold_out_status_check__end', $this, $sold_out, $spaces_remaining, $tickets);
1057
-        return $sold_out;
1058
-    }
1059
-
1060
-
1061
-    /**
1062
-     * This returns the total remaining spaces for sale on this event.
1063
-     *
1064
-     * @return int|float
1065
-     * @throws EE_Error
1066
-     * @throws DomainException
1067
-     * @throws UnexpectedEntityException
1068
-     * @throws ReflectionException
1069
-     * @uses EE_Event::total_available_spaces()
1070
-     */
1071
-    public function spaces_remaining_for_sale()
1072
-    {
1073
-        return $this->total_available_spaces(true);
1074
-    }
1075
-
1076
-
1077
-    /**
1078
-     * This returns the total spaces available for an event
1079
-     * while considering all the quantities on the tickets and the reg limits
1080
-     * on the datetimes attached to this event.
1081
-     *
1082
-     * @param bool $consider_sold   Whether to consider any tickets that have already sold in our calculation.
1083
-     *                              If this is false, then we return the most tickets that could ever be sold
1084
-     *                              for this event with the datetime and tickets setup on the event under optimal
1085
-     *                              selling conditions.  Otherwise we return a live calculation of spaces available
1086
-     *                              based on tickets sold.  Depending on setup and stage of sales, this
1087
-     *                              may appear to equal remaining tickets.  However, the more tickets are
1088
-     *                              sold out, the more accurate the "live" total is.
1089
-     * @return int|float
1090
-     * @throws EE_Error
1091
-     * @throws DomainException
1092
-     * @throws UnexpectedEntityException
1093
-     * @throws ReflectionException
1094
-     */
1095
-    public function total_available_spaces(bool $consider_sold = false)
1096
-    {
1097
-        $spaces_available = $consider_sold
1098
-            ? $this->getAvailableSpacesCalculator()->spacesRemaining()
1099
-            : $this->getAvailableSpacesCalculator()->totalSpacesAvailable();
1100
-        return apply_filters(
1101
-            'FHEE_EE_Event__total_available_spaces__spaces_available',
1102
-            $spaces_available,
1103
-            $this,
1104
-            $this->getAvailableSpacesCalculator()->getDatetimes(),
1105
-            $this->getAvailableSpacesCalculator()->getActiveTickets()
1106
-        );
1107
-    }
1108
-
1109
-
1110
-    /**
1111
-     * Checks if the event is set to sold out
1112
-     *
1113
-     * @param bool $actual  whether or not to perform calculations to not only figure the
1114
-     *                      actual status but also to flip the status if necessary to sold
1115
-     *                      out If false, we just check the existing status of the event
1116
-     * @return boolean
1117
-     * @throws EE_Error
1118
-     * @throws ReflectionException
1119
-     */
1120
-    public function is_sold_out(bool $actual = false): bool
1121
-    {
1122
-        if (! $actual) {
1123
-            return $this->status() === EEM_Event::sold_out;
1124
-        }
1125
-        return $this->perform_sold_out_status_check();
1126
-    }
1127
-
1128
-
1129
-    /**
1130
-     * Checks if the event is marked as postponed
1131
-     *
1132
-     * @return boolean
1133
-     */
1134
-    public function is_postponed(): bool
1135
-    {
1136
-        return $this->status() === EEM_Event::postponed;
1137
-    }
1138
-
1139
-
1140
-    /**
1141
-     * Checks if the event is marked as cancelled
1142
-     *
1143
-     * @return boolean
1144
-     */
1145
-    public function is_cancelled(): bool
1146
-    {
1147
-        return $this->status() === EEM_Event::cancelled;
1148
-    }
1149
-
1150
-
1151
-    /**
1152
-     * Get the logical active status in a hierarchical order for all the datetimes.  Note
1153
-     * Basically, we order the datetimes by EVT_start_date.  Then first test on whether the event is published.  If its
1154
-     * NOT published then we test for whether its expired or not.  IF it IS published then we test first on whether an
1155
-     * event has any active dates.  If no active dates then we check for any upcoming dates.  If no upcoming dates then
1156
-     * the event is considered expired.
1157
-     * NOTE: this method does NOT calculate whether the datetimes are sold out when event is published.  Sold Out is a
1158
-     * status set on the EVENT when it is not published and thus is done
1159
-     *
1160
-     * @param bool $reset
1161
-     * @return bool | string - based on EE_Datetime active constants or FALSE if error.
1162
-     * @throws EE_Error
1163
-     * @throws ReflectionException
1164
-     */
1165
-    public function get_active_status(bool $reset = false)
1166
-    {
1167
-        // if the active status has already been set, then just use that value (unless we are resetting it)
1168
-        if (! empty($this->_active_status) && ! $reset) {
1169
-            return $this->_active_status;
1170
-        }
1171
-        // first check if event id is present on this object
1172
-        if (! $this->ID()) {
1173
-            return false;
1174
-        }
1175
-        $where_params_for_event = [['EVT_ID' => $this->ID()]];
1176
-        // if event is published:
1177
-        if (
1178
-            $this->status() === EEM_CPT_Base::post_status_publish
1179
-            || $this->status() === EEM_CPT_Base::post_status_private
1180
-        ) {
1181
-            // active?
1182
-            if (
1183
-                EEM_Datetime::instance()->get_datetime_count_for_status(
1184
-                    EE_Datetime::active,
1185
-                    $where_params_for_event
1186
-                ) > 0
1187
-            ) {
1188
-                $this->_active_status = EE_Datetime::active;
1189
-            } else {
1190
-                // upcoming?
1191
-                if (
1192
-                    EEM_Datetime::instance()->get_datetime_count_for_status(
1193
-                        EE_Datetime::upcoming,
1194
-                        $where_params_for_event
1195
-                    ) > 0
1196
-                ) {
1197
-                    $this->_active_status = EE_Datetime::upcoming;
1198
-                } else {
1199
-                    // expired?
1200
-                    if (
1201
-                        EEM_Datetime::instance()->get_datetime_count_for_status(
1202
-                            EE_Datetime::expired,
1203
-                            $where_params_for_event
1204
-                        ) > 0
1205
-                    ) {
1206
-                        $this->_active_status = EE_Datetime::expired;
1207
-                    } else {
1208
-                        // it would be odd if things make it this far
1209
-                        // because it basically means there are no datetimes attached to the event.
1210
-                        // So in this case it will just be considered inactive.
1211
-                        $this->_active_status = EE_Datetime::inactive;
1212
-                    }
1213
-                }
1214
-            }
1215
-        } else {
1216
-            // the event is not published, so let's just set it's active status according to its' post status
1217
-            switch ($this->status()) {
1218
-                case EEM_Event::sold_out:
1219
-                    $this->_active_status = EE_Datetime::sold_out;
1220
-                    break;
1221
-                case EEM_Event::cancelled:
1222
-                    $this->_active_status = EE_Datetime::cancelled;
1223
-                    break;
1224
-                case EEM_Event::postponed:
1225
-                    $this->_active_status = EE_Datetime::postponed;
1226
-                    break;
1227
-                default:
1228
-                    $this->_active_status = EE_Datetime::inactive;
1229
-            }
1230
-        }
1231
-        return $this->_active_status;
1232
-    }
1233
-
1234
-
1235
-    /**
1236
-     *    pretty_active_status
1237
-     *
1238
-     * @param boolean $echo whether to return (FALSE), or echo out the result (TRUE)
1239
-     * @return string
1240
-     * @throws EE_Error
1241
-     * @throws ReflectionException
1242
-     */
1243
-    public function pretty_active_status(bool $echo = true): string
1244
-    {
1245
-        $active_status = $this->get_active_status();
1246
-        $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
+	 * @deprecated
528
+	 */
529
+	public function visible_on(): string
530
+	{
531
+		EE_Error::doing_it_wrong(
532
+			__METHOD__,
533
+			esc_html__(
534
+				'This method has been deprecated and there is no replacement for it.',
535
+				'event_espresso'
536
+			),
537
+			'5.0.0.rc.002'
538
+		);
539
+		return $this->get('EVT_visible_on');
540
+	}
541
+
542
+
543
+	/**
544
+	 * @return int
545
+	 * @throws EE_Error
546
+	 * @throws ReflectionException
547
+	 */
548
+	public function wp_user(): int
549
+	{
550
+		return $this->get('EVT_wp_user');
551
+	}
552
+
553
+
554
+	/**
555
+	 * @return bool
556
+	 * @throws EE_Error
557
+	 * @throws ReflectionException
558
+	 */
559
+	public function donations(): bool
560
+	{
561
+		return $this->get('EVT_donations');
562
+	}
563
+
564
+
565
+	/**
566
+	 * @param int $limit
567
+	 * @throws EE_Error
568
+	 * @throws ReflectionException
569
+	 */
570
+	public function set_additional_limit(int $limit)
571
+	{
572
+		$this->set('EVT_additional_limit', $limit);
573
+	}
574
+
575
+
576
+	/**
577
+	 * @param $created
578
+	 * @throws EE_Error
579
+	 * @throws ReflectionException
580
+	 */
581
+	public function set_created($created)
582
+	{
583
+		$this->set('EVT_created', $created);
584
+	}
585
+
586
+
587
+	/**
588
+	 * @param $desc
589
+	 * @throws EE_Error
590
+	 * @throws ReflectionException
591
+	 */
592
+	public function set_description($desc)
593
+	{
594
+		$this->set('EVT_desc', $desc);
595
+	}
596
+
597
+
598
+	/**
599
+	 * @param $display_desc
600
+	 * @throws EE_Error
601
+	 * @throws ReflectionException
602
+	 */
603
+	public function set_display_description($display_desc)
604
+	{
605
+		$this->set('EVT_display_desc', $display_desc);
606
+	}
607
+
608
+
609
+	/**
610
+	 * @param $display_ticket_selector
611
+	 * @throws EE_Error
612
+	 * @throws ReflectionException
613
+	 */
614
+	public function set_display_ticket_selector($display_ticket_selector)
615
+	{
616
+		$this->set('EVT_display_ticket_selector', $display_ticket_selector);
617
+	}
618
+
619
+
620
+	/**
621
+	 * @param $external_url
622
+	 * @throws EE_Error
623
+	 * @throws ReflectionException
624
+	 */
625
+	public function set_external_url($external_url)
626
+	{
627
+		$this->set('EVT_external_URL', $external_url);
628
+	}
629
+
630
+
631
+	/**
632
+	 * @param $member_only
633
+	 * @throws EE_Error
634
+	 * @throws ReflectionException
635
+	 */
636
+	public function set_member_only($member_only)
637
+	{
638
+		$this->set('EVT_member_only', $member_only);
639
+	}
640
+
641
+
642
+	/**
643
+	 * @param $event_phone
644
+	 * @throws EE_Error
645
+	 * @throws ReflectionException
646
+	 */
647
+	public function set_event_phone($event_phone)
648
+	{
649
+		$this->set('EVT_phone', $event_phone);
650
+	}
651
+
652
+
653
+	/**
654
+	 * @param $modified
655
+	 * @throws EE_Error
656
+	 * @throws ReflectionException
657
+	 */
658
+	public function set_modified($modified)
659
+	{
660
+		$this->set('EVT_modified', $modified);
661
+	}
662
+
663
+
664
+	/**
665
+	 * @param $name
666
+	 * @throws EE_Error
667
+	 * @throws ReflectionException
668
+	 */
669
+	public function set_name($name)
670
+	{
671
+		$this->set('EVT_name', $name);
672
+	}
673
+
674
+
675
+	/**
676
+	 * @param $order
677
+	 * @throws EE_Error
678
+	 * @throws ReflectionException
679
+	 */
680
+	public function set_order($order)
681
+	{
682
+		$this->set('EVT_order', $order);
683
+	}
684
+
685
+
686
+	/**
687
+	 * @param $short_desc
688
+	 * @throws EE_Error
689
+	 * @throws ReflectionException
690
+	 */
691
+	public function set_short_description($short_desc)
692
+	{
693
+		$this->set('EVT_short_desc', $short_desc);
694
+	}
695
+
696
+
697
+	/**
698
+	 * @param $slug
699
+	 * @throws EE_Error
700
+	 * @throws ReflectionException
701
+	 */
702
+	public function set_slug($slug)
703
+	{
704
+		$this->set('EVT_slug', $slug);
705
+	}
706
+
707
+
708
+	/**
709
+	 * @param $timezone_string
710
+	 * @throws EE_Error
711
+	 * @throws ReflectionException
712
+	 */
713
+	public function set_timezone_string($timezone_string)
714
+	{
715
+		$this->set('EVT_timezone_string', $timezone_string);
716
+	}
717
+
718
+
719
+	/**
720
+	 * @param $visible_on
721
+	 * @throws EE_Error
722
+	 * @throws ReflectionException
723
+	 * @deprecated
724
+	 */
725
+	public function set_visible_on($visible_on)
726
+	{
727
+		EE_Error::doing_it_wrong(
728
+			__METHOD__,
729
+			esc_html__(
730
+				'This method has been deprecated and there is no replacement for it.',
731
+				'event_espresso'
732
+			),
733
+			'5.0.0.rc.002'
734
+		);
735
+		$this->set('EVT_visible_on', $visible_on);
736
+	}
737
+
738
+
739
+	/**
740
+	 * @param $wp_user
741
+	 * @throws EE_Error
742
+	 * @throws ReflectionException
743
+	 */
744
+	public function set_wp_user($wp_user)
745
+	{
746
+		$this->set('EVT_wp_user', $wp_user);
747
+	}
748
+
749
+
750
+	/**
751
+	 * @param $default_registration_status
752
+	 * @throws EE_Error
753
+	 * @throws ReflectionException
754
+	 */
755
+	public function set_default_registration_status($default_registration_status)
756
+	{
757
+		$this->set('EVT_default_registration_status', $default_registration_status);
758
+	}
759
+
760
+
761
+	/**
762
+	 * @param $donations
763
+	 * @throws EE_Error
764
+	 * @throws ReflectionException
765
+	 */
766
+	public function set_donations($donations)
767
+	{
768
+		$this->set('EVT_donations', $donations);
769
+	}
770
+
771
+
772
+	/**
773
+	 * Adds a venue to this event
774
+	 *
775
+	 * @param int|EE_Venue /int $venue_id_or_obj
776
+	 * @return EE_Base_Class|EE_Venue
777
+	 * @throws EE_Error
778
+	 * @throws ReflectionException
779
+	 */
780
+	public function add_venue($venue_id_or_obj): EE_Venue
781
+	{
782
+		return $this->_add_relation_to($venue_id_or_obj, 'Venue');
783
+	}
784
+
785
+
786
+	/**
787
+	 * Removes a venue from the event
788
+	 *
789
+	 * @param EE_Venue /int $venue_id_or_obj
790
+	 * @return EE_Base_Class|EE_Venue
791
+	 * @throws EE_Error
792
+	 * @throws ReflectionException
793
+	 */
794
+	public function remove_venue($venue_id_or_obj): EE_Venue
795
+	{
796
+		$venue_id_or_obj = ! empty($venue_id_or_obj) ? $venue_id_or_obj : $this->venue();
797
+		return $this->_remove_relation_to($venue_id_or_obj, 'Venue');
798
+	}
799
+
800
+
801
+	/**
802
+	 * Gets the venue related to the event. May provide additional $query_params if desired
803
+	 *
804
+	 * @param array $query_params
805
+	 * @return int
806
+	 * @throws EE_Error
807
+	 * @throws ReflectionException
808
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
809
+	 */
810
+	public function venue_ID(array $query_params = []): int
811
+	{
812
+		$venue = $this->get_first_related('Venue', $query_params);
813
+		return $venue instanceof EE_Venue ? $venue->ID() : 0;
814
+	}
815
+
816
+
817
+	/**
818
+	 * Gets the venue related to the event. May provide additional $query_params if desired
819
+	 *
820
+	 * @param array $query_params
821
+	 * @return EE_Base_Class|EE_Venue|null
822
+	 * @throws EE_Error
823
+	 * @throws ReflectionException
824
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
825
+	 */
826
+	public function venue(array $query_params = []): ?EE_Venue
827
+	{
828
+		return $this->get_first_related('Venue', $query_params);
829
+	}
830
+
831
+
832
+	/**
833
+	 * @param array $query_params
834
+	 * @return EE_Base_Class[]|EE_Venue[]
835
+	 * @throws EE_Error
836
+	 * @throws ReflectionException
837
+	 * @deprecated 5.0.0.p
838
+	 */
839
+	public function venues(array $query_params = []): array
840
+	{
841
+		$venue = $this->venue($query_params);
842
+		return $venue instanceof EE_Venue ? [$venue] : [];
843
+	}
844
+
845
+
846
+	/**
847
+	 * check if event id is present and if event is published
848
+	 *
849
+	 * @return boolean true yes, false no
850
+	 * @throws EE_Error
851
+	 * @throws ReflectionException
852
+	 */
853
+	private function _has_ID_and_is_published(): bool
854
+	{
855
+		// first check if event id is present and not NULL,
856
+		// then check if this event is published (or any of the equivalent "published" statuses)
857
+		return
858
+			$this->ID() && $this->ID() !== null
859
+			&& (
860
+				$this->status() === 'publish'
861
+				|| $this->status() === EEM_Event::sold_out
862
+				|| $this->status() === EEM_Event::postponed
863
+				|| $this->status() === EEM_Event::cancelled
864
+			);
865
+	}
866
+
867
+
868
+	/**
869
+	 * This simply compares the internal dates with NOW and determines if the event is upcoming or not.
870
+	 *
871
+	 * @return boolean true yes, false no
872
+	 * @throws EE_Error
873
+	 * @throws ReflectionException
874
+	 */
875
+	public function is_upcoming(): bool
876
+	{
877
+		// check if event id is present and if this event is published
878
+		if ($this->is_inactive()) {
879
+			return false;
880
+		}
881
+		// set initial value
882
+		$upcoming = false;
883
+		// next let's get all datetimes and loop through them
884
+		$datetimes = $this->datetimes_in_chronological_order();
885
+		foreach ($datetimes as $datetime) {
886
+			if ($datetime instanceof EE_Datetime) {
887
+				// if this dtt is expired then we continue cause one of the other datetimes might be upcoming.
888
+				if ($datetime->is_expired()) {
889
+					continue;
890
+				}
891
+				// if this dtt is active then we return false.
892
+				if ($datetime->is_active()) {
893
+					return false;
894
+				}
895
+				// otherwise let's check upcoming status
896
+				$upcoming = $datetime->is_upcoming();
897
+			}
898
+		}
899
+		return $upcoming;
900
+	}
901
+
902
+
903
+	/**
904
+	 * @return bool
905
+	 * @throws EE_Error
906
+	 * @throws ReflectionException
907
+	 */
908
+	public function is_active(): bool
909
+	{
910
+		// check if event id is present and if this event is published
911
+		if ($this->is_inactive()) {
912
+			return false;
913
+		}
914
+		// set initial value
915
+		$active = false;
916
+		// next let's get all datetimes and loop through them
917
+		$datetimes = $this->datetimes_in_chronological_order();
918
+		foreach ($datetimes as $datetime) {
919
+			if ($datetime instanceof EE_Datetime) {
920
+				// if this dtt is expired then we continue cause one of the other datetimes might be active.
921
+				if ($datetime->is_expired()) {
922
+					continue;
923
+				}
924
+				// if this dtt is upcoming then we return false.
925
+				if ($datetime->is_upcoming()) {
926
+					return false;
927
+				}
928
+				// otherwise let's check active status
929
+				$active = $datetime->is_active();
930
+			}
931
+		}
932
+		return $active;
933
+	}
934
+
935
+
936
+	/**
937
+	 * @return bool
938
+	 * @throws EE_Error
939
+	 * @throws ReflectionException
940
+	 */
941
+	public function is_expired(): bool
942
+	{
943
+		// check if event id is present and if this event is published
944
+		if ($this->is_inactive()) {
945
+			return false;
946
+		}
947
+		// set initial value
948
+		$expired = false;
949
+		// first let's get all datetimes and loop through them
950
+		$datetimes = $this->datetimes_in_chronological_order();
951
+		foreach ($datetimes as $datetime) {
952
+			if ($datetime instanceof EE_Datetime) {
953
+				// if this dtt is upcoming or active then we return false.
954
+				if ($datetime->is_upcoming() || $datetime->is_active()) {
955
+					return false;
956
+				}
957
+				// otherwise let's check active status
958
+				$expired = $datetime->is_expired();
959
+			}
960
+		}
961
+		return $expired;
962
+	}
963
+
964
+
965
+	/**
966
+	 * @return bool
967
+	 * @throws EE_Error
968
+	 * @throws ReflectionException
969
+	 */
970
+	public function is_inactive(): bool
971
+	{
972
+		// check if event id is present and if this event is published
973
+		if ($this->_has_ID_and_is_published()) {
974
+			return false;
975
+		}
976
+		return true;
977
+	}
978
+
979
+
980
+	/**
981
+	 * calculate spaces remaining based on "saleable" tickets
982
+	 *
983
+	 * @param array|null $tickets
984
+	 * @param bool       $filtered
985
+	 * @return int|float
986
+	 * @throws EE_Error
987
+	 * @throws DomainException
988
+	 * @throws UnexpectedEntityException
989
+	 * @throws ReflectionException
990
+	 */
991
+	public function spaces_remaining(?array $tickets = [], ?bool $filtered = true)
992
+	{
993
+		$this->getAvailableSpacesCalculator()->setActiveTickets($tickets);
994
+		$spaces_remaining = $this->getAvailableSpacesCalculator()->spacesRemaining();
995
+		return $filtered
996
+			? apply_filters(
997
+				'FHEE_EE_Event__spaces_remaining',
998
+				$spaces_remaining,
999
+				$this,
1000
+				$tickets
1001
+			)
1002
+			: $spaces_remaining;
1003
+	}
1004
+
1005
+
1006
+	/**
1007
+	 *    perform_sold_out_status_check
1008
+	 *    checks all of this event's datetime  reg_limit - sold values to determine if ANY datetimes have spaces
1009
+	 *    available... if NOT, then the event status will get toggled to 'sold_out'
1010
+	 *
1011
+	 * @return bool    return the ACTUAL sold out state.
1012
+	 * @throws EE_Error
1013
+	 * @throws DomainException
1014
+	 * @throws UnexpectedEntityException
1015
+	 * @throws ReflectionException
1016
+	 */
1017
+	public function perform_sold_out_status_check(): bool
1018
+	{
1019
+		// get all tickets
1020
+		$tickets     = $this->tickets(
1021
+			[
1022
+				'default_where_conditions' => 'none',
1023
+				'order_by'                 => ['TKT_qty' => 'ASC'],
1024
+			]
1025
+		);
1026
+		$all_expired = true;
1027
+		foreach ($tickets as $ticket) {
1028
+			if (! $ticket->is_expired()) {
1029
+				$all_expired = false;
1030
+				break;
1031
+			}
1032
+		}
1033
+		// if all the tickets are just expired, then don't update the event status to sold out
1034
+		if ($all_expired) {
1035
+			return true;
1036
+		}
1037
+		$spaces_remaining = $this->spaces_remaining($tickets);
1038
+		if ($spaces_remaining < 1) {
1039
+			if ($this->status() !== EEM_CPT_Base::post_status_private) {
1040
+				$this->set_status(EEM_Event::sold_out);
1041
+				$this->save();
1042
+			}
1043
+			$sold_out = true;
1044
+		} else {
1045
+			$sold_out = false;
1046
+			// was event previously marked as sold out ?
1047
+			if ($this->status() === EEM_Event::sold_out) {
1048
+				// revert status to previous value, if it was set
1049
+				$previous_event_status = $this->get_post_meta('_previous_event_status', true);
1050
+				if ($previous_event_status) {
1051
+					$this->set_status($previous_event_status);
1052
+					$this->save();
1053
+				}
1054
+			}
1055
+		}
1056
+		do_action('AHEE__EE_Event__perform_sold_out_status_check__end', $this, $sold_out, $spaces_remaining, $tickets);
1057
+		return $sold_out;
1058
+	}
1059
+
1060
+
1061
+	/**
1062
+	 * This returns the total remaining spaces for sale on this event.
1063
+	 *
1064
+	 * @return int|float
1065
+	 * @throws EE_Error
1066
+	 * @throws DomainException
1067
+	 * @throws UnexpectedEntityException
1068
+	 * @throws ReflectionException
1069
+	 * @uses EE_Event::total_available_spaces()
1070
+	 */
1071
+	public function spaces_remaining_for_sale()
1072
+	{
1073
+		return $this->total_available_spaces(true);
1074
+	}
1075
+
1076
+
1077
+	/**
1078
+	 * This returns the total spaces available for an event
1079
+	 * while considering all the quantities on the tickets and the reg limits
1080
+	 * on the datetimes attached to this event.
1081
+	 *
1082
+	 * @param bool $consider_sold   Whether to consider any tickets that have already sold in our calculation.
1083
+	 *                              If this is false, then we return the most tickets that could ever be sold
1084
+	 *                              for this event with the datetime and tickets setup on the event under optimal
1085
+	 *                              selling conditions.  Otherwise we return a live calculation of spaces available
1086
+	 *                              based on tickets sold.  Depending on setup and stage of sales, this
1087
+	 *                              may appear to equal remaining tickets.  However, the more tickets are
1088
+	 *                              sold out, the more accurate the "live" total is.
1089
+	 * @return int|float
1090
+	 * @throws EE_Error
1091
+	 * @throws DomainException
1092
+	 * @throws UnexpectedEntityException
1093
+	 * @throws ReflectionException
1094
+	 */
1095
+	public function total_available_spaces(bool $consider_sold = false)
1096
+	{
1097
+		$spaces_available = $consider_sold
1098
+			? $this->getAvailableSpacesCalculator()->spacesRemaining()
1099
+			: $this->getAvailableSpacesCalculator()->totalSpacesAvailable();
1100
+		return apply_filters(
1101
+			'FHEE_EE_Event__total_available_spaces__spaces_available',
1102
+			$spaces_available,
1103
+			$this,
1104
+			$this->getAvailableSpacesCalculator()->getDatetimes(),
1105
+			$this->getAvailableSpacesCalculator()->getActiveTickets()
1106
+		);
1107
+	}
1108
+
1109
+
1110
+	/**
1111
+	 * Checks if the event is set to sold out
1112
+	 *
1113
+	 * @param bool $actual  whether or not to perform calculations to not only figure the
1114
+	 *                      actual status but also to flip the status if necessary to sold
1115
+	 *                      out If false, we just check the existing status of the event
1116
+	 * @return boolean
1117
+	 * @throws EE_Error
1118
+	 * @throws ReflectionException
1119
+	 */
1120
+	public function is_sold_out(bool $actual = false): bool
1121
+	{
1122
+		if (! $actual) {
1123
+			return $this->status() === EEM_Event::sold_out;
1124
+		}
1125
+		return $this->perform_sold_out_status_check();
1126
+	}
1127
+
1128
+
1129
+	/**
1130
+	 * Checks if the event is marked as postponed
1131
+	 *
1132
+	 * @return boolean
1133
+	 */
1134
+	public function is_postponed(): bool
1135
+	{
1136
+		return $this->status() === EEM_Event::postponed;
1137
+	}
1138
+
1139
+
1140
+	/**
1141
+	 * Checks if the event is marked as cancelled
1142
+	 *
1143
+	 * @return boolean
1144
+	 */
1145
+	public function is_cancelled(): bool
1146
+	{
1147
+		return $this->status() === EEM_Event::cancelled;
1148
+	}
1149
+
1150
+
1151
+	/**
1152
+	 * Get the logical active status in a hierarchical order for all the datetimes.  Note
1153
+	 * Basically, we order the datetimes by EVT_start_date.  Then first test on whether the event is published.  If its
1154
+	 * NOT published then we test for whether its expired or not.  IF it IS published then we test first on whether an
1155
+	 * event has any active dates.  If no active dates then we check for any upcoming dates.  If no upcoming dates then
1156
+	 * the event is considered expired.
1157
+	 * NOTE: this method does NOT calculate whether the datetimes are sold out when event is published.  Sold Out is a
1158
+	 * status set on the EVENT when it is not published and thus is done
1159
+	 *
1160
+	 * @param bool $reset
1161
+	 * @return bool | string - based on EE_Datetime active constants or FALSE if error.
1162
+	 * @throws EE_Error
1163
+	 * @throws ReflectionException
1164
+	 */
1165
+	public function get_active_status(bool $reset = false)
1166
+	{
1167
+		// if the active status has already been set, then just use that value (unless we are resetting it)
1168
+		if (! empty($this->_active_status) && ! $reset) {
1169
+			return $this->_active_status;
1170
+		}
1171
+		// first check if event id is present on this object
1172
+		if (! $this->ID()) {
1173
+			return false;
1174
+		}
1175
+		$where_params_for_event = [['EVT_ID' => $this->ID()]];
1176
+		// if event is published:
1177
+		if (
1178
+			$this->status() === EEM_CPT_Base::post_status_publish
1179
+			|| $this->status() === EEM_CPT_Base::post_status_private
1180
+		) {
1181
+			// active?
1182
+			if (
1183
+				EEM_Datetime::instance()->get_datetime_count_for_status(
1184
+					EE_Datetime::active,
1185
+					$where_params_for_event
1186
+				) > 0
1187
+			) {
1188
+				$this->_active_status = EE_Datetime::active;
1189
+			} else {
1190
+				// upcoming?
1191
+				if (
1192
+					EEM_Datetime::instance()->get_datetime_count_for_status(
1193
+						EE_Datetime::upcoming,
1194
+						$where_params_for_event
1195
+					) > 0
1196
+				) {
1197
+					$this->_active_status = EE_Datetime::upcoming;
1198
+				} else {
1199
+					// expired?
1200
+					if (
1201
+						EEM_Datetime::instance()->get_datetime_count_for_status(
1202
+							EE_Datetime::expired,
1203
+							$where_params_for_event
1204
+						) > 0
1205
+					) {
1206
+						$this->_active_status = EE_Datetime::expired;
1207
+					} else {
1208
+						// it would be odd if things make it this far
1209
+						// because it basically means there are no datetimes attached to the event.
1210
+						// So in this case it will just be considered inactive.
1211
+						$this->_active_status = EE_Datetime::inactive;
1212
+					}
1213
+				}
1214
+			}
1215
+		} else {
1216
+			// the event is not published, so let's just set it's active status according to its' post status
1217
+			switch ($this->status()) {
1218
+				case EEM_Event::sold_out:
1219
+					$this->_active_status = EE_Datetime::sold_out;
1220
+					break;
1221
+				case EEM_Event::cancelled:
1222
+					$this->_active_status = EE_Datetime::cancelled;
1223
+					break;
1224
+				case EEM_Event::postponed:
1225
+					$this->_active_status = EE_Datetime::postponed;
1226
+					break;
1227
+				default:
1228
+					$this->_active_status = EE_Datetime::inactive;
1229
+			}
1230
+		}
1231
+		return $this->_active_status;
1232
+	}
1233
+
1234
+
1235
+	/**
1236
+	 *    pretty_active_status
1237
+	 *
1238
+	 * @param boolean $echo whether to return (FALSE), or echo out the result (TRUE)
1239
+	 * @return string
1240
+	 * @throws EE_Error
1241
+	 * @throws ReflectionException
1242
+	 */
1243
+	public function pretty_active_status(bool $echo = true): string
1244
+	{
1245
+		$active_status = $this->get_active_status();
1246
+		$status        = "
1247 1247
         <span class='ee-status ee-status-bg--$active_status event-active-status-$active_status'>
1248 1248
             " . EEH_Template::pretty_status($active_status, false, 'sentence') . "
1249 1249
         </span >";
1250
-        if ($echo) {
1251
-            echo wp_kses($status, AllowedTags::getAllowedTags());
1252
-            return '';
1253
-        }
1254
-        return $status;
1255
-    }
1256
-
1257
-
1258
-    /**
1259
-     * @return bool|int
1260
-     * @throws EE_Error
1261
-     * @throws ReflectionException
1262
-     */
1263
-    public function get_number_of_tickets_sold()
1264
-    {
1265
-        $tkt_sold = 0;
1266
-        if (! $this->ID()) {
1267
-            return 0;
1268
-        }
1269
-        $datetimes = $this->datetimes();
1270
-        foreach ($datetimes as $datetime) {
1271
-            if ($datetime instanceof EE_Datetime) {
1272
-                $tkt_sold += $datetime->sold();
1273
-            }
1274
-        }
1275
-        return $tkt_sold;
1276
-    }
1277
-
1278
-
1279
-    /**
1280
-     * This just returns a count of all the registrations for this event
1281
-     *
1282
-     * @return int
1283
-     * @throws EE_Error
1284
-     * @throws ReflectionException
1285
-     */
1286
-    public function get_count_of_all_registrations(): int
1287
-    {
1288
-        return EEM_Event::instance()->count_related($this, 'Registration');
1289
-    }
1290
-
1291
-
1292
-    /**
1293
-     * This returns the ticket with the earliest start time that is
1294
-     * available for this event (across all datetimes attached to the event)
1295
-     *
1296
-     * @return EE_Base_Class|EE_Ticket|null
1297
-     * @throws EE_Error
1298
-     * @throws ReflectionException
1299
-     */
1300
-    public function get_ticket_with_earliest_start_time()
1301
-    {
1302
-        $where['Datetime.EVT_ID'] = $this->ID();
1303
-        $query_params             = [$where, 'order_by' => ['TKT_start_date' => 'ASC']];
1304
-        return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1305
-    }
1306
-
1307
-
1308
-    /**
1309
-     * This returns the ticket with the latest end time that is available
1310
-     * for this event (across all datetimes attached to the event)
1311
-     *
1312
-     * @return EE_Base_Class|EE_Ticket|null
1313
-     * @throws EE_Error
1314
-     * @throws ReflectionException
1315
-     */
1316
-    public function get_ticket_with_latest_end_time()
1317
-    {
1318
-        $where['Datetime.EVT_ID'] = $this->ID();
1319
-        $query_params             = [$where, 'order_by' => ['TKT_end_date' => 'DESC']];
1320
-        return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1321
-    }
1322
-
1323
-
1324
-    /**
1325
-     * This returns the number of different ticket types currently on sale for this event.
1326
-     *
1327
-     * @return int
1328
-     * @throws EE_Error
1329
-     * @throws ReflectionException
1330
-     */
1331
-    public function countTicketsOnSale(): int
1332
-    {
1333
-        $where = [
1334
-            'Datetime.EVT_ID' => $this->ID(),
1335
-            'TKT_start_date'  => ['<', time()],
1336
-            'TKT_end_date'    => ['>', time()],
1337
-        ];
1338
-        return EEM_Ticket::instance()->count([$where]);
1339
-    }
1340
-
1341
-
1342
-    /**
1343
-     * This returns whether there are any tickets on sale for this event.
1344
-     *
1345
-     * @return bool true = YES tickets on sale.
1346
-     * @throws EE_Error
1347
-     * @throws ReflectionException
1348
-     */
1349
-    public function tickets_on_sale(): bool
1350
-    {
1351
-        return $this->countTicketsOnSale() > 0;
1352
-    }
1353
-
1354
-
1355
-    /**
1356
-     * Gets the URL for viewing this event on the front-end. Overrides parent
1357
-     * to check for an external URL first
1358
-     *
1359
-     * @return string
1360
-     * @throws EE_Error
1361
-     * @throws ReflectionException
1362
-     */
1363
-    public function get_permalink(): string
1364
-    {
1365
-        if ($this->external_url()) {
1366
-            return $this->external_url();
1367
-        }
1368
-        return parent::get_permalink();
1369
-    }
1370
-
1371
-
1372
-    /**
1373
-     * Gets the first term for 'espresso_event_categories' we can find
1374
-     *
1375
-     * @param array $query_params
1376
-     * @return EE_Base_Class|EE_Term|null
1377
-     * @throws EE_Error
1378
-     * @throws ReflectionException
1379
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1380
-     */
1381
-    public function first_event_category(array $query_params = []): ?EE_Term
1382
-    {
1383
-        $query_params[0]['Term_Taxonomy.taxonomy']     = 'espresso_event_categories';
1384
-        $query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1385
-        return EEM_Term::instance()->get_one($query_params);
1386
-    }
1387
-
1388
-
1389
-    /**
1390
-     * Gets all terms for 'espresso_event_categories' we can find
1391
-     *
1392
-     * @param array $query_params
1393
-     * @return EE_Base_Class[]|EE_Term[]
1394
-     * @throws EE_Error
1395
-     * @throws ReflectionException
1396
-     */
1397
-    public function get_all_event_categories(array $query_params = []): array
1398
-    {
1399
-        $query_params[0]['Term_Taxonomy.taxonomy']     = 'espresso_event_categories';
1400
-        $query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1401
-        return EEM_Term::instance()->get_all($query_params);
1402
-    }
1403
-
1404
-
1405
-    /**
1406
-     * Adds a question group to this event
1407
-     *
1408
-     * @param EE_Question_Group|int $question_group_id_or_obj
1409
-     * @param bool                  $for_primary if true, the question group will be added for the primary
1410
-     *                                           registrant, if false will be added for others. default: false
1411
-     * @return EE_Base_Class|EE_Question_Group
1412
-     * @throws EE_Error
1413
-     * @throws InvalidArgumentException
1414
-     * @throws InvalidDataTypeException
1415
-     * @throws InvalidInterfaceException
1416
-     * @throws ReflectionException
1417
-     */
1418
-    public function add_question_group($question_group_id_or_obj, bool $for_primary = false): EE_Question_Group
1419
-    {
1420
-        // If the row already exists, it will be updated. If it doesn't, it will be inserted.
1421
-        // That's in EE_HABTM_Relation::add_relation_to().
1422
-        return $this->_add_relation_to(
1423
-            $question_group_id_or_obj,
1424
-            'Question_Group',
1425
-            [
1426
-                EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary) => true,
1427
-            ]
1428
-        );
1429
-    }
1430
-
1431
-
1432
-    /**
1433
-     * Removes a question group from the event
1434
-     *
1435
-     * @param EE_Question_Group|int $question_group_id_or_obj
1436
-     * @param bool                  $for_primary if true, the question group will be removed from the primary
1437
-     *                                           registrant, if false will be removed from others. default: false
1438
-     * @return EE_Base_Class|EE_Question_Group|int
1439
-     * @throws EE_Error
1440
-     * @throws InvalidArgumentException
1441
-     * @throws ReflectionException
1442
-     * @throws InvalidDataTypeException
1443
-     * @throws InvalidInterfaceException
1444
-     */
1445
-    public function remove_question_group($question_group_id_or_obj, bool $for_primary = false)
1446
-    {
1447
-        // If the question group is used for the other type (primary or additional)
1448
-        // then just update it. If not, delete it outright.
1449
-        $existing_relation = $this->get_first_related(
1450
-            'Event_Question_Group',
1451
-            [
1452
-                [
1453
-                    'QSG_ID' => EEM_Question_Group::instance()->ensure_is_ID($question_group_id_or_obj),
1454
-                ],
1455
-            ]
1456
-        );
1457
-        $field_to_update   = EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary);
1458
-        $other_field       = EEM_Event_Question_Group::instance()->fieldNameForContext(! $for_primary);
1459
-        if ($existing_relation->get($other_field) === false) {
1460
-            // Delete it. It's now no longer for primary or additional question groups.
1461
-            return $this->_remove_relation_to($question_group_id_or_obj, 'Question_Group');
1462
-        }
1463
-        // Just update it. They'll still use this question group for the other category
1464
-        $existing_relation->save(
1465
-            [
1466
-                $field_to_update => false,
1467
-            ]
1468
-        );
1469
-        return $question_group_id_or_obj;
1470
-    }
1471
-
1472
-
1473
-    /**
1474
-     * Gets all the question groups, ordering them by QSG_order ascending
1475
-     *
1476
-     * @param array $query_params
1477
-     * @return EE_Base_Class[]|EE_Question_Group[]
1478
-     * @throws EE_Error
1479
-     * @throws ReflectionException
1480
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1481
-     */
1482
-    public function question_groups(array $query_params = []): array
1483
-    {
1484
-        $query_params = ! empty($query_params) ? $query_params : ['order_by' => ['QSG_order' => 'ASC']];
1485
-        return $this->get_many_related('Question_Group', $query_params);
1486
-    }
1487
-
1488
-
1489
-    /**
1490
-     * Implementation for EEI_Has_Icon interface method.
1491
-     *
1492
-     * @return string
1493
-     * @see EEI_Visual_Representation for comments
1494
-     */
1495
-    public function get_icon(): string
1496
-    {
1497
-        return '<span class="dashicons dashicons-flag"></span>';
1498
-    }
1499
-
1500
-
1501
-    /**
1502
-     * Implementation for EEI_Admin_Links interface method.
1503
-     *
1504
-     * @return string
1505
-     * @throws EE_Error
1506
-     * @throws ReflectionException
1507
-     * @see EEI_Admin_Links for comments
1508
-     */
1509
-    public function get_admin_details_link(): string
1510
-    {
1511
-        return $this->get_admin_edit_link();
1512
-    }
1513
-
1514
-
1515
-    /**
1516
-     * Implementation for EEI_Admin_Links interface method.
1517
-     *
1518
-     * @return string
1519
-     * @throws EE_Error
1520
-     * @throws ReflectionException
1521
-     * @see EEI_Admin_Links for comments
1522
-     */
1523
-    public function get_admin_edit_link(): string
1524
-    {
1525
-        return EEH_URL::add_query_args_and_nonce(
1526
-            [
1527
-                'page'   => 'espresso_events',
1528
-                'action' => 'edit',
1529
-                'post'   => $this->ID(),
1530
-            ],
1531
-            admin_url('admin.php')
1532
-        );
1533
-    }
1534
-
1535
-
1536
-    /**
1537
-     * Implementation for EEI_Admin_Links interface method.
1538
-     *
1539
-     * @return string
1540
-     * @see EEI_Admin_Links for comments
1541
-     */
1542
-    public function get_admin_settings_link(): string
1543
-    {
1544
-        return EEH_URL::add_query_args_and_nonce(
1545
-            [
1546
-                'page'   => 'espresso_events',
1547
-                'action' => 'default_event_settings',
1548
-            ],
1549
-            admin_url('admin.php')
1550
-        );
1551
-    }
1552
-
1553
-
1554
-    /**
1555
-     * Implementation for EEI_Admin_Links interface method.
1556
-     *
1557
-     * @return string
1558
-     * @see EEI_Admin_Links for comments
1559
-     */
1560
-    public function get_admin_overview_link(): string
1561
-    {
1562
-        return EEH_URL::add_query_args_and_nonce(
1563
-            [
1564
-                'page'   => 'espresso_events',
1565
-                'action' => 'default',
1566
-            ],
1567
-            admin_url('admin.php')
1568
-        );
1569
-    }
1570
-
1571
-
1572
-    /**
1573
-     * @return string|null
1574
-     * @throws EE_Error
1575
-     * @throws ReflectionException
1576
-     */
1577
-    public function registrationFormUuid(): ?string
1578
-    {
1579
-        return $this->get('FSC_UUID') ?? '';
1580
-    }
1581
-
1582
-
1583
-    /**
1584
-     * Gets all the form sections for this event
1585
-     *
1586
-     * @return EE_Base_Class[]|EE_Form_Section[]
1587
-     * @throws EE_Error
1588
-     * @throws ReflectionException
1589
-     */
1590
-    public function registrationForm(): array
1591
-    {
1592
-        $FSC_UUID = $this->registrationFormUuid();
1593
-
1594
-        if (empty($FSC_UUID)) {
1595
-            return [];
1596
-        }
1597
-
1598
-        return EEM_Form_Section::instance()->get_all(
1599
-            [
1600
-                [
1601
-                    'OR' => [
1602
-                        'FSC_UUID'      => $FSC_UUID, // top level form
1603
-                        'FSC_belongsTo' => $FSC_UUID, // child form sections
1604
-                    ],
1605
-                ],
1606
-                'order_by' => ['FSC_order' => 'ASC'],
1607
-            ]
1608
-        );
1609
-    }
1610
-
1611
-
1612
-    /**
1613
-     * @param string $UUID
1614
-     * @throws EE_Error
1615
-     * @throws ReflectionException
1616
-     */
1617
-    public function setRegistrationFormUuid(string $UUID): void
1618
-    {
1619
-        if (! Cuid::isCuid($UUID)) {
1620
-            throw new InvalidArgumentException(
1621
-                sprintf(
1622
-                /* translators: 1: UUID value, 2: UUID generator function. */
1623
-                    esc_html__(
1624
-                        'The supplied UUID "%1$s" is invalid or missing. Please use %2$s to generate a valid one.',
1625
-                        'event_espresso'
1626
-                    ),
1627
-                    $UUID,
1628
-                    '`Cuid::cuid()`'
1629
-                )
1630
-            );
1631
-        }
1632
-        $this->set('FSC_UUID', $UUID);
1633
-    }
1634
-
1635
-
1636
-    /**
1637
-     * Get visibility status of event
1638
-     *
1639
-     * @param bool $hide_public
1640
-     * @return string
1641
-     */
1642
-    public function get_visibility_status(bool $hide_public = true): string
1643
-    {
1644
-        if ($this->status() === 'private') {
1645
-            return esc_html__('Private', 'event_espresso');
1646
-        }
1647
-        if (! empty($this->wp_post()->post_password)) {
1648
-            return esc_html__('Password Protected', 'event_espresso');
1649
-        }
1650
-        if (! $hide_public) {
1651
-            return esc_html__('Public', 'event_espresso');
1652
-        }
1653
-
1654
-        return '';
1655
-    }
1250
+		if ($echo) {
1251
+			echo wp_kses($status, AllowedTags::getAllowedTags());
1252
+			return '';
1253
+		}
1254
+		return $status;
1255
+	}
1256
+
1257
+
1258
+	/**
1259
+	 * @return bool|int
1260
+	 * @throws EE_Error
1261
+	 * @throws ReflectionException
1262
+	 */
1263
+	public function get_number_of_tickets_sold()
1264
+	{
1265
+		$tkt_sold = 0;
1266
+		if (! $this->ID()) {
1267
+			return 0;
1268
+		}
1269
+		$datetimes = $this->datetimes();
1270
+		foreach ($datetimes as $datetime) {
1271
+			if ($datetime instanceof EE_Datetime) {
1272
+				$tkt_sold += $datetime->sold();
1273
+			}
1274
+		}
1275
+		return $tkt_sold;
1276
+	}
1277
+
1278
+
1279
+	/**
1280
+	 * This just returns a count of all the registrations for this event
1281
+	 *
1282
+	 * @return int
1283
+	 * @throws EE_Error
1284
+	 * @throws ReflectionException
1285
+	 */
1286
+	public function get_count_of_all_registrations(): int
1287
+	{
1288
+		return EEM_Event::instance()->count_related($this, 'Registration');
1289
+	}
1290
+
1291
+
1292
+	/**
1293
+	 * This returns the ticket with the earliest start time that is
1294
+	 * available for this event (across all datetimes attached to the event)
1295
+	 *
1296
+	 * @return EE_Base_Class|EE_Ticket|null
1297
+	 * @throws EE_Error
1298
+	 * @throws ReflectionException
1299
+	 */
1300
+	public function get_ticket_with_earliest_start_time()
1301
+	{
1302
+		$where['Datetime.EVT_ID'] = $this->ID();
1303
+		$query_params             = [$where, 'order_by' => ['TKT_start_date' => 'ASC']];
1304
+		return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1305
+	}
1306
+
1307
+
1308
+	/**
1309
+	 * This returns the ticket with the latest end time that is available
1310
+	 * for this event (across all datetimes attached to the event)
1311
+	 *
1312
+	 * @return EE_Base_Class|EE_Ticket|null
1313
+	 * @throws EE_Error
1314
+	 * @throws ReflectionException
1315
+	 */
1316
+	public function get_ticket_with_latest_end_time()
1317
+	{
1318
+		$where['Datetime.EVT_ID'] = $this->ID();
1319
+		$query_params             = [$where, 'order_by' => ['TKT_end_date' => 'DESC']];
1320
+		return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1321
+	}
1322
+
1323
+
1324
+	/**
1325
+	 * This returns the number of different ticket types currently on sale for this event.
1326
+	 *
1327
+	 * @return int
1328
+	 * @throws EE_Error
1329
+	 * @throws ReflectionException
1330
+	 */
1331
+	public function countTicketsOnSale(): int
1332
+	{
1333
+		$where = [
1334
+			'Datetime.EVT_ID' => $this->ID(),
1335
+			'TKT_start_date'  => ['<', time()],
1336
+			'TKT_end_date'    => ['>', time()],
1337
+		];
1338
+		return EEM_Ticket::instance()->count([$where]);
1339
+	}
1340
+
1341
+
1342
+	/**
1343
+	 * This returns whether there are any tickets on sale for this event.
1344
+	 *
1345
+	 * @return bool true = YES tickets on sale.
1346
+	 * @throws EE_Error
1347
+	 * @throws ReflectionException
1348
+	 */
1349
+	public function tickets_on_sale(): bool
1350
+	{
1351
+		return $this->countTicketsOnSale() > 0;
1352
+	}
1353
+
1354
+
1355
+	/**
1356
+	 * Gets the URL for viewing this event on the front-end. Overrides parent
1357
+	 * to check for an external URL first
1358
+	 *
1359
+	 * @return string
1360
+	 * @throws EE_Error
1361
+	 * @throws ReflectionException
1362
+	 */
1363
+	public function get_permalink(): string
1364
+	{
1365
+		if ($this->external_url()) {
1366
+			return $this->external_url();
1367
+		}
1368
+		return parent::get_permalink();
1369
+	}
1370
+
1371
+
1372
+	/**
1373
+	 * Gets the first term for 'espresso_event_categories' we can find
1374
+	 *
1375
+	 * @param array $query_params
1376
+	 * @return EE_Base_Class|EE_Term|null
1377
+	 * @throws EE_Error
1378
+	 * @throws ReflectionException
1379
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1380
+	 */
1381
+	public function first_event_category(array $query_params = []): ?EE_Term
1382
+	{
1383
+		$query_params[0]['Term_Taxonomy.taxonomy']     = 'espresso_event_categories';
1384
+		$query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1385
+		return EEM_Term::instance()->get_one($query_params);
1386
+	}
1387
+
1388
+
1389
+	/**
1390
+	 * Gets all terms for 'espresso_event_categories' we can find
1391
+	 *
1392
+	 * @param array $query_params
1393
+	 * @return EE_Base_Class[]|EE_Term[]
1394
+	 * @throws EE_Error
1395
+	 * @throws ReflectionException
1396
+	 */
1397
+	public function get_all_event_categories(array $query_params = []): array
1398
+	{
1399
+		$query_params[0]['Term_Taxonomy.taxonomy']     = 'espresso_event_categories';
1400
+		$query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1401
+		return EEM_Term::instance()->get_all($query_params);
1402
+	}
1403
+
1404
+
1405
+	/**
1406
+	 * Adds a question group to this event
1407
+	 *
1408
+	 * @param EE_Question_Group|int $question_group_id_or_obj
1409
+	 * @param bool                  $for_primary if true, the question group will be added for the primary
1410
+	 *                                           registrant, if false will be added for others. default: false
1411
+	 * @return EE_Base_Class|EE_Question_Group
1412
+	 * @throws EE_Error
1413
+	 * @throws InvalidArgumentException
1414
+	 * @throws InvalidDataTypeException
1415
+	 * @throws InvalidInterfaceException
1416
+	 * @throws ReflectionException
1417
+	 */
1418
+	public function add_question_group($question_group_id_or_obj, bool $for_primary = false): EE_Question_Group
1419
+	{
1420
+		// If the row already exists, it will be updated. If it doesn't, it will be inserted.
1421
+		// That's in EE_HABTM_Relation::add_relation_to().
1422
+		return $this->_add_relation_to(
1423
+			$question_group_id_or_obj,
1424
+			'Question_Group',
1425
+			[
1426
+				EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary) => true,
1427
+			]
1428
+		);
1429
+	}
1430
+
1431
+
1432
+	/**
1433
+	 * Removes a question group from the event
1434
+	 *
1435
+	 * @param EE_Question_Group|int $question_group_id_or_obj
1436
+	 * @param bool                  $for_primary if true, the question group will be removed from the primary
1437
+	 *                                           registrant, if false will be removed from others. default: false
1438
+	 * @return EE_Base_Class|EE_Question_Group|int
1439
+	 * @throws EE_Error
1440
+	 * @throws InvalidArgumentException
1441
+	 * @throws ReflectionException
1442
+	 * @throws InvalidDataTypeException
1443
+	 * @throws InvalidInterfaceException
1444
+	 */
1445
+	public function remove_question_group($question_group_id_or_obj, bool $for_primary = false)
1446
+	{
1447
+		// If the question group is used for the other type (primary or additional)
1448
+		// then just update it. If not, delete it outright.
1449
+		$existing_relation = $this->get_first_related(
1450
+			'Event_Question_Group',
1451
+			[
1452
+				[
1453
+					'QSG_ID' => EEM_Question_Group::instance()->ensure_is_ID($question_group_id_or_obj),
1454
+				],
1455
+			]
1456
+		);
1457
+		$field_to_update   = EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary);
1458
+		$other_field       = EEM_Event_Question_Group::instance()->fieldNameForContext(! $for_primary);
1459
+		if ($existing_relation->get($other_field) === false) {
1460
+			// Delete it. It's now no longer for primary or additional question groups.
1461
+			return $this->_remove_relation_to($question_group_id_or_obj, 'Question_Group');
1462
+		}
1463
+		// Just update it. They'll still use this question group for the other category
1464
+		$existing_relation->save(
1465
+			[
1466
+				$field_to_update => false,
1467
+			]
1468
+		);
1469
+		return $question_group_id_or_obj;
1470
+	}
1471
+
1472
+
1473
+	/**
1474
+	 * Gets all the question groups, ordering them by QSG_order ascending
1475
+	 *
1476
+	 * @param array $query_params
1477
+	 * @return EE_Base_Class[]|EE_Question_Group[]
1478
+	 * @throws EE_Error
1479
+	 * @throws ReflectionException
1480
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1481
+	 */
1482
+	public function question_groups(array $query_params = []): array
1483
+	{
1484
+		$query_params = ! empty($query_params) ? $query_params : ['order_by' => ['QSG_order' => 'ASC']];
1485
+		return $this->get_many_related('Question_Group', $query_params);
1486
+	}
1487
+
1488
+
1489
+	/**
1490
+	 * Implementation for EEI_Has_Icon interface method.
1491
+	 *
1492
+	 * @return string
1493
+	 * @see EEI_Visual_Representation for comments
1494
+	 */
1495
+	public function get_icon(): string
1496
+	{
1497
+		return '<span class="dashicons dashicons-flag"></span>';
1498
+	}
1499
+
1500
+
1501
+	/**
1502
+	 * Implementation for EEI_Admin_Links interface method.
1503
+	 *
1504
+	 * @return string
1505
+	 * @throws EE_Error
1506
+	 * @throws ReflectionException
1507
+	 * @see EEI_Admin_Links for comments
1508
+	 */
1509
+	public function get_admin_details_link(): string
1510
+	{
1511
+		return $this->get_admin_edit_link();
1512
+	}
1513
+
1514
+
1515
+	/**
1516
+	 * Implementation for EEI_Admin_Links interface method.
1517
+	 *
1518
+	 * @return string
1519
+	 * @throws EE_Error
1520
+	 * @throws ReflectionException
1521
+	 * @see EEI_Admin_Links for comments
1522
+	 */
1523
+	public function get_admin_edit_link(): string
1524
+	{
1525
+		return EEH_URL::add_query_args_and_nonce(
1526
+			[
1527
+				'page'   => 'espresso_events',
1528
+				'action' => 'edit',
1529
+				'post'   => $this->ID(),
1530
+			],
1531
+			admin_url('admin.php')
1532
+		);
1533
+	}
1534
+
1535
+
1536
+	/**
1537
+	 * Implementation for EEI_Admin_Links interface method.
1538
+	 *
1539
+	 * @return string
1540
+	 * @see EEI_Admin_Links for comments
1541
+	 */
1542
+	public function get_admin_settings_link(): string
1543
+	{
1544
+		return EEH_URL::add_query_args_and_nonce(
1545
+			[
1546
+				'page'   => 'espresso_events',
1547
+				'action' => 'default_event_settings',
1548
+			],
1549
+			admin_url('admin.php')
1550
+		);
1551
+	}
1552
+
1553
+
1554
+	/**
1555
+	 * Implementation for EEI_Admin_Links interface method.
1556
+	 *
1557
+	 * @return string
1558
+	 * @see EEI_Admin_Links for comments
1559
+	 */
1560
+	public function get_admin_overview_link(): string
1561
+	{
1562
+		return EEH_URL::add_query_args_and_nonce(
1563
+			[
1564
+				'page'   => 'espresso_events',
1565
+				'action' => 'default',
1566
+			],
1567
+			admin_url('admin.php')
1568
+		);
1569
+	}
1570
+
1571
+
1572
+	/**
1573
+	 * @return string|null
1574
+	 * @throws EE_Error
1575
+	 * @throws ReflectionException
1576
+	 */
1577
+	public function registrationFormUuid(): ?string
1578
+	{
1579
+		return $this->get('FSC_UUID') ?? '';
1580
+	}
1581
+
1582
+
1583
+	/**
1584
+	 * Gets all the form sections for this event
1585
+	 *
1586
+	 * @return EE_Base_Class[]|EE_Form_Section[]
1587
+	 * @throws EE_Error
1588
+	 * @throws ReflectionException
1589
+	 */
1590
+	public function registrationForm(): array
1591
+	{
1592
+		$FSC_UUID = $this->registrationFormUuid();
1593
+
1594
+		if (empty($FSC_UUID)) {
1595
+			return [];
1596
+		}
1597
+
1598
+		return EEM_Form_Section::instance()->get_all(
1599
+			[
1600
+				[
1601
+					'OR' => [
1602
+						'FSC_UUID'      => $FSC_UUID, // top level form
1603
+						'FSC_belongsTo' => $FSC_UUID, // child form sections
1604
+					],
1605
+				],
1606
+				'order_by' => ['FSC_order' => 'ASC'],
1607
+			]
1608
+		);
1609
+	}
1610
+
1611
+
1612
+	/**
1613
+	 * @param string $UUID
1614
+	 * @throws EE_Error
1615
+	 * @throws ReflectionException
1616
+	 */
1617
+	public function setRegistrationFormUuid(string $UUID): void
1618
+	{
1619
+		if (! Cuid::isCuid($UUID)) {
1620
+			throw new InvalidArgumentException(
1621
+				sprintf(
1622
+				/* translators: 1: UUID value, 2: UUID generator function. */
1623
+					esc_html__(
1624
+						'The supplied UUID "%1$s" is invalid or missing. Please use %2$s to generate a valid one.',
1625
+						'event_espresso'
1626
+					),
1627
+					$UUID,
1628
+					'`Cuid::cuid()`'
1629
+				)
1630
+			);
1631
+		}
1632
+		$this->set('FSC_UUID', $UUID);
1633
+	}
1634
+
1635
+
1636
+	/**
1637
+	 * Get visibility status of event
1638
+	 *
1639
+	 * @param bool $hide_public
1640
+	 * @return string
1641
+	 */
1642
+	public function get_visibility_status(bool $hide_public = true): string
1643
+	{
1644
+		if ($this->status() === 'private') {
1645
+			return esc_html__('Private', 'event_espresso');
1646
+		}
1647
+		if (! empty($this->wp_post()->post_password)) {
1648
+			return esc_html__('Password Protected', 'event_espresso');
1649
+		}
1650
+		if (! $hide_public) {
1651
+			return esc_html__('Public', 'event_espresso');
1652
+		}
1653
+
1654
+		return '';
1655
+	}
1656 1656
 }
Please login to merge, or discard this patch.
core/services/request/DataType.php 1 patch
Indentation   +42 added lines, -42 removed lines patch added patch discarded remove patch
@@ -12,59 +12,59 @@
 block discarded – undo
12 12
  */
13 13
 class DataType
14 14
 {
15
-    const ARRAY   = 'array';
15
+	const ARRAY   = 'array';
16 16
 
17
-    const BOOL    = 'bool';
18
-    const BOOLEAN = 'bool';
17
+	const BOOL    = 'bool';
18
+	const BOOLEAN = 'bool';
19 19
 
20
-    const DOUBLE  = 'float';
21
-    const FLOAT   = 'float';
20
+	const DOUBLE  = 'float';
21
+	const FLOAT   = 'float';
22 22
 
23
-    const EDITOR  = 'editor';
24
-    const FQCN    = 'fqcn';
23
+	const EDITOR  = 'editor';
24
+	const FQCN    = 'fqcn';
25 25
 
26
-    const HTML    = 'html';
26
+	const HTML    = 'html';
27 27
 
28
-    const INT     = 'int';
29
-    const INTEGER = 'int';
28
+	const INT     = 'int';
29
+	const INTEGER = 'int';
30 30
 
31
-    const KEY     = 'key';
31
+	const KEY     = 'key';
32 32
 
33
-    const OBJECT  = 'object';
33
+	const OBJECT  = 'object';
34 34
 
35
-    const NULL    = 'null';
35
+	const NULL    = 'null';
36 36
 
37
-    const TITLE   = 'title';
37
+	const TITLE   = 'title';
38 38
 
39
-    const URL     = 'url';
39
+	const URL     = 'url';
40 40
 
41
-    const STRING  = 'string';
41
+	const STRING  = 'string';
42 42
 
43 43
 
44
-    /**
45
-     * @param mixed  $param
46
-     * @param string $type
47
-     * @return mixed
48
-     */
49
-    public static function setDataType($param, string $type)
50
-    {
51
-        switch ($type) {
52
-            case DataType::NULL:
53
-                return null;
54
-            case DataType::OBJECT:
55
-                return $param;
56
-            case DataType::EDITOR:
57
-            case DataType::FQCN:
58
-            case DataType::HTML:
59
-            case DataType::KEY:
60
-            case DataType::STRING:
61
-            case DataType::TITLE:
62
-            case DataType::URL:
63
-                settype($param, DataType::STRING);
64
-                break;
65
-            default:
66
-                settype($param, $type);
67
-        }
68
-        return $param;
69
-    }
44
+	/**
45
+	 * @param mixed  $param
46
+	 * @param string $type
47
+	 * @return mixed
48
+	 */
49
+	public static function setDataType($param, string $type)
50
+	{
51
+		switch ($type) {
52
+			case DataType::NULL:
53
+				return null;
54
+			case DataType::OBJECT:
55
+				return $param;
56
+			case DataType::EDITOR:
57
+			case DataType::FQCN:
58
+			case DataType::HTML:
59
+			case DataType::KEY:
60
+			case DataType::STRING:
61
+			case DataType::TITLE:
62
+			case DataType::URL:
63
+				settype($param, DataType::STRING);
64
+				break;
65
+			default:
66
+				settype($param, $type);
67
+		}
68
+		return $param;
69
+	}
70 70
 }
Please login to merge, or discard this patch.
core/services/request/sanitizers/RequestSanitizer.php 1 patch
Indentation   +64 added lines, -64 removed lines patch added patch discarded remove patch
@@ -6,70 +6,70 @@
 block discarded – undo
6 6
 
7 7
 class RequestSanitizer
8 8
 {
9
-    /**
10
-     * Will sanitize the supplied request parameter based on the specified data type
11
-     *
12
-     * @param mixed  $param     the supplied request parameter
13
-     * @param string $type      the specified data type (default: "string")
14
-     *                          valid values: "bool", "float", "int", "key", "url", or "string"
15
-     * @param bool   $is_array  if true, then $param will be treated as an array of $type
16
-     * @param string $delimiter if $param is a CSV like value (ex: 1,2,3,4,5...) then this is the value separator
17
-     * @return array|bool|float|int|string
18
-     * @since 4.10.14.p
19
-     */
20
-    public function clean($param, $type = DataType::STRING, $is_array = false, $delimiter = '')
21
-    {
22
-        if ($delimiter !== '' && is_string($param)) {
23
-            $param = explode($delimiter, $param);
24
-            $is_array = is_array($param);
25
-            // unset the delimiter else this function will recurse forever when we loop over the array of results
26
-            $delimiter = '';
27
-        }
28
-        // check if we are getting an improperly typed array and correct
29
-        $is_array = $is_array && is_array($param);
30
-        if ($is_array) {
31
-            $values = [];
32
-            foreach ((array) $param as $key => $value) {
33
-                $values[ $key ] = $this->clean($value, $type, is_array($value), $delimiter);
34
-            }
35
-            return $values;
36
-        }
37
-        return $this->sanitizeParam($param, $type);
38
-    }
9
+	/**
10
+	 * Will sanitize the supplied request parameter based on the specified data type
11
+	 *
12
+	 * @param mixed  $param     the supplied request parameter
13
+	 * @param string $type      the specified data type (default: "string")
14
+	 *                          valid values: "bool", "float", "int", "key", "url", or "string"
15
+	 * @param bool   $is_array  if true, then $param will be treated as an array of $type
16
+	 * @param string $delimiter if $param is a CSV like value (ex: 1,2,3,4,5...) then this is the value separator
17
+	 * @return array|bool|float|int|string
18
+	 * @since 4.10.14.p
19
+	 */
20
+	public function clean($param, $type = DataType::STRING, $is_array = false, $delimiter = '')
21
+	{
22
+		if ($delimiter !== '' && is_string($param)) {
23
+			$param = explode($delimiter, $param);
24
+			$is_array = is_array($param);
25
+			// unset the delimiter else this function will recurse forever when we loop over the array of results
26
+			$delimiter = '';
27
+		}
28
+		// check if we are getting an improperly typed array and correct
29
+		$is_array = $is_array && is_array($param);
30
+		if ($is_array) {
31
+			$values = [];
32
+			foreach ((array) $param as $key => $value) {
33
+				$values[ $key ] = $this->clean($value, $type, is_array($value), $delimiter);
34
+			}
35
+			return $values;
36
+		}
37
+		return $this->sanitizeParam($param, $type);
38
+	}
39 39
 
40 40
 
41
-    /**
42
-     * @param mixed  $param
43
-     * @param string $type
44
-     * @return array|float|int|mixed|string|string[]|null
45
-     * @since   4.10.20.p
46
-     */
47
-    public function sanitizeParam($param, $type = DataType::STRING)
48
-    {
49
-        switch ($type) {
50
-            case DataType::BOOL:
51
-                return filter_var($param, FILTER_VALIDATE_BOOLEAN);
52
-            case DataType::EDITOR:
53
-                $allowed_tags = AllowedTags::getWithFullTags();
54
-                return wp_kses($param, $allowed_tags);
55
-            case DataType::FLOAT:
56
-                return (float) $param;
57
-            case DataType::FQCN:
58
-                return preg_replace('[^\\\w\d]', '', $param);
59
-            case DataType::HTML:
60
-                $allowed_tags = AllowedTags::getAllowedTags();
61
-                return wp_kses($param, $allowed_tags);
62
-            case DataType::INT:
63
-                return (int) $param;
64
-            case DataType::KEY:
65
-                return sanitize_key($param);
66
-            case DataType::TITLE:
67
-                return sanitize_title($param);
68
-            case DataType::URL:
69
-                return esc_url_raw($param);
70
-            case DataType::STRING:
71
-            default:
72
-                return sanitize_text_field($param);
73
-        }
74
-    }
41
+	/**
42
+	 * @param mixed  $param
43
+	 * @param string $type
44
+	 * @return array|float|int|mixed|string|string[]|null
45
+	 * @since   4.10.20.p
46
+	 */
47
+	public function sanitizeParam($param, $type = DataType::STRING)
48
+	{
49
+		switch ($type) {
50
+			case DataType::BOOL:
51
+				return filter_var($param, FILTER_VALIDATE_BOOLEAN);
52
+			case DataType::EDITOR:
53
+				$allowed_tags = AllowedTags::getWithFullTags();
54
+				return wp_kses($param, $allowed_tags);
55
+			case DataType::FLOAT:
56
+				return (float) $param;
57
+			case DataType::FQCN:
58
+				return preg_replace('[^\\\w\d]', '', $param);
59
+			case DataType::HTML:
60
+				$allowed_tags = AllowedTags::getAllowedTags();
61
+				return wp_kses($param, $allowed_tags);
62
+			case DataType::INT:
63
+				return (int) $param;
64
+			case DataType::KEY:
65
+				return sanitize_key($param);
66
+			case DataType::TITLE:
67
+				return sanitize_title($param);
68
+			case DataType::URL:
69
+				return esc_url_raw($param);
70
+			case DataType::STRING:
71
+			default:
72
+				return sanitize_text_field($param);
73
+		}
74
+	}
75 75
 }
Please login to merge, or discard this patch.