Completed
Branch dev (b3855f)
by
unknown
13:34 queued 05:26
created
core/db_classes/EE_Event.class.php 1 patch
Indentation   +1593 added lines, -1593 removed lines patch added patch discarded remove patch
@@ -16,1600 +16,1600 @@
 block discarded – undo
16 16
  */
17 17
 class EE_Event extends EE_CPT_Base implements EEI_Line_Item_Object, EEI_Admin_Links, EEI_Has_Icon, EEI_Event
18 18
 {
19
-    /**
20
-     * cached value for the the logical active status for the event
21
-     *
22
-     * @see get_active_status()
23
-     * @var string
24
-     */
25
-    protected $_active_status = '';
26
-
27
-    /**
28
-     * This is just used for caching the Primary Datetime for the Event on initial retrieval
29
-     *
30
-     * @var EE_Datetime
31
-     */
32
-    protected $_Primary_Datetime;
33
-
34
-    /**
35
-     * @var EventSpacesCalculator $available_spaces_calculator
36
-     */
37
-    protected $available_spaces_calculator;
38
-
39
-
40
-    /**
41
-     * @param array  $props_n_values          incoming values
42
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
43
-     *                                        used.)
44
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
45
-     *                                        date_format and the second value is the time format
46
-     * @return EE_Event
47
-     * @throws EE_Error
48
-     * @throws ReflectionException
49
-     */
50
-    public static function new_instance($props_n_values = [], $timezone = null, $date_formats = []): EE_Event
51
-    {
52
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
53
-        return $has_object ?: new self($props_n_values, false, $timezone, $date_formats);
54
-    }
55
-
56
-
57
-    /**
58
-     * @param array  $props_n_values  incoming values from the database
59
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
60
-     *                                the website will be used.
61
-     * @return EE_Event
62
-     * @throws EE_Error
63
-     * @throws ReflectionException
64
-     */
65
-    public static function new_instance_from_db($props_n_values = [], $timezone = null): EE_Event
66
-    {
67
-        return new self($props_n_values, true, $timezone);
68
-    }
69
-
70
-
71
-    /**
72
-     * @return EventSpacesCalculator
73
-     * @throws EE_Error
74
-     * @throws ReflectionException
75
-     */
76
-    public function getAvailableSpacesCalculator(): EventSpacesCalculator
77
-    {
78
-        if (! $this->available_spaces_calculator instanceof EventSpacesCalculator) {
79
-            $this->available_spaces_calculator = new EventSpacesCalculator($this);
80
-        }
81
-        return $this->available_spaces_calculator;
82
-    }
83
-
84
-
85
-    /**
86
-     * Overrides parent set() method so that all calls to set( 'status', $status ) can be routed to internal methods
87
-     *
88
-     * @param string $field_name
89
-     * @param mixed  $field_value
90
-     * @param bool   $use_default
91
-     * @throws EE_Error
92
-     * @throws ReflectionException
93
-     */
94
-    public function set($field_name, $field_value, $use_default = false)
95
-    {
96
-        switch ($field_name) {
97
-            case 'status':
98
-                $this->set_status($field_value, $use_default);
99
-                break;
100
-            default:
101
-                parent::set($field_name, $field_value, $use_default);
102
-        }
103
-    }
104
-
105
-
106
-    /**
107
-     *    set_status
108
-     * Checks if event status is being changed to SOLD OUT
109
-     * and updates event meta data with previous event status
110
-     * so that we can revert things if/when the event is no longer sold out
111
-     *
112
-     * @param string $status
113
-     * @param bool   $use_default
114
-     * @return void
115
-     * @throws EE_Error
116
-     * @throws ReflectionException
117
-     */
118
-    public function set_status($status = '', $use_default = false)
119
-    {
120
-        // if nothing is set, and we aren't explicitly wanting to reset the status, then just leave
121
-        if (empty($status) && ! $use_default) {
122
-            return;
123
-        }
124
-        // get current Event status
125
-        $old_status = $this->status();
126
-        // if status has changed
127
-        if ($old_status !== $status) {
128
-            // TO sold_out
129
-            if ($status === EEM_Event::sold_out) {
130
-                // save the previous event status so that we can revert if the event is no longer sold out
131
-                $this->add_post_meta('_previous_event_status', $old_status);
132
-                do_action('AHEE__EE_Event__set_status__to_sold_out', $this, $old_status, $status);
133
-                // OR FROM  sold_out
134
-            } elseif ($old_status === EEM_Event::sold_out) {
135
-                $this->delete_post_meta('_previous_event_status');
136
-                do_action('AHEE__EE_Event__set_status__from_sold_out', $this, $old_status, $status);
137
-            }
138
-            // clear out the active status so that it gets reset the next time it is requested
139
-            $this->_active_status = null;
140
-            // update status
141
-            parent::set('status', $status, $use_default);
142
-            do_action('AHEE__EE_Event__set_status__after_update', $this);
143
-            return;
144
-        }
145
-        // even though the old value matches the new value, it's still good to
146
-        // allow the parent set method to have a say
147
-        parent::set('status', $status, $use_default);
148
-    }
149
-
150
-
151
-    /**
152
-     * Gets all the datetimes for this event
153
-     *
154
-     * @param array|null $query_params
155
-     * @return EE_Base_Class[]|EE_Datetime[]
156
-     * @throws EE_Error
157
-     * @throws ReflectionException
158
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
159
-     */
160
-    public function datetimes(?array $query_params = []): array
161
-    {
162
-        return $this->get_many_related('Datetime', $query_params);
163
-    }
164
-
165
-
166
-    /**
167
-     * Gets all the datetimes for this event that are currently ACTIVE,
168
-     * meaning the datetime has started and has not yet ended.
169
-     *
170
-     * @param int|null   $start_date   timestamp to use for event date start time, defaults to NOW unless set to 0
171
-     * @param array|null $query_params will recursively replace default values
172
-     * @throws EE_Error
173
-     * @throws ReflectionException
174
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
175
-     */
176
-    public function activeDatetimes(?int $start_date, ?array $query_params = []): array
177
-    {
178
-        // if start date is null, then use current time
179
-        $start_date = $start_date ?? time();
180
-        $where      = [];
181
-        if ($start_date) {
182
-            $where['DTT_EVT_start'] = ['<', $start_date];
183
-            $where['DTT_EVT_end']   = ['>', time()];
184
-        }
185
-        $query_params = array_replace_recursive(
186
-            [
187
-                $where,
188
-                'order_by' => ['DTT_EVT_start' => 'ASC'],
189
-            ],
190
-            $query_params
191
-        );
192
-        return $this->get_many_related('Datetime', $query_params);
193
-    }
194
-
195
-
196
-    /**
197
-     * Gets all the datetimes for this event, ordered by DTT_EVT_start in ascending order
198
-     *
199
-     * @return EE_Base_Class[]|EE_Datetime[]
200
-     * @throws EE_Error
201
-     * @throws ReflectionException
202
-     */
203
-    public function datetimes_in_chronological_order(): array
204
-    {
205
-        return $this->get_many_related('Datetime', ['order_by' => ['DTT_EVT_start' => 'ASC']]);
206
-    }
207
-
208
-
209
-    /**
210
-     * Gets all the datetimes for this event, ordered by the DTT_order on the datetime.
211
-     * @darren, we should probably UNSET timezone on the EEM_Datetime model
212
-     * after running our query, so that this timezone isn't set for EVERY query
213
-     * on EEM_Datetime for the rest of the request, no?
214
-     *
215
-     * @param bool     $show_expired whether or not to include expired events
216
-     * @param bool     $show_deleted whether or not to include deleted events
217
-     * @param int|null $limit
218
-     * @return EE_Datetime[]
219
-     * @throws EE_Error
220
-     * @throws ReflectionException
221
-     */
222
-    public function datetimes_ordered(bool $show_expired = true, bool $show_deleted = false, ?int $limit = null): array
223
-    {
224
-        return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_event_ordered_by_DTT_order(
225
-            $this->ID(),
226
-            $show_expired,
227
-            $show_deleted,
228
-            $limit
229
-        );
230
-    }
231
-
232
-
233
-    /**
234
-     * Returns one related datetime. Mostly only used by some legacy code.
235
-     *
236
-     * @return EE_Base_Class|EE_Datetime
237
-     * @throws EE_Error
238
-     * @throws ReflectionException
239
-     */
240
-    public function first_datetime(): EE_Datetime
241
-    {
242
-        return $this->get_first_related('Datetime');
243
-    }
244
-
245
-
246
-    /**
247
-     * Returns the 'primary' datetime for the event
248
-     *
249
-     * @param bool $try_to_exclude_expired
250
-     * @param bool $try_to_exclude_deleted
251
-     * @return EE_Datetime|null
252
-     * @throws EE_Error
253
-     * @throws ReflectionException
254
-     */
255
-    public function primary_datetime(
256
-        bool $try_to_exclude_expired = true,
257
-        bool $try_to_exclude_deleted = true
258
-    ): ?EE_Datetime {
259
-        if (! empty($this->_Primary_Datetime)) {
260
-            return $this->_Primary_Datetime;
261
-        }
262
-        $this->_Primary_Datetime = EEM_Datetime::instance($this->_timezone)->get_primary_datetime_for_event(
263
-            $this->ID(),
264
-            $try_to_exclude_expired,
265
-            $try_to_exclude_deleted
266
-        );
267
-        return $this->_Primary_Datetime;
268
-    }
269
-
270
-
271
-    /**
272
-     * Gets all the tickets available for purchase of this event
273
-     *
274
-     * @param array|null $query_params
275
-     * @return EE_Base_Class[]|EE_Ticket[]
276
-     * @throws EE_Error
277
-     * @throws ReflectionException
278
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
279
-     */
280
-    public function tickets(?array $query_params = []): array
281
-    {
282
-        // first get all datetimes
283
-        $datetimes = $this->datetimes_ordered();
284
-        if (! $datetimes) {
285
-            return [];
286
-        }
287
-        $datetime_ids = [];
288
-        foreach ($datetimes as $datetime) {
289
-            $datetime_ids[] = $datetime->ID();
290
-        }
291
-        $where_params = ['Datetime.DTT_ID' => ['IN', $datetime_ids]];
292
-        // if incoming $query_params has where conditions let's merge but not override existing.
293
-        if (is_array($query_params) && isset($query_params[0])) {
294
-            $where_params = array_merge($query_params[0], $where_params);
295
-            unset($query_params[0]);
296
-        }
297
-        // now add $where_params to $query_params
298
-        $query_params[0] = $where_params;
299
-        return EEM_Ticket::instance()->get_all($query_params);
300
-    }
301
-
302
-
303
-    /**
304
-     * get all unexpired not-trashed tickets
305
-     *
306
-     * @return EE_Ticket[]
307
-     * @throws EE_Error
308
-     * @throws ReflectionException
309
-     */
310
-    public function active_tickets(): array
311
-    {
312
-        return $this->tickets(
313
-            [
314
-                [
315
-                    'TKT_end_date' => ['>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')],
316
-                    'TKT_deleted'  => false,
317
-                ],
318
-            ]
319
-        );
320
-    }
321
-
322
-
323
-    /**
324
-     * @return int
325
-     * @throws EE_Error
326
-     * @throws ReflectionException
327
-     */
328
-    public function additional_limit(): int
329
-    {
330
-        return $this->get('EVT_additional_limit');
331
-    }
332
-
333
-
334
-    /**
335
-     * @return bool
336
-     * @throws EE_Error
337
-     * @throws ReflectionException
338
-     */
339
-    public function allow_overflow(): bool
340
-    {
341
-        return $this->get('EVT_allow_overflow');
342
-    }
343
-
344
-
345
-    /**
346
-     * @return string
347
-     * @throws EE_Error
348
-     * @throws ReflectionException
349
-     */
350
-    public function created(): string
351
-    {
352
-        return $this->get('EVT_created');
353
-    }
354
-
355
-
356
-    /**
357
-     * @return string
358
-     * @throws EE_Error
359
-     * @throws ReflectionException
360
-     */
361
-    public function description(): string
362
-    {
363
-        return $this->get('EVT_desc');
364
-    }
365
-
366
-
367
-    /**
368
-     * Runs do_shortcode and wpautop on the description
369
-     *
370
-     * @return string of html
371
-     * @throws EE_Error
372
-     * @throws ReflectionException
373
-     */
374
-    public function description_filtered(): string
375
-    {
376
-        return $this->get_pretty('EVT_desc');
377
-    }
378
-
379
-
380
-    /**
381
-     * @return bool
382
-     * @throws EE_Error
383
-     * @throws ReflectionException
384
-     */
385
-    public function display_description(): bool
386
-    {
387
-        return $this->get('EVT_display_desc');
388
-    }
389
-
390
-
391
-    /**
392
-     * @return bool
393
-     * @throws EE_Error
394
-     * @throws ReflectionException
395
-     */
396
-    public function display_ticket_selector(): bool
397
-    {
398
-        return (bool) $this->get('EVT_display_ticket_selector');
399
-    }
400
-
401
-
402
-    /**
403
-     * @return string
404
-     * @throws EE_Error
405
-     * @throws ReflectionException
406
-     */
407
-    public function external_url(): string
408
-    {
409
-        return $this->get('EVT_external_URL');
410
-    }
411
-
412
-
413
-    /**
414
-     * @return bool
415
-     * @throws EE_Error
416
-     * @throws ReflectionException
417
-     */
418
-    public function member_only(): bool
419
-    {
420
-        return $this->get('EVT_member_only');
421
-    }
422
-
423
-
424
-    /**
425
-     * @return string
426
-     * @throws EE_Error
427
-     * @throws ReflectionException
428
-     */
429
-    public function phone(): string
430
-    {
431
-        return $this->get('EVT_phone');
432
-    }
433
-
434
-
435
-    /**
436
-     * @return string
437
-     * @throws EE_Error
438
-     * @throws ReflectionException
439
-     */
440
-    public function modified(): string
441
-    {
442
-        return $this->get('EVT_modified');
443
-    }
444
-
445
-
446
-    /**
447
-     * @return string
448
-     * @throws EE_Error
449
-     * @throws ReflectionException
450
-     */
451
-    public function name(): string
452
-    {
453
-        return $this->get('EVT_name');
454
-    }
455
-
456
-
457
-    /**
458
-     * @return int
459
-     * @throws EE_Error
460
-     * @throws ReflectionException
461
-     */
462
-    public function order(): int
463
-    {
464
-        return $this->get('EVT_order');
465
-    }
466
-
467
-
468
-    /**
469
-     * @return string
470
-     * @throws EE_Error
471
-     * @throws ReflectionException
472
-     */
473
-    public function default_registration_status(): string
474
-    {
475
-        $event_default_registration_status = $this->get('EVT_default_registration_status');
476
-        return ! empty($event_default_registration_status)
477
-            ? $event_default_registration_status
478
-            : EE_Registry::instance()->CFG->registration->default_STS_ID;
479
-    }
480
-
481
-
482
-    /**
483
-     * @param int|null    $num_words
484
-     * @param string|null $more
485
-     * @param bool        $not_full_desc
486
-     * @return string
487
-     * @throws EE_Error
488
-     * @throws ReflectionException
489
-     */
490
-    public function short_description(?int $num_words = 55, string $more = null, bool $not_full_desc = false): string
491
-    {
492
-        $short_desc = $this->get('EVT_short_desc');
493
-        if (! empty($short_desc) || $not_full_desc) {
494
-            return $short_desc;
495
-        }
496
-        $full_desc = $this->get('EVT_desc');
497
-        return wp_trim_words($full_desc, $num_words, $more);
498
-    }
499
-
500
-
501
-    /**
502
-     * @return string
503
-     * @throws EE_Error
504
-     * @throws ReflectionException
505
-     */
506
-    public function slug(): string
507
-    {
508
-        return $this->get('EVT_slug');
509
-    }
510
-
511
-
512
-    /**
513
-     * @return string
514
-     * @throws EE_Error
515
-     * @throws ReflectionException
516
-     */
517
-    public function timezone_string(): string
518
-    {
519
-        return $this->get('EVT_timezone_string');
520
-    }
521
-
522
-
523
-    /**
524
-     * @return string
525
-     * @throws EE_Error
526
-     * @throws ReflectionException
527
-     */
528
-    public function visible_on(): string
529
-    {
530
-        return $this->get('EVT_visible_on');
531
-    }
532
-
533
-
534
-    /**
535
-     * @return int
536
-     * @throws EE_Error
537
-     * @throws ReflectionException
538
-     */
539
-    public function wp_user(): int
540
-    {
541
-        return $this->get('EVT_wp_user');
542
-    }
543
-
544
-
545
-    /**
546
-     * @return bool
547
-     * @throws EE_Error
548
-     * @throws ReflectionException
549
-     */
550
-    public function donations(): bool
551
-    {
552
-        return $this->get('EVT_donations');
553
-    }
554
-
555
-
556
-    /**
557
-     * @param int $limit
558
-     * @throws EE_Error
559
-     * @throws ReflectionException
560
-     */
561
-    public function set_additional_limit(int $limit)
562
-    {
563
-        $this->set('EVT_additional_limit', $limit);
564
-    }
565
-
566
-
567
-    /**
568
-     * @param $created
569
-     * @throws EE_Error
570
-     * @throws ReflectionException
571
-     */
572
-    public function set_created($created)
573
-    {
574
-        $this->set('EVT_created', $created);
575
-    }
576
-
577
-
578
-    /**
579
-     * @param $desc
580
-     * @throws EE_Error
581
-     * @throws ReflectionException
582
-     */
583
-    public function set_description($desc)
584
-    {
585
-        $this->set('EVT_desc', $desc);
586
-    }
587
-
588
-
589
-    /**
590
-     * @param $display_desc
591
-     * @throws EE_Error
592
-     * @throws ReflectionException
593
-     */
594
-    public function set_display_description($display_desc)
595
-    {
596
-        $this->set('EVT_display_desc', $display_desc);
597
-    }
598
-
599
-
600
-    /**
601
-     * @param $display_ticket_selector
602
-     * @throws EE_Error
603
-     * @throws ReflectionException
604
-     */
605
-    public function set_display_ticket_selector($display_ticket_selector)
606
-    {
607
-        $this->set('EVT_display_ticket_selector', $display_ticket_selector);
608
-    }
609
-
610
-
611
-    /**
612
-     * @param $external_url
613
-     * @throws EE_Error
614
-     * @throws ReflectionException
615
-     */
616
-    public function set_external_url($external_url)
617
-    {
618
-        $this->set('EVT_external_URL', $external_url);
619
-    }
620
-
621
-
622
-    /**
623
-     * @param $member_only
624
-     * @throws EE_Error
625
-     * @throws ReflectionException
626
-     */
627
-    public function set_member_only($member_only)
628
-    {
629
-        $this->set('EVT_member_only', $member_only);
630
-    }
631
-
632
-
633
-    /**
634
-     * @param $event_phone
635
-     * @throws EE_Error
636
-     * @throws ReflectionException
637
-     */
638
-    public function set_event_phone($event_phone)
639
-    {
640
-        $this->set('EVT_phone', $event_phone);
641
-    }
642
-
643
-
644
-    /**
645
-     * @param $modified
646
-     * @throws EE_Error
647
-     * @throws ReflectionException
648
-     */
649
-    public function set_modified($modified)
650
-    {
651
-        $this->set('EVT_modified', $modified);
652
-    }
653
-
654
-
655
-    /**
656
-     * @param $name
657
-     * @throws EE_Error
658
-     * @throws ReflectionException
659
-     */
660
-    public function set_name($name)
661
-    {
662
-        $this->set('EVT_name', $name);
663
-    }
664
-
665
-
666
-    /**
667
-     * @param $order
668
-     * @throws EE_Error
669
-     * @throws ReflectionException
670
-     */
671
-    public function set_order($order)
672
-    {
673
-        $this->set('EVT_order', $order);
674
-    }
675
-
676
-
677
-    /**
678
-     * @param $short_desc
679
-     * @throws EE_Error
680
-     * @throws ReflectionException
681
-     */
682
-    public function set_short_description($short_desc)
683
-    {
684
-        $this->set('EVT_short_desc', $short_desc);
685
-    }
686
-
687
-
688
-    /**
689
-     * @param $slug
690
-     * @throws EE_Error
691
-     * @throws ReflectionException
692
-     */
693
-    public function set_slug($slug)
694
-    {
695
-        $this->set('EVT_slug', $slug);
696
-    }
697
-
698
-
699
-    /**
700
-     * @param $timezone_string
701
-     * @throws EE_Error
702
-     * @throws ReflectionException
703
-     */
704
-    public function set_timezone_string($timezone_string)
705
-    {
706
-        $this->set('EVT_timezone_string', $timezone_string);
707
-    }
708
-
709
-
710
-    /**
711
-     * @param $visible_on
712
-     * @throws EE_Error
713
-     * @throws ReflectionException
714
-     */
715
-    public function set_visible_on($visible_on)
716
-    {
717
-        $this->set('EVT_visible_on', $visible_on);
718
-    }
719
-
720
-
721
-    /**
722
-     * @param $wp_user
723
-     * @throws EE_Error
724
-     * @throws ReflectionException
725
-     */
726
-    public function set_wp_user($wp_user)
727
-    {
728
-        $this->set('EVT_wp_user', $wp_user);
729
-    }
730
-
731
-
732
-    /**
733
-     * @param $default_registration_status
734
-     * @throws EE_Error
735
-     * @throws ReflectionException
736
-     */
737
-    public function set_default_registration_status($default_registration_status)
738
-    {
739
-        $this->set('EVT_default_registration_status', $default_registration_status);
740
-    }
741
-
742
-
743
-    /**
744
-     * @param $donations
745
-     * @throws EE_Error
746
-     * @throws ReflectionException
747
-     */
748
-    public function set_donations($donations)
749
-    {
750
-        $this->set('EVT_donations', $donations);
751
-    }
752
-
753
-
754
-    /**
755
-     * Adds a venue to this event
756
-     *
757
-     * @param int|EE_Venue /int $venue_id_or_obj
758
-     * @return EE_Base_Class|EE_Venue
759
-     * @throws EE_Error
760
-     * @throws ReflectionException
761
-     */
762
-    public function add_venue($venue_id_or_obj): EE_Venue
763
-    {
764
-        return $this->_add_relation_to($venue_id_or_obj, 'Venue');
765
-    }
766
-
767
-
768
-    /**
769
-     * Removes a venue from the event
770
-     *
771
-     * @param EE_Venue /int $venue_id_or_obj
772
-     * @return EE_Base_Class|EE_Venue
773
-     * @throws EE_Error
774
-     * @throws ReflectionException
775
-     */
776
-    public function remove_venue($venue_id_or_obj): EE_Venue
777
-    {
778
-        $venue_id_or_obj = ! empty($venue_id_or_obj) ? $venue_id_or_obj : $this->venue();
779
-        return $this->_remove_relation_to($venue_id_or_obj, 'Venue');
780
-    }
781
-
782
-
783
-    /**
784
-     * Gets the venue related to the event. May provide additional $query_params if desired
785
-     *
786
-     * @param array $query_params
787
-     * @return int
788
-     * @throws EE_Error
789
-     * @throws ReflectionException
790
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
791
-     */
792
-    public function venue_ID(array $query_params = []): int
793
-    {
794
-        $venue = $this->get_first_related('Venue', $query_params);
795
-        return $venue instanceof EE_Venue ? $venue->ID() : 0;
796
-    }
797
-
798
-
799
-    /**
800
-     * Gets the venue related to the event. May provide additional $query_params if desired
801
-     *
802
-     * @param array $query_params
803
-     * @return EE_Base_Class|EE_Venue|null
804
-     * @throws EE_Error
805
-     * @throws ReflectionException
806
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
807
-     */
808
-    public function venue(array $query_params = []): ?EE_Venue
809
-    {
810
-        return $this->get_first_related('Venue', $query_params);
811
-    }
812
-
813
-
814
-    /**
815
-     * @param array $query_params
816
-     * @return EE_Base_Class[]|EE_Venue[]
817
-     * @throws EE_Error
818
-     * @throws ReflectionException
819
-     * @deprecated $VID:$
820
-     */
821
-    public function venues(array $query_params = []): array
822
-    {
823
-        return [$this->venue($query_params)];
824
-    }
825
-
826
-
827
-    /**
828
-     * check if event id is present and if event is published
829
-     *
830
-     * @return boolean true yes, false no
831
-     * @throws EE_Error
832
-     * @throws ReflectionException
833
-     */
834
-    private function _has_ID_and_is_published(): bool
835
-    {
836
-        // first check if event id is present and not NULL,
837
-        // then check if this event is published (or any of the equivalent "published" statuses)
838
-        return
839
-            $this->ID() && $this->ID() !== null
840
-            && (
841
-                $this->status() === 'publish'
842
-                || $this->status() === EEM_Event::sold_out
843
-                || $this->status() === EEM_Event::postponed
844
-                || $this->status() === EEM_Event::cancelled
845
-            );
846
-    }
847
-
848
-
849
-    /**
850
-     * This simply compares the internal dates with NOW and determines if the event is upcoming or not.
851
-     *
852
-     * @return boolean true yes, false no
853
-     * @throws EE_Error
854
-     * @throws ReflectionException
855
-     */
856
-    public function is_upcoming(): bool
857
-    {
858
-        // check if event id is present and if this event is published
859
-        if ($this->is_inactive()) {
860
-            return false;
861
-        }
862
-        // set initial value
863
-        $upcoming = false;
864
-        // next let's get all datetimes and loop through them
865
-        $datetimes = $this->datetimes_in_chronological_order();
866
-        foreach ($datetimes as $datetime) {
867
-            if ($datetime instanceof EE_Datetime) {
868
-                // if this dtt is expired then we continue cause one of the other datetimes might be upcoming.
869
-                if ($datetime->is_expired()) {
870
-                    continue;
871
-                }
872
-                // if this dtt is active then we return false.
873
-                if ($datetime->is_active()) {
874
-                    return false;
875
-                }
876
-                // otherwise let's check upcoming status
877
-                $upcoming = $datetime->is_upcoming();
878
-            }
879
-        }
880
-        return $upcoming;
881
-    }
882
-
883
-
884
-    /**
885
-     * @return bool
886
-     * @throws EE_Error
887
-     * @throws ReflectionException
888
-     */
889
-    public function is_active(): bool
890
-    {
891
-        // check if event id is present and if this event is published
892
-        if ($this->is_inactive()) {
893
-            return false;
894
-        }
895
-        // set initial value
896
-        $active = false;
897
-        // next let's get all datetimes and loop through them
898
-        $datetimes = $this->datetimes_in_chronological_order();
899
-        foreach ($datetimes as $datetime) {
900
-            if ($datetime instanceof EE_Datetime) {
901
-                // if this dtt is expired then we continue cause one of the other datetimes might be active.
902
-                if ($datetime->is_expired()) {
903
-                    continue;
904
-                }
905
-                // if this dtt is upcoming then we return false.
906
-                if ($datetime->is_upcoming()) {
907
-                    return false;
908
-                }
909
-                // otherwise let's check active status
910
-                $active = $datetime->is_active();
911
-            }
912
-        }
913
-        return $active;
914
-    }
915
-
916
-
917
-    /**
918
-     * @return bool
919
-     * @throws EE_Error
920
-     * @throws ReflectionException
921
-     */
922
-    public function is_expired(): bool
923
-    {
924
-        // check if event id is present and if this event is published
925
-        if ($this->is_inactive()) {
926
-            return false;
927
-        }
928
-        // set initial value
929
-        $expired = false;
930
-        // first let's get all datetimes and loop through them
931
-        $datetimes = $this->datetimes_in_chronological_order();
932
-        foreach ($datetimes as $datetime) {
933
-            if ($datetime instanceof EE_Datetime) {
934
-                // if this dtt is upcoming or active then we return false.
935
-                if ($datetime->is_upcoming() || $datetime->is_active()) {
936
-                    return false;
937
-                }
938
-                // otherwise let's check active status
939
-                $expired = $datetime->is_expired();
940
-            }
941
-        }
942
-        return $expired;
943
-    }
944
-
945
-
946
-    /**
947
-     * @return bool
948
-     * @throws EE_Error
949
-     * @throws ReflectionException
950
-     */
951
-    public function is_inactive(): bool
952
-    {
953
-        // check if event id is present and if this event is published
954
-        if ($this->_has_ID_and_is_published()) {
955
-            return false;
956
-        }
957
-        return true;
958
-    }
959
-
960
-
961
-    /**
962
-     * calculate spaces remaining based on "saleable" tickets
963
-     *
964
-     * @param array|null $tickets
965
-     * @param bool       $filtered
966
-     * @return int|float
967
-     * @throws EE_Error
968
-     * @throws DomainException
969
-     * @throws UnexpectedEntityException
970
-     * @throws ReflectionException
971
-     */
972
-    public function spaces_remaining(?array $tickets = [], ?bool $filtered = true)
973
-    {
974
-        $this->getAvailableSpacesCalculator()->setActiveTickets($tickets);
975
-        $spaces_remaining = $this->getAvailableSpacesCalculator()->spacesRemaining();
976
-        return $filtered
977
-            ? apply_filters(
978
-                'FHEE_EE_Event__spaces_remaining',
979
-                $spaces_remaining,
980
-                $this,
981
-                $tickets
982
-            )
983
-            : $spaces_remaining;
984
-    }
985
-
986
-
987
-    /**
988
-     *    perform_sold_out_status_check
989
-     *    checks all of this event's datetime  reg_limit - sold values to determine if ANY datetimes have spaces
990
-     *    available... if NOT, then the event status will get toggled to 'sold_out'
991
-     *
992
-     * @return bool    return the ACTUAL sold out state.
993
-     * @throws EE_Error
994
-     * @throws DomainException
995
-     * @throws UnexpectedEntityException
996
-     * @throws ReflectionException
997
-     */
998
-    public function perform_sold_out_status_check(): bool
999
-    {
1000
-        // get all tickets
1001
-        $tickets     = $this->tickets(
1002
-            [
1003
-                'default_where_conditions' => 'none',
1004
-                'order_by'                 => ['TKT_qty' => 'ASC'],
1005
-            ]
1006
-        );
1007
-        $all_expired = true;
1008
-        foreach ($tickets as $ticket) {
1009
-            if (! $ticket->is_expired()) {
1010
-                $all_expired = false;
1011
-                break;
1012
-            }
1013
-        }
1014
-        // if all the tickets are just expired, then don't update the event status to sold out
1015
-        if ($all_expired) {
1016
-            return true;
1017
-        }
1018
-        $spaces_remaining = $this->spaces_remaining($tickets);
1019
-        if ($spaces_remaining < 1) {
1020
-            if ($this->status() !== EEM_CPT_Base::post_status_private) {
1021
-                $this->set_status(EEM_Event::sold_out);
1022
-                $this->save();
1023
-            }
1024
-            $sold_out = true;
1025
-        } else {
1026
-            $sold_out = false;
1027
-            // was event previously marked as sold out ?
1028
-            if ($this->status() === EEM_Event::sold_out) {
1029
-                // revert status to previous value, if it was set
1030
-                $previous_event_status = $this->get_post_meta('_previous_event_status', true);
1031
-                if ($previous_event_status) {
1032
-                    $this->set_status($previous_event_status);
1033
-                    $this->save();
1034
-                }
1035
-            }
1036
-        }
1037
-        do_action('AHEE__EE_Event__perform_sold_out_status_check__end', $this, $sold_out, $spaces_remaining, $tickets);
1038
-        return $sold_out;
1039
-    }
1040
-
1041
-
1042
-    /**
1043
-     * This returns the total remaining spaces for sale on this event.
1044
-     *
1045
-     * @return int|float
1046
-     * @throws EE_Error
1047
-     * @throws DomainException
1048
-     * @throws UnexpectedEntityException
1049
-     * @throws ReflectionException
1050
-     * @uses EE_Event::total_available_spaces()
1051
-     */
1052
-    public function spaces_remaining_for_sale()
1053
-    {
1054
-        return $this->total_available_spaces(true);
1055
-    }
1056
-
1057
-
1058
-    /**
1059
-     * This returns the total spaces available for an event
1060
-     * while considering all the quantities on the tickets and the reg limits
1061
-     * on the datetimes attached to this event.
1062
-     *
1063
-     * @param bool $consider_sold   Whether to consider any tickets that have already sold in our calculation.
1064
-     *                              If this is false, then we return the most tickets that could ever be sold
1065
-     *                              for this event with the datetime and tickets setup on the event under optimal
1066
-     *                              selling conditions.  Otherwise we return a live calculation of spaces available
1067
-     *                              based on tickets sold.  Depending on setup and stage of sales, this
1068
-     *                              may appear to equal remaining tickets.  However, the more tickets are
1069
-     *                              sold out, the more accurate the "live" total is.
1070
-     * @return int|float
1071
-     * @throws EE_Error
1072
-     * @throws DomainException
1073
-     * @throws UnexpectedEntityException
1074
-     * @throws ReflectionException
1075
-     */
1076
-    public function total_available_spaces(bool $consider_sold = false)
1077
-    {
1078
-        $spaces_available = $consider_sold
1079
-            ? $this->getAvailableSpacesCalculator()->spacesRemaining()
1080
-            : $this->getAvailableSpacesCalculator()->totalSpacesAvailable();
1081
-        return apply_filters(
1082
-            'FHEE_EE_Event__total_available_spaces__spaces_available',
1083
-            $spaces_available,
1084
-            $this,
1085
-            $this->getAvailableSpacesCalculator()->getDatetimes(),
1086
-            $this->getAvailableSpacesCalculator()->getActiveTickets()
1087
-        );
1088
-    }
1089
-
1090
-
1091
-    /**
1092
-     * Checks if the event is set to sold out
1093
-     *
1094
-     * @param bool $actual  whether or not to perform calculations to not only figure the
1095
-     *                      actual status but also to flip the status if necessary to sold
1096
-     *                      out If false, we just check the existing status of the event
1097
-     * @return boolean
1098
-     * @throws EE_Error
1099
-     * @throws ReflectionException
1100
-     */
1101
-    public function is_sold_out(bool $actual = false): bool
1102
-    {
1103
-        if (! $actual) {
1104
-            return $this->status() === EEM_Event::sold_out;
1105
-        }
1106
-        return $this->perform_sold_out_status_check();
1107
-    }
1108
-
1109
-
1110
-    /**
1111
-     * Checks if the event is marked as postponed
1112
-     *
1113
-     * @return boolean
1114
-     */
1115
-    public function is_postponed(): bool
1116
-    {
1117
-        return $this->status() === EEM_Event::postponed;
1118
-    }
1119
-
1120
-
1121
-    /**
1122
-     * Checks if the event is marked as cancelled
1123
-     *
1124
-     * @return boolean
1125
-     */
1126
-    public function is_cancelled(): bool
1127
-    {
1128
-        return $this->status() === EEM_Event::cancelled;
1129
-    }
1130
-
1131
-
1132
-    /**
1133
-     * Get the logical active status in a hierarchical order for all the datetimes.  Note
1134
-     * Basically, we order the datetimes by EVT_start_date.  Then first test on whether the event is published.  If its
1135
-     * NOT published then we test for whether its expired or not.  IF it IS published then we test first on whether an
1136
-     * event has any active dates.  If no active dates then we check for any upcoming dates.  If no upcoming dates then
1137
-     * the event is considered expired.
1138
-     * NOTE: this method does NOT calculate whether the datetimes are sold out when event is published.  Sold Out is a
1139
-     * status set on the EVENT when it is not published and thus is done
1140
-     *
1141
-     * @param bool $reset
1142
-     * @return bool | string - based on EE_Datetime active constants or FALSE if error.
1143
-     * @throws EE_Error
1144
-     * @throws ReflectionException
1145
-     */
1146
-    public function get_active_status(bool $reset = false)
1147
-    {
1148
-        // if the active status has already been set, then just use that value (unless we are resetting it)
1149
-        if (! empty($this->_active_status) && ! $reset) {
1150
-            return $this->_active_status;
1151
-        }
1152
-        // first check if event id is present on this object
1153
-        if (! $this->ID()) {
1154
-            return false;
1155
-        }
1156
-        $where_params_for_event = [['EVT_ID' => $this->ID()]];
1157
-        // if event is published:
1158
-        if (
1159
-            $this->status() === EEM_CPT_Base::post_status_publish
1160
-            || $this->status() === EEM_CPT_Base::post_status_private
1161
-        ) {
1162
-            // active?
1163
-            if (
1164
-                EEM_Datetime::instance()->get_datetime_count_for_status(
1165
-                    EE_Datetime::active,
1166
-                    $where_params_for_event
1167
-                ) > 0
1168
-            ) {
1169
-                $this->_active_status = EE_Datetime::active;
1170
-            } else {
1171
-                // upcoming?
1172
-                if (
1173
-                    EEM_Datetime::instance()->get_datetime_count_for_status(
1174
-                        EE_Datetime::upcoming,
1175
-                        $where_params_for_event
1176
-                    ) > 0
1177
-                ) {
1178
-                    $this->_active_status = EE_Datetime::upcoming;
1179
-                } else {
1180
-                    // expired?
1181
-                    if (
1182
-                        EEM_Datetime::instance()->get_datetime_count_for_status(
1183
-                            EE_Datetime::expired,
1184
-                            $where_params_for_event
1185
-                        ) > 0
1186
-                    ) {
1187
-                        $this->_active_status = EE_Datetime::expired;
1188
-                    } else {
1189
-                        // it would be odd if things make it this far
1190
-                        // because it basically means there are no datetimes attached to the event.
1191
-                        // So in this case it will just be considered inactive.
1192
-                        $this->_active_status = EE_Datetime::inactive;
1193
-                    }
1194
-                }
1195
-            }
1196
-        } else {
1197
-            // the event is not published, so let's just set it's active status according to its' post status
1198
-            switch ($this->status()) {
1199
-                case EEM_Event::sold_out:
1200
-                    $this->_active_status = EE_Datetime::sold_out;
1201
-                    break;
1202
-                case EEM_Event::cancelled:
1203
-                    $this->_active_status = EE_Datetime::cancelled;
1204
-                    break;
1205
-                case EEM_Event::postponed:
1206
-                    $this->_active_status = EE_Datetime::postponed;
1207
-                    break;
1208
-                default:
1209
-                    $this->_active_status = EE_Datetime::inactive;
1210
-            }
1211
-        }
1212
-        return $this->_active_status;
1213
-    }
1214
-
1215
-
1216
-    /**
1217
-     *    pretty_active_status
1218
-     *
1219
-     * @param boolean $echo whether to return (FALSE), or echo out the result (TRUE)
1220
-     * @return string
1221
-     * @throws EE_Error
1222
-     * @throws ReflectionException
1223
-     */
1224
-    public function pretty_active_status(bool $echo = true): string
1225
-    {
1226
-        $active_status = $this->get_active_status();
1227
-        $status        = "
19
+	/**
20
+	 * cached value for the the logical active status for the event
21
+	 *
22
+	 * @see get_active_status()
23
+	 * @var string
24
+	 */
25
+	protected $_active_status = '';
26
+
27
+	/**
28
+	 * This is just used for caching the Primary Datetime for the Event on initial retrieval
29
+	 *
30
+	 * @var EE_Datetime
31
+	 */
32
+	protected $_Primary_Datetime;
33
+
34
+	/**
35
+	 * @var EventSpacesCalculator $available_spaces_calculator
36
+	 */
37
+	protected $available_spaces_calculator;
38
+
39
+
40
+	/**
41
+	 * @param array  $props_n_values          incoming values
42
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
43
+	 *                                        used.)
44
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
45
+	 *                                        date_format and the second value is the time format
46
+	 * @return EE_Event
47
+	 * @throws EE_Error
48
+	 * @throws ReflectionException
49
+	 */
50
+	public static function new_instance($props_n_values = [], $timezone = null, $date_formats = []): EE_Event
51
+	{
52
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
53
+		return $has_object ?: new self($props_n_values, false, $timezone, $date_formats);
54
+	}
55
+
56
+
57
+	/**
58
+	 * @param array  $props_n_values  incoming values from the database
59
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
60
+	 *                                the website will be used.
61
+	 * @return EE_Event
62
+	 * @throws EE_Error
63
+	 * @throws ReflectionException
64
+	 */
65
+	public static function new_instance_from_db($props_n_values = [], $timezone = null): EE_Event
66
+	{
67
+		return new self($props_n_values, true, $timezone);
68
+	}
69
+
70
+
71
+	/**
72
+	 * @return EventSpacesCalculator
73
+	 * @throws EE_Error
74
+	 * @throws ReflectionException
75
+	 */
76
+	public function getAvailableSpacesCalculator(): EventSpacesCalculator
77
+	{
78
+		if (! $this->available_spaces_calculator instanceof EventSpacesCalculator) {
79
+			$this->available_spaces_calculator = new EventSpacesCalculator($this);
80
+		}
81
+		return $this->available_spaces_calculator;
82
+	}
83
+
84
+
85
+	/**
86
+	 * Overrides parent set() method so that all calls to set( 'status', $status ) can be routed to internal methods
87
+	 *
88
+	 * @param string $field_name
89
+	 * @param mixed  $field_value
90
+	 * @param bool   $use_default
91
+	 * @throws EE_Error
92
+	 * @throws ReflectionException
93
+	 */
94
+	public function set($field_name, $field_value, $use_default = false)
95
+	{
96
+		switch ($field_name) {
97
+			case 'status':
98
+				$this->set_status($field_value, $use_default);
99
+				break;
100
+			default:
101
+				parent::set($field_name, $field_value, $use_default);
102
+		}
103
+	}
104
+
105
+
106
+	/**
107
+	 *    set_status
108
+	 * Checks if event status is being changed to SOLD OUT
109
+	 * and updates event meta data with previous event status
110
+	 * so that we can revert things if/when the event is no longer sold out
111
+	 *
112
+	 * @param string $status
113
+	 * @param bool   $use_default
114
+	 * @return void
115
+	 * @throws EE_Error
116
+	 * @throws ReflectionException
117
+	 */
118
+	public function set_status($status = '', $use_default = false)
119
+	{
120
+		// if nothing is set, and we aren't explicitly wanting to reset the status, then just leave
121
+		if (empty($status) && ! $use_default) {
122
+			return;
123
+		}
124
+		// get current Event status
125
+		$old_status = $this->status();
126
+		// if status has changed
127
+		if ($old_status !== $status) {
128
+			// TO sold_out
129
+			if ($status === EEM_Event::sold_out) {
130
+				// save the previous event status so that we can revert if the event is no longer sold out
131
+				$this->add_post_meta('_previous_event_status', $old_status);
132
+				do_action('AHEE__EE_Event__set_status__to_sold_out', $this, $old_status, $status);
133
+				// OR FROM  sold_out
134
+			} elseif ($old_status === EEM_Event::sold_out) {
135
+				$this->delete_post_meta('_previous_event_status');
136
+				do_action('AHEE__EE_Event__set_status__from_sold_out', $this, $old_status, $status);
137
+			}
138
+			// clear out the active status so that it gets reset the next time it is requested
139
+			$this->_active_status = null;
140
+			// update status
141
+			parent::set('status', $status, $use_default);
142
+			do_action('AHEE__EE_Event__set_status__after_update', $this);
143
+			return;
144
+		}
145
+		// even though the old value matches the new value, it's still good to
146
+		// allow the parent set method to have a say
147
+		parent::set('status', $status, $use_default);
148
+	}
149
+
150
+
151
+	/**
152
+	 * Gets all the datetimes for this event
153
+	 *
154
+	 * @param array|null $query_params
155
+	 * @return EE_Base_Class[]|EE_Datetime[]
156
+	 * @throws EE_Error
157
+	 * @throws ReflectionException
158
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
159
+	 */
160
+	public function datetimes(?array $query_params = []): array
161
+	{
162
+		return $this->get_many_related('Datetime', $query_params);
163
+	}
164
+
165
+
166
+	/**
167
+	 * Gets all the datetimes for this event that are currently ACTIVE,
168
+	 * meaning the datetime has started and has not yet ended.
169
+	 *
170
+	 * @param int|null   $start_date   timestamp to use for event date start time, defaults to NOW unless set to 0
171
+	 * @param array|null $query_params will recursively replace default values
172
+	 * @throws EE_Error
173
+	 * @throws ReflectionException
174
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
175
+	 */
176
+	public function activeDatetimes(?int $start_date, ?array $query_params = []): array
177
+	{
178
+		// if start date is null, then use current time
179
+		$start_date = $start_date ?? time();
180
+		$where      = [];
181
+		if ($start_date) {
182
+			$where['DTT_EVT_start'] = ['<', $start_date];
183
+			$where['DTT_EVT_end']   = ['>', time()];
184
+		}
185
+		$query_params = array_replace_recursive(
186
+			[
187
+				$where,
188
+				'order_by' => ['DTT_EVT_start' => 'ASC'],
189
+			],
190
+			$query_params
191
+		);
192
+		return $this->get_many_related('Datetime', $query_params);
193
+	}
194
+
195
+
196
+	/**
197
+	 * Gets all the datetimes for this event, ordered by DTT_EVT_start in ascending order
198
+	 *
199
+	 * @return EE_Base_Class[]|EE_Datetime[]
200
+	 * @throws EE_Error
201
+	 * @throws ReflectionException
202
+	 */
203
+	public function datetimes_in_chronological_order(): array
204
+	{
205
+		return $this->get_many_related('Datetime', ['order_by' => ['DTT_EVT_start' => 'ASC']]);
206
+	}
207
+
208
+
209
+	/**
210
+	 * Gets all the datetimes for this event, ordered by the DTT_order on the datetime.
211
+	 * @darren, we should probably UNSET timezone on the EEM_Datetime model
212
+	 * after running our query, so that this timezone isn't set for EVERY query
213
+	 * on EEM_Datetime for the rest of the request, no?
214
+	 *
215
+	 * @param bool     $show_expired whether or not to include expired events
216
+	 * @param bool     $show_deleted whether or not to include deleted events
217
+	 * @param int|null $limit
218
+	 * @return EE_Datetime[]
219
+	 * @throws EE_Error
220
+	 * @throws ReflectionException
221
+	 */
222
+	public function datetimes_ordered(bool $show_expired = true, bool $show_deleted = false, ?int $limit = null): array
223
+	{
224
+		return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_event_ordered_by_DTT_order(
225
+			$this->ID(),
226
+			$show_expired,
227
+			$show_deleted,
228
+			$limit
229
+		);
230
+	}
231
+
232
+
233
+	/**
234
+	 * Returns one related datetime. Mostly only used by some legacy code.
235
+	 *
236
+	 * @return EE_Base_Class|EE_Datetime
237
+	 * @throws EE_Error
238
+	 * @throws ReflectionException
239
+	 */
240
+	public function first_datetime(): EE_Datetime
241
+	{
242
+		return $this->get_first_related('Datetime');
243
+	}
244
+
245
+
246
+	/**
247
+	 * Returns the 'primary' datetime for the event
248
+	 *
249
+	 * @param bool $try_to_exclude_expired
250
+	 * @param bool $try_to_exclude_deleted
251
+	 * @return EE_Datetime|null
252
+	 * @throws EE_Error
253
+	 * @throws ReflectionException
254
+	 */
255
+	public function primary_datetime(
256
+		bool $try_to_exclude_expired = true,
257
+		bool $try_to_exclude_deleted = true
258
+	): ?EE_Datetime {
259
+		if (! empty($this->_Primary_Datetime)) {
260
+			return $this->_Primary_Datetime;
261
+		}
262
+		$this->_Primary_Datetime = EEM_Datetime::instance($this->_timezone)->get_primary_datetime_for_event(
263
+			$this->ID(),
264
+			$try_to_exclude_expired,
265
+			$try_to_exclude_deleted
266
+		);
267
+		return $this->_Primary_Datetime;
268
+	}
269
+
270
+
271
+	/**
272
+	 * Gets all the tickets available for purchase of this event
273
+	 *
274
+	 * @param array|null $query_params
275
+	 * @return EE_Base_Class[]|EE_Ticket[]
276
+	 * @throws EE_Error
277
+	 * @throws ReflectionException
278
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
279
+	 */
280
+	public function tickets(?array $query_params = []): array
281
+	{
282
+		// first get all datetimes
283
+		$datetimes = $this->datetimes_ordered();
284
+		if (! $datetimes) {
285
+			return [];
286
+		}
287
+		$datetime_ids = [];
288
+		foreach ($datetimes as $datetime) {
289
+			$datetime_ids[] = $datetime->ID();
290
+		}
291
+		$where_params = ['Datetime.DTT_ID' => ['IN', $datetime_ids]];
292
+		// if incoming $query_params has where conditions let's merge but not override existing.
293
+		if (is_array($query_params) && isset($query_params[0])) {
294
+			$where_params = array_merge($query_params[0], $where_params);
295
+			unset($query_params[0]);
296
+		}
297
+		// now add $where_params to $query_params
298
+		$query_params[0] = $where_params;
299
+		return EEM_Ticket::instance()->get_all($query_params);
300
+	}
301
+
302
+
303
+	/**
304
+	 * get all unexpired not-trashed tickets
305
+	 *
306
+	 * @return EE_Ticket[]
307
+	 * @throws EE_Error
308
+	 * @throws ReflectionException
309
+	 */
310
+	public function active_tickets(): array
311
+	{
312
+		return $this->tickets(
313
+			[
314
+				[
315
+					'TKT_end_date' => ['>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')],
316
+					'TKT_deleted'  => false,
317
+				],
318
+			]
319
+		);
320
+	}
321
+
322
+
323
+	/**
324
+	 * @return int
325
+	 * @throws EE_Error
326
+	 * @throws ReflectionException
327
+	 */
328
+	public function additional_limit(): int
329
+	{
330
+		return $this->get('EVT_additional_limit');
331
+	}
332
+
333
+
334
+	/**
335
+	 * @return bool
336
+	 * @throws EE_Error
337
+	 * @throws ReflectionException
338
+	 */
339
+	public function allow_overflow(): bool
340
+	{
341
+		return $this->get('EVT_allow_overflow');
342
+	}
343
+
344
+
345
+	/**
346
+	 * @return string
347
+	 * @throws EE_Error
348
+	 * @throws ReflectionException
349
+	 */
350
+	public function created(): string
351
+	{
352
+		return $this->get('EVT_created');
353
+	}
354
+
355
+
356
+	/**
357
+	 * @return string
358
+	 * @throws EE_Error
359
+	 * @throws ReflectionException
360
+	 */
361
+	public function description(): string
362
+	{
363
+		return $this->get('EVT_desc');
364
+	}
365
+
366
+
367
+	/**
368
+	 * Runs do_shortcode and wpautop on the description
369
+	 *
370
+	 * @return string of html
371
+	 * @throws EE_Error
372
+	 * @throws ReflectionException
373
+	 */
374
+	public function description_filtered(): string
375
+	{
376
+		return $this->get_pretty('EVT_desc');
377
+	}
378
+
379
+
380
+	/**
381
+	 * @return bool
382
+	 * @throws EE_Error
383
+	 * @throws ReflectionException
384
+	 */
385
+	public function display_description(): bool
386
+	{
387
+		return $this->get('EVT_display_desc');
388
+	}
389
+
390
+
391
+	/**
392
+	 * @return bool
393
+	 * @throws EE_Error
394
+	 * @throws ReflectionException
395
+	 */
396
+	public function display_ticket_selector(): bool
397
+	{
398
+		return (bool) $this->get('EVT_display_ticket_selector');
399
+	}
400
+
401
+
402
+	/**
403
+	 * @return string
404
+	 * @throws EE_Error
405
+	 * @throws ReflectionException
406
+	 */
407
+	public function external_url(): string
408
+	{
409
+		return $this->get('EVT_external_URL');
410
+	}
411
+
412
+
413
+	/**
414
+	 * @return bool
415
+	 * @throws EE_Error
416
+	 * @throws ReflectionException
417
+	 */
418
+	public function member_only(): bool
419
+	{
420
+		return $this->get('EVT_member_only');
421
+	}
422
+
423
+
424
+	/**
425
+	 * @return string
426
+	 * @throws EE_Error
427
+	 * @throws ReflectionException
428
+	 */
429
+	public function phone(): string
430
+	{
431
+		return $this->get('EVT_phone');
432
+	}
433
+
434
+
435
+	/**
436
+	 * @return string
437
+	 * @throws EE_Error
438
+	 * @throws ReflectionException
439
+	 */
440
+	public function modified(): string
441
+	{
442
+		return $this->get('EVT_modified');
443
+	}
444
+
445
+
446
+	/**
447
+	 * @return string
448
+	 * @throws EE_Error
449
+	 * @throws ReflectionException
450
+	 */
451
+	public function name(): string
452
+	{
453
+		return $this->get('EVT_name');
454
+	}
455
+
456
+
457
+	/**
458
+	 * @return int
459
+	 * @throws EE_Error
460
+	 * @throws ReflectionException
461
+	 */
462
+	public function order(): int
463
+	{
464
+		return $this->get('EVT_order');
465
+	}
466
+
467
+
468
+	/**
469
+	 * @return string
470
+	 * @throws EE_Error
471
+	 * @throws ReflectionException
472
+	 */
473
+	public function default_registration_status(): string
474
+	{
475
+		$event_default_registration_status = $this->get('EVT_default_registration_status');
476
+		return ! empty($event_default_registration_status)
477
+			? $event_default_registration_status
478
+			: EE_Registry::instance()->CFG->registration->default_STS_ID;
479
+	}
480
+
481
+
482
+	/**
483
+	 * @param int|null    $num_words
484
+	 * @param string|null $more
485
+	 * @param bool        $not_full_desc
486
+	 * @return string
487
+	 * @throws EE_Error
488
+	 * @throws ReflectionException
489
+	 */
490
+	public function short_description(?int $num_words = 55, string $more = null, bool $not_full_desc = false): string
491
+	{
492
+		$short_desc = $this->get('EVT_short_desc');
493
+		if (! empty($short_desc) || $not_full_desc) {
494
+			return $short_desc;
495
+		}
496
+		$full_desc = $this->get('EVT_desc');
497
+		return wp_trim_words($full_desc, $num_words, $more);
498
+	}
499
+
500
+
501
+	/**
502
+	 * @return string
503
+	 * @throws EE_Error
504
+	 * @throws ReflectionException
505
+	 */
506
+	public function slug(): string
507
+	{
508
+		return $this->get('EVT_slug');
509
+	}
510
+
511
+
512
+	/**
513
+	 * @return string
514
+	 * @throws EE_Error
515
+	 * @throws ReflectionException
516
+	 */
517
+	public function timezone_string(): string
518
+	{
519
+		return $this->get('EVT_timezone_string');
520
+	}
521
+
522
+
523
+	/**
524
+	 * @return string
525
+	 * @throws EE_Error
526
+	 * @throws ReflectionException
527
+	 */
528
+	public function visible_on(): string
529
+	{
530
+		return $this->get('EVT_visible_on');
531
+	}
532
+
533
+
534
+	/**
535
+	 * @return int
536
+	 * @throws EE_Error
537
+	 * @throws ReflectionException
538
+	 */
539
+	public function wp_user(): int
540
+	{
541
+		return $this->get('EVT_wp_user');
542
+	}
543
+
544
+
545
+	/**
546
+	 * @return bool
547
+	 * @throws EE_Error
548
+	 * @throws ReflectionException
549
+	 */
550
+	public function donations(): bool
551
+	{
552
+		return $this->get('EVT_donations');
553
+	}
554
+
555
+
556
+	/**
557
+	 * @param int $limit
558
+	 * @throws EE_Error
559
+	 * @throws ReflectionException
560
+	 */
561
+	public function set_additional_limit(int $limit)
562
+	{
563
+		$this->set('EVT_additional_limit', $limit);
564
+	}
565
+
566
+
567
+	/**
568
+	 * @param $created
569
+	 * @throws EE_Error
570
+	 * @throws ReflectionException
571
+	 */
572
+	public function set_created($created)
573
+	{
574
+		$this->set('EVT_created', $created);
575
+	}
576
+
577
+
578
+	/**
579
+	 * @param $desc
580
+	 * @throws EE_Error
581
+	 * @throws ReflectionException
582
+	 */
583
+	public function set_description($desc)
584
+	{
585
+		$this->set('EVT_desc', $desc);
586
+	}
587
+
588
+
589
+	/**
590
+	 * @param $display_desc
591
+	 * @throws EE_Error
592
+	 * @throws ReflectionException
593
+	 */
594
+	public function set_display_description($display_desc)
595
+	{
596
+		$this->set('EVT_display_desc', $display_desc);
597
+	}
598
+
599
+
600
+	/**
601
+	 * @param $display_ticket_selector
602
+	 * @throws EE_Error
603
+	 * @throws ReflectionException
604
+	 */
605
+	public function set_display_ticket_selector($display_ticket_selector)
606
+	{
607
+		$this->set('EVT_display_ticket_selector', $display_ticket_selector);
608
+	}
609
+
610
+
611
+	/**
612
+	 * @param $external_url
613
+	 * @throws EE_Error
614
+	 * @throws ReflectionException
615
+	 */
616
+	public function set_external_url($external_url)
617
+	{
618
+		$this->set('EVT_external_URL', $external_url);
619
+	}
620
+
621
+
622
+	/**
623
+	 * @param $member_only
624
+	 * @throws EE_Error
625
+	 * @throws ReflectionException
626
+	 */
627
+	public function set_member_only($member_only)
628
+	{
629
+		$this->set('EVT_member_only', $member_only);
630
+	}
631
+
632
+
633
+	/**
634
+	 * @param $event_phone
635
+	 * @throws EE_Error
636
+	 * @throws ReflectionException
637
+	 */
638
+	public function set_event_phone($event_phone)
639
+	{
640
+		$this->set('EVT_phone', $event_phone);
641
+	}
642
+
643
+
644
+	/**
645
+	 * @param $modified
646
+	 * @throws EE_Error
647
+	 * @throws ReflectionException
648
+	 */
649
+	public function set_modified($modified)
650
+	{
651
+		$this->set('EVT_modified', $modified);
652
+	}
653
+
654
+
655
+	/**
656
+	 * @param $name
657
+	 * @throws EE_Error
658
+	 * @throws ReflectionException
659
+	 */
660
+	public function set_name($name)
661
+	{
662
+		$this->set('EVT_name', $name);
663
+	}
664
+
665
+
666
+	/**
667
+	 * @param $order
668
+	 * @throws EE_Error
669
+	 * @throws ReflectionException
670
+	 */
671
+	public function set_order($order)
672
+	{
673
+		$this->set('EVT_order', $order);
674
+	}
675
+
676
+
677
+	/**
678
+	 * @param $short_desc
679
+	 * @throws EE_Error
680
+	 * @throws ReflectionException
681
+	 */
682
+	public function set_short_description($short_desc)
683
+	{
684
+		$this->set('EVT_short_desc', $short_desc);
685
+	}
686
+
687
+
688
+	/**
689
+	 * @param $slug
690
+	 * @throws EE_Error
691
+	 * @throws ReflectionException
692
+	 */
693
+	public function set_slug($slug)
694
+	{
695
+		$this->set('EVT_slug', $slug);
696
+	}
697
+
698
+
699
+	/**
700
+	 * @param $timezone_string
701
+	 * @throws EE_Error
702
+	 * @throws ReflectionException
703
+	 */
704
+	public function set_timezone_string($timezone_string)
705
+	{
706
+		$this->set('EVT_timezone_string', $timezone_string);
707
+	}
708
+
709
+
710
+	/**
711
+	 * @param $visible_on
712
+	 * @throws EE_Error
713
+	 * @throws ReflectionException
714
+	 */
715
+	public function set_visible_on($visible_on)
716
+	{
717
+		$this->set('EVT_visible_on', $visible_on);
718
+	}
719
+
720
+
721
+	/**
722
+	 * @param $wp_user
723
+	 * @throws EE_Error
724
+	 * @throws ReflectionException
725
+	 */
726
+	public function set_wp_user($wp_user)
727
+	{
728
+		$this->set('EVT_wp_user', $wp_user);
729
+	}
730
+
731
+
732
+	/**
733
+	 * @param $default_registration_status
734
+	 * @throws EE_Error
735
+	 * @throws ReflectionException
736
+	 */
737
+	public function set_default_registration_status($default_registration_status)
738
+	{
739
+		$this->set('EVT_default_registration_status', $default_registration_status);
740
+	}
741
+
742
+
743
+	/**
744
+	 * @param $donations
745
+	 * @throws EE_Error
746
+	 * @throws ReflectionException
747
+	 */
748
+	public function set_donations($donations)
749
+	{
750
+		$this->set('EVT_donations', $donations);
751
+	}
752
+
753
+
754
+	/**
755
+	 * Adds a venue to this event
756
+	 *
757
+	 * @param int|EE_Venue /int $venue_id_or_obj
758
+	 * @return EE_Base_Class|EE_Venue
759
+	 * @throws EE_Error
760
+	 * @throws ReflectionException
761
+	 */
762
+	public function add_venue($venue_id_or_obj): EE_Venue
763
+	{
764
+		return $this->_add_relation_to($venue_id_or_obj, 'Venue');
765
+	}
766
+
767
+
768
+	/**
769
+	 * Removes a venue from the event
770
+	 *
771
+	 * @param EE_Venue /int $venue_id_or_obj
772
+	 * @return EE_Base_Class|EE_Venue
773
+	 * @throws EE_Error
774
+	 * @throws ReflectionException
775
+	 */
776
+	public function remove_venue($venue_id_or_obj): EE_Venue
777
+	{
778
+		$venue_id_or_obj = ! empty($venue_id_or_obj) ? $venue_id_or_obj : $this->venue();
779
+		return $this->_remove_relation_to($venue_id_or_obj, 'Venue');
780
+	}
781
+
782
+
783
+	/**
784
+	 * Gets the venue related to the event. May provide additional $query_params if desired
785
+	 *
786
+	 * @param array $query_params
787
+	 * @return int
788
+	 * @throws EE_Error
789
+	 * @throws ReflectionException
790
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
791
+	 */
792
+	public function venue_ID(array $query_params = []): int
793
+	{
794
+		$venue = $this->get_first_related('Venue', $query_params);
795
+		return $venue instanceof EE_Venue ? $venue->ID() : 0;
796
+	}
797
+
798
+
799
+	/**
800
+	 * Gets the venue related to the event. May provide additional $query_params if desired
801
+	 *
802
+	 * @param array $query_params
803
+	 * @return EE_Base_Class|EE_Venue|null
804
+	 * @throws EE_Error
805
+	 * @throws ReflectionException
806
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
807
+	 */
808
+	public function venue(array $query_params = []): ?EE_Venue
809
+	{
810
+		return $this->get_first_related('Venue', $query_params);
811
+	}
812
+
813
+
814
+	/**
815
+	 * @param array $query_params
816
+	 * @return EE_Base_Class[]|EE_Venue[]
817
+	 * @throws EE_Error
818
+	 * @throws ReflectionException
819
+	 * @deprecated $VID:$
820
+	 */
821
+	public function venues(array $query_params = []): array
822
+	{
823
+		return [$this->venue($query_params)];
824
+	}
825
+
826
+
827
+	/**
828
+	 * check if event id is present and if event is published
829
+	 *
830
+	 * @return boolean true yes, false no
831
+	 * @throws EE_Error
832
+	 * @throws ReflectionException
833
+	 */
834
+	private function _has_ID_and_is_published(): bool
835
+	{
836
+		// first check if event id is present and not NULL,
837
+		// then check if this event is published (or any of the equivalent "published" statuses)
838
+		return
839
+			$this->ID() && $this->ID() !== null
840
+			&& (
841
+				$this->status() === 'publish'
842
+				|| $this->status() === EEM_Event::sold_out
843
+				|| $this->status() === EEM_Event::postponed
844
+				|| $this->status() === EEM_Event::cancelled
845
+			);
846
+	}
847
+
848
+
849
+	/**
850
+	 * This simply compares the internal dates with NOW and determines if the event is upcoming or not.
851
+	 *
852
+	 * @return boolean true yes, false no
853
+	 * @throws EE_Error
854
+	 * @throws ReflectionException
855
+	 */
856
+	public function is_upcoming(): bool
857
+	{
858
+		// check if event id is present and if this event is published
859
+		if ($this->is_inactive()) {
860
+			return false;
861
+		}
862
+		// set initial value
863
+		$upcoming = false;
864
+		// next let's get all datetimes and loop through them
865
+		$datetimes = $this->datetimes_in_chronological_order();
866
+		foreach ($datetimes as $datetime) {
867
+			if ($datetime instanceof EE_Datetime) {
868
+				// if this dtt is expired then we continue cause one of the other datetimes might be upcoming.
869
+				if ($datetime->is_expired()) {
870
+					continue;
871
+				}
872
+				// if this dtt is active then we return false.
873
+				if ($datetime->is_active()) {
874
+					return false;
875
+				}
876
+				// otherwise let's check upcoming status
877
+				$upcoming = $datetime->is_upcoming();
878
+			}
879
+		}
880
+		return $upcoming;
881
+	}
882
+
883
+
884
+	/**
885
+	 * @return bool
886
+	 * @throws EE_Error
887
+	 * @throws ReflectionException
888
+	 */
889
+	public function is_active(): bool
890
+	{
891
+		// check if event id is present and if this event is published
892
+		if ($this->is_inactive()) {
893
+			return false;
894
+		}
895
+		// set initial value
896
+		$active = false;
897
+		// next let's get all datetimes and loop through them
898
+		$datetimes = $this->datetimes_in_chronological_order();
899
+		foreach ($datetimes as $datetime) {
900
+			if ($datetime instanceof EE_Datetime) {
901
+				// if this dtt is expired then we continue cause one of the other datetimes might be active.
902
+				if ($datetime->is_expired()) {
903
+					continue;
904
+				}
905
+				// if this dtt is upcoming then we return false.
906
+				if ($datetime->is_upcoming()) {
907
+					return false;
908
+				}
909
+				// otherwise let's check active status
910
+				$active = $datetime->is_active();
911
+			}
912
+		}
913
+		return $active;
914
+	}
915
+
916
+
917
+	/**
918
+	 * @return bool
919
+	 * @throws EE_Error
920
+	 * @throws ReflectionException
921
+	 */
922
+	public function is_expired(): bool
923
+	{
924
+		// check if event id is present and if this event is published
925
+		if ($this->is_inactive()) {
926
+			return false;
927
+		}
928
+		// set initial value
929
+		$expired = false;
930
+		// first let's get all datetimes and loop through them
931
+		$datetimes = $this->datetimes_in_chronological_order();
932
+		foreach ($datetimes as $datetime) {
933
+			if ($datetime instanceof EE_Datetime) {
934
+				// if this dtt is upcoming or active then we return false.
935
+				if ($datetime->is_upcoming() || $datetime->is_active()) {
936
+					return false;
937
+				}
938
+				// otherwise let's check active status
939
+				$expired = $datetime->is_expired();
940
+			}
941
+		}
942
+		return $expired;
943
+	}
944
+
945
+
946
+	/**
947
+	 * @return bool
948
+	 * @throws EE_Error
949
+	 * @throws ReflectionException
950
+	 */
951
+	public function is_inactive(): bool
952
+	{
953
+		// check if event id is present and if this event is published
954
+		if ($this->_has_ID_and_is_published()) {
955
+			return false;
956
+		}
957
+		return true;
958
+	}
959
+
960
+
961
+	/**
962
+	 * calculate spaces remaining based on "saleable" tickets
963
+	 *
964
+	 * @param array|null $tickets
965
+	 * @param bool       $filtered
966
+	 * @return int|float
967
+	 * @throws EE_Error
968
+	 * @throws DomainException
969
+	 * @throws UnexpectedEntityException
970
+	 * @throws ReflectionException
971
+	 */
972
+	public function spaces_remaining(?array $tickets = [], ?bool $filtered = true)
973
+	{
974
+		$this->getAvailableSpacesCalculator()->setActiveTickets($tickets);
975
+		$spaces_remaining = $this->getAvailableSpacesCalculator()->spacesRemaining();
976
+		return $filtered
977
+			? apply_filters(
978
+				'FHEE_EE_Event__spaces_remaining',
979
+				$spaces_remaining,
980
+				$this,
981
+				$tickets
982
+			)
983
+			: $spaces_remaining;
984
+	}
985
+
986
+
987
+	/**
988
+	 *    perform_sold_out_status_check
989
+	 *    checks all of this event's datetime  reg_limit - sold values to determine if ANY datetimes have spaces
990
+	 *    available... if NOT, then the event status will get toggled to 'sold_out'
991
+	 *
992
+	 * @return bool    return the ACTUAL sold out state.
993
+	 * @throws EE_Error
994
+	 * @throws DomainException
995
+	 * @throws UnexpectedEntityException
996
+	 * @throws ReflectionException
997
+	 */
998
+	public function perform_sold_out_status_check(): bool
999
+	{
1000
+		// get all tickets
1001
+		$tickets     = $this->tickets(
1002
+			[
1003
+				'default_where_conditions' => 'none',
1004
+				'order_by'                 => ['TKT_qty' => 'ASC'],
1005
+			]
1006
+		);
1007
+		$all_expired = true;
1008
+		foreach ($tickets as $ticket) {
1009
+			if (! $ticket->is_expired()) {
1010
+				$all_expired = false;
1011
+				break;
1012
+			}
1013
+		}
1014
+		// if all the tickets are just expired, then don't update the event status to sold out
1015
+		if ($all_expired) {
1016
+			return true;
1017
+		}
1018
+		$spaces_remaining = $this->spaces_remaining($tickets);
1019
+		if ($spaces_remaining < 1) {
1020
+			if ($this->status() !== EEM_CPT_Base::post_status_private) {
1021
+				$this->set_status(EEM_Event::sold_out);
1022
+				$this->save();
1023
+			}
1024
+			$sold_out = true;
1025
+		} else {
1026
+			$sold_out = false;
1027
+			// was event previously marked as sold out ?
1028
+			if ($this->status() === EEM_Event::sold_out) {
1029
+				// revert status to previous value, if it was set
1030
+				$previous_event_status = $this->get_post_meta('_previous_event_status', true);
1031
+				if ($previous_event_status) {
1032
+					$this->set_status($previous_event_status);
1033
+					$this->save();
1034
+				}
1035
+			}
1036
+		}
1037
+		do_action('AHEE__EE_Event__perform_sold_out_status_check__end', $this, $sold_out, $spaces_remaining, $tickets);
1038
+		return $sold_out;
1039
+	}
1040
+
1041
+
1042
+	/**
1043
+	 * This returns the total remaining spaces for sale on this event.
1044
+	 *
1045
+	 * @return int|float
1046
+	 * @throws EE_Error
1047
+	 * @throws DomainException
1048
+	 * @throws UnexpectedEntityException
1049
+	 * @throws ReflectionException
1050
+	 * @uses EE_Event::total_available_spaces()
1051
+	 */
1052
+	public function spaces_remaining_for_sale()
1053
+	{
1054
+		return $this->total_available_spaces(true);
1055
+	}
1056
+
1057
+
1058
+	/**
1059
+	 * This returns the total spaces available for an event
1060
+	 * while considering all the quantities on the tickets and the reg limits
1061
+	 * on the datetimes attached to this event.
1062
+	 *
1063
+	 * @param bool $consider_sold   Whether to consider any tickets that have already sold in our calculation.
1064
+	 *                              If this is false, then we return the most tickets that could ever be sold
1065
+	 *                              for this event with the datetime and tickets setup on the event under optimal
1066
+	 *                              selling conditions.  Otherwise we return a live calculation of spaces available
1067
+	 *                              based on tickets sold.  Depending on setup and stage of sales, this
1068
+	 *                              may appear to equal remaining tickets.  However, the more tickets are
1069
+	 *                              sold out, the more accurate the "live" total is.
1070
+	 * @return int|float
1071
+	 * @throws EE_Error
1072
+	 * @throws DomainException
1073
+	 * @throws UnexpectedEntityException
1074
+	 * @throws ReflectionException
1075
+	 */
1076
+	public function total_available_spaces(bool $consider_sold = false)
1077
+	{
1078
+		$spaces_available = $consider_sold
1079
+			? $this->getAvailableSpacesCalculator()->spacesRemaining()
1080
+			: $this->getAvailableSpacesCalculator()->totalSpacesAvailable();
1081
+		return apply_filters(
1082
+			'FHEE_EE_Event__total_available_spaces__spaces_available',
1083
+			$spaces_available,
1084
+			$this,
1085
+			$this->getAvailableSpacesCalculator()->getDatetimes(),
1086
+			$this->getAvailableSpacesCalculator()->getActiveTickets()
1087
+		);
1088
+	}
1089
+
1090
+
1091
+	/**
1092
+	 * Checks if the event is set to sold out
1093
+	 *
1094
+	 * @param bool $actual  whether or not to perform calculations to not only figure the
1095
+	 *                      actual status but also to flip the status if necessary to sold
1096
+	 *                      out If false, we just check the existing status of the event
1097
+	 * @return boolean
1098
+	 * @throws EE_Error
1099
+	 * @throws ReflectionException
1100
+	 */
1101
+	public function is_sold_out(bool $actual = false): bool
1102
+	{
1103
+		if (! $actual) {
1104
+			return $this->status() === EEM_Event::sold_out;
1105
+		}
1106
+		return $this->perform_sold_out_status_check();
1107
+	}
1108
+
1109
+
1110
+	/**
1111
+	 * Checks if the event is marked as postponed
1112
+	 *
1113
+	 * @return boolean
1114
+	 */
1115
+	public function is_postponed(): bool
1116
+	{
1117
+		return $this->status() === EEM_Event::postponed;
1118
+	}
1119
+
1120
+
1121
+	/**
1122
+	 * Checks if the event is marked as cancelled
1123
+	 *
1124
+	 * @return boolean
1125
+	 */
1126
+	public function is_cancelled(): bool
1127
+	{
1128
+		return $this->status() === EEM_Event::cancelled;
1129
+	}
1130
+
1131
+
1132
+	/**
1133
+	 * Get the logical active status in a hierarchical order for all the datetimes.  Note
1134
+	 * Basically, we order the datetimes by EVT_start_date.  Then first test on whether the event is published.  If its
1135
+	 * NOT published then we test for whether its expired or not.  IF it IS published then we test first on whether an
1136
+	 * event has any active dates.  If no active dates then we check for any upcoming dates.  If no upcoming dates then
1137
+	 * the event is considered expired.
1138
+	 * NOTE: this method does NOT calculate whether the datetimes are sold out when event is published.  Sold Out is a
1139
+	 * status set on the EVENT when it is not published and thus is done
1140
+	 *
1141
+	 * @param bool $reset
1142
+	 * @return bool | string - based on EE_Datetime active constants or FALSE if error.
1143
+	 * @throws EE_Error
1144
+	 * @throws ReflectionException
1145
+	 */
1146
+	public function get_active_status(bool $reset = false)
1147
+	{
1148
+		// if the active status has already been set, then just use that value (unless we are resetting it)
1149
+		if (! empty($this->_active_status) && ! $reset) {
1150
+			return $this->_active_status;
1151
+		}
1152
+		// first check if event id is present on this object
1153
+		if (! $this->ID()) {
1154
+			return false;
1155
+		}
1156
+		$where_params_for_event = [['EVT_ID' => $this->ID()]];
1157
+		// if event is published:
1158
+		if (
1159
+			$this->status() === EEM_CPT_Base::post_status_publish
1160
+			|| $this->status() === EEM_CPT_Base::post_status_private
1161
+		) {
1162
+			// active?
1163
+			if (
1164
+				EEM_Datetime::instance()->get_datetime_count_for_status(
1165
+					EE_Datetime::active,
1166
+					$where_params_for_event
1167
+				) > 0
1168
+			) {
1169
+				$this->_active_status = EE_Datetime::active;
1170
+			} else {
1171
+				// upcoming?
1172
+				if (
1173
+					EEM_Datetime::instance()->get_datetime_count_for_status(
1174
+						EE_Datetime::upcoming,
1175
+						$where_params_for_event
1176
+					) > 0
1177
+				) {
1178
+					$this->_active_status = EE_Datetime::upcoming;
1179
+				} else {
1180
+					// expired?
1181
+					if (
1182
+						EEM_Datetime::instance()->get_datetime_count_for_status(
1183
+							EE_Datetime::expired,
1184
+							$where_params_for_event
1185
+						) > 0
1186
+					) {
1187
+						$this->_active_status = EE_Datetime::expired;
1188
+					} else {
1189
+						// it would be odd if things make it this far
1190
+						// because it basically means there are no datetimes attached to the event.
1191
+						// So in this case it will just be considered inactive.
1192
+						$this->_active_status = EE_Datetime::inactive;
1193
+					}
1194
+				}
1195
+			}
1196
+		} else {
1197
+			// the event is not published, so let's just set it's active status according to its' post status
1198
+			switch ($this->status()) {
1199
+				case EEM_Event::sold_out:
1200
+					$this->_active_status = EE_Datetime::sold_out;
1201
+					break;
1202
+				case EEM_Event::cancelled:
1203
+					$this->_active_status = EE_Datetime::cancelled;
1204
+					break;
1205
+				case EEM_Event::postponed:
1206
+					$this->_active_status = EE_Datetime::postponed;
1207
+					break;
1208
+				default:
1209
+					$this->_active_status = EE_Datetime::inactive;
1210
+			}
1211
+		}
1212
+		return $this->_active_status;
1213
+	}
1214
+
1215
+
1216
+	/**
1217
+	 *    pretty_active_status
1218
+	 *
1219
+	 * @param boolean $echo whether to return (FALSE), or echo out the result (TRUE)
1220
+	 * @return string
1221
+	 * @throws EE_Error
1222
+	 * @throws ReflectionException
1223
+	 */
1224
+	public function pretty_active_status(bool $echo = true): string
1225
+	{
1226
+		$active_status = $this->get_active_status();
1227
+		$status        = "
1228 1228
         <span class='ee-status ee-status-bg--$active_status event-active-status-$active_status'>
1229 1229
             " . EEH_Template::pretty_status($active_status, false, 'sentence') . "
1230 1230
         </span >";
1231
-        if ($echo) {
1232
-            echo wp_kses($status, AllowedTags::getAllowedTags());
1233
-            return '';
1234
-        }
1235
-        return $status;
1236
-    }
1237
-
1238
-
1239
-    /**
1240
-     * @return bool|int
1241
-     * @throws EE_Error
1242
-     * @throws ReflectionException
1243
-     */
1244
-    public function get_number_of_tickets_sold()
1245
-    {
1246
-        $tkt_sold = 0;
1247
-        if (! $this->ID()) {
1248
-            return 0;
1249
-        }
1250
-        $datetimes = $this->datetimes();
1251
-        foreach ($datetimes as $datetime) {
1252
-            if ($datetime instanceof EE_Datetime) {
1253
-                $tkt_sold += $datetime->sold();
1254
-            }
1255
-        }
1256
-        return $tkt_sold;
1257
-    }
1258
-
1259
-
1260
-    /**
1261
-     * This just returns a count of all the registrations for this event
1262
-     *
1263
-     * @return int
1264
-     * @throws EE_Error
1265
-     * @throws ReflectionException
1266
-     */
1267
-    public function get_count_of_all_registrations(): int
1268
-    {
1269
-        return EEM_Event::instance()->count_related($this, 'Registration');
1270
-    }
1271
-
1272
-
1273
-    /**
1274
-     * This returns the ticket with the earliest start time that is
1275
-     * available for this event (across all datetimes attached to the event)
1276
-     *
1277
-     * @return EE_Base_Class|EE_Ticket|null
1278
-     * @throws EE_Error
1279
-     * @throws ReflectionException
1280
-     */
1281
-    public function get_ticket_with_earliest_start_time()
1282
-    {
1283
-        $where['Datetime.EVT_ID'] = $this->ID();
1284
-        $query_params             = [$where, 'order_by' => ['TKT_start_date' => 'ASC']];
1285
-        return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1286
-    }
1287
-
1288
-
1289
-    /**
1290
-     * This returns the ticket with the latest end time that is available
1291
-     * for this event (across all datetimes attached to the event)
1292
-     *
1293
-     * @return EE_Base_Class|EE_Ticket|null
1294
-     * @throws EE_Error
1295
-     * @throws ReflectionException
1296
-     */
1297
-    public function get_ticket_with_latest_end_time()
1298
-    {
1299
-        $where['Datetime.EVT_ID'] = $this->ID();
1300
-        $query_params             = [$where, 'order_by' => ['TKT_end_date' => 'DESC']];
1301
-        return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1302
-    }
1303
-
1304
-
1305
-    /**
1306
-     * This returns the number of different ticket types currently on sale for this event.
1307
-     *
1308
-     * @return int
1309
-     * @throws EE_Error
1310
-     * @throws ReflectionException
1311
-     */
1312
-    public function countTicketsOnSale(): int
1313
-    {
1314
-        $where = [
1315
-            'Datetime.EVT_ID' => $this->ID(),
1316
-            'TKT_start_date'  => ['<', time()],
1317
-            'TKT_end_date'    => ['>', time()],
1318
-        ];
1319
-        return EEM_Ticket::instance()->count([$where]);
1320
-    }
1321
-
1322
-
1323
-    /**
1324
-     * This returns whether there are any tickets on sale for this event.
1325
-     *
1326
-     * @return bool true = YES tickets on sale.
1327
-     * @throws EE_Error
1328
-     * @throws ReflectionException
1329
-     */
1330
-    public function tickets_on_sale(): bool
1331
-    {
1332
-        return $this->countTicketsOnSale() > 0;
1333
-    }
1334
-
1335
-
1336
-    /**
1337
-     * Gets the URL for viewing this event on the front-end. Overrides parent
1338
-     * to check for an external URL first
1339
-     *
1340
-     * @return string
1341
-     * @throws EE_Error
1342
-     * @throws ReflectionException
1343
-     */
1344
-    public function get_permalink(): string
1345
-    {
1346
-        if ($this->external_url()) {
1347
-            return $this->external_url();
1348
-        }
1349
-        return parent::get_permalink();
1350
-    }
1351
-
1352
-
1353
-    /**
1354
-     * Gets the first term for 'espresso_event_categories' we can find
1355
-     *
1356
-     * @param array $query_params
1357
-     * @return EE_Base_Class|EE_Term|null
1358
-     * @throws EE_Error
1359
-     * @throws ReflectionException
1360
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1361
-     */
1362
-    public function first_event_category(array $query_params = []): ?EE_Term
1363
-    {
1364
-        $query_params[0]['Term_Taxonomy.taxonomy']     = 'espresso_event_categories';
1365
-        $query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1366
-        return EEM_Term::instance()->get_one($query_params);
1367
-    }
1368
-
1369
-
1370
-    /**
1371
-     * Gets all terms for 'espresso_event_categories' we can find
1372
-     *
1373
-     * @param array $query_params
1374
-     * @return EE_Base_Class[]|EE_Term[]
1375
-     * @throws EE_Error
1376
-     * @throws ReflectionException
1377
-     */
1378
-    public function get_all_event_categories(array $query_params = []): array
1379
-    {
1380
-        $query_params[0]['Term_Taxonomy.taxonomy']     = 'espresso_event_categories';
1381
-        $query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1382
-        return EEM_Term::instance()->get_all($query_params);
1383
-    }
1384
-
1385
-
1386
-    /**
1387
-     * Adds a question group to this event
1388
-     *
1389
-     * @param EE_Question_Group|int $question_group_id_or_obj
1390
-     * @param bool                  $for_primary if true, the question group will be added for the primary
1391
-     *                                           registrant, if false will be added for others. default: false
1392
-     * @return EE_Base_Class|EE_Question_Group
1393
-     * @throws EE_Error
1394
-     * @throws InvalidArgumentException
1395
-     * @throws InvalidDataTypeException
1396
-     * @throws InvalidInterfaceException
1397
-     * @throws ReflectionException
1398
-     */
1399
-    public function add_question_group($question_group_id_or_obj, bool $for_primary = false): EE_Question_Group
1400
-    {
1401
-        // If the row already exists, it will be updated. If it doesn't, it will be inserted.
1402
-        // That's in EE_HABTM_Relation::add_relation_to().
1403
-        return $this->_add_relation_to(
1404
-            $question_group_id_or_obj,
1405
-            'Question_Group',
1406
-            [
1407
-                EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary) => true,
1408
-            ]
1409
-        );
1410
-    }
1411
-
1412
-
1413
-    /**
1414
-     * Removes a question group from the event
1415
-     *
1416
-     * @param EE_Question_Group|int $question_group_id_or_obj
1417
-     * @param bool                  $for_primary if true, the question group will be removed from the primary
1418
-     *                                           registrant, if false will be removed from others. default: false
1419
-     * @return EE_Base_Class|EE_Question_Group|int
1420
-     * @throws EE_Error
1421
-     * @throws InvalidArgumentException
1422
-     * @throws ReflectionException
1423
-     * @throws InvalidDataTypeException
1424
-     * @throws InvalidInterfaceException
1425
-     */
1426
-    public function remove_question_group($question_group_id_or_obj, bool $for_primary = false)
1427
-    {
1428
-        // If the question group is used for the other type (primary or additional)
1429
-        // then just update it. If not, delete it outright.
1430
-        $existing_relation = $this->get_first_related(
1431
-            'Event_Question_Group',
1432
-            [
1433
-                [
1434
-                    'QSG_ID' => EEM_Question_Group::instance()->ensure_is_ID($question_group_id_or_obj),
1435
-                ],
1436
-            ]
1437
-        );
1438
-        $field_to_update   = EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary);
1439
-        $other_field       = EEM_Event_Question_Group::instance()->fieldNameForContext(! $for_primary);
1440
-        if ($existing_relation->get($other_field) === false) {
1441
-            // Delete it. It's now no longer for primary or additional question groups.
1442
-            return $this->_remove_relation_to($question_group_id_or_obj, 'Question_Group');
1443
-        }
1444
-        // Just update it. They'll still use this question group for the other category
1445
-        $existing_relation->save(
1446
-            [
1447
-                $field_to_update => false,
1448
-            ]
1449
-        );
1450
-        return $question_group_id_or_obj;
1451
-    }
1452
-
1453
-
1454
-    /**
1455
-     * Gets all the question groups, ordering them by QSG_order ascending
1456
-     *
1457
-     * @param array $query_params
1458
-     * @return EE_Base_Class[]|EE_Question_Group[]
1459
-     * @throws EE_Error
1460
-     * @throws ReflectionException
1461
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1462
-     */
1463
-    public function question_groups(array $query_params = []): array
1464
-    {
1465
-        $query_params = ! empty($query_params) ? $query_params : ['order_by' => ['QSG_order' => 'ASC']];
1466
-        return $this->get_many_related('Question_Group', $query_params);
1467
-    }
1468
-
1469
-
1470
-    /**
1471
-     * Implementation for EEI_Has_Icon interface method.
1472
-     *
1473
-     * @return string
1474
-     * @see EEI_Visual_Representation for comments
1475
-     */
1476
-    public function get_icon(): string
1477
-    {
1478
-        return '<span class="dashicons dashicons-flag"></span>';
1479
-    }
1480
-
1481
-
1482
-    /**
1483
-     * Implementation for EEI_Admin_Links interface method.
1484
-     *
1485
-     * @return string
1486
-     * @throws EE_Error
1487
-     * @throws ReflectionException
1488
-     * @see EEI_Admin_Links for comments
1489
-     */
1490
-    public function get_admin_details_link(): string
1491
-    {
1492
-        return $this->get_admin_edit_link();
1493
-    }
1494
-
1495
-
1496
-    /**
1497
-     * Implementation for EEI_Admin_Links interface method.
1498
-     *
1499
-     * @return string
1500
-     * @throws EE_Error
1501
-     * @throws ReflectionException
1502
-     * @see EEI_Admin_Links for comments
1503
-     */
1504
-    public function get_admin_edit_link(): string
1505
-    {
1506
-        return EEH_URL::add_query_args_and_nonce(
1507
-            [
1508
-                'page'   => 'espresso_events',
1509
-                'action' => 'edit',
1510
-                'post'   => $this->ID(),
1511
-            ],
1512
-            admin_url('admin.php')
1513
-        );
1514
-    }
1515
-
1516
-
1517
-    /**
1518
-     * Implementation for EEI_Admin_Links interface method.
1519
-     *
1520
-     * @return string
1521
-     * @see EEI_Admin_Links for comments
1522
-     */
1523
-    public function get_admin_settings_link(): string
1524
-    {
1525
-        return EEH_URL::add_query_args_and_nonce(
1526
-            [
1527
-                'page'   => 'espresso_events',
1528
-                'action' => 'default_event_settings',
1529
-            ],
1530
-            admin_url('admin.php')
1531
-        );
1532
-    }
1533
-
1534
-
1535
-    /**
1536
-     * Implementation for EEI_Admin_Links interface method.
1537
-     *
1538
-     * @return string
1539
-     * @see EEI_Admin_Links for comments
1540
-     */
1541
-    public function get_admin_overview_link(): string
1542
-    {
1543
-        return EEH_URL::add_query_args_and_nonce(
1544
-            [
1545
-                'page'   => 'espresso_events',
1546
-                'action' => 'default',
1547
-            ],
1548
-            admin_url('admin.php')
1549
-        );
1550
-    }
1551
-
1552
-
1553
-    /**
1554
-     * @return string|null
1555
-     * @throws EE_Error
1556
-     * @throws ReflectionException
1557
-     */
1558
-    public function registrationFormUuid(): ?string
1559
-    {
1560
-        return $this->get('FSC_UUID');
1561
-    }
1562
-
1563
-
1564
-    /**
1565
-     * Gets all the form sections for this event
1566
-     *
1567
-     * @return EE_Base_Class[]|EE_Form_Section[]
1568
-     * @throws EE_Error
1569
-     * @throws ReflectionException
1570
-     */
1571
-    public function registrationForm(): array
1572
-    {
1573
-        $FSC_UUID = $this->registrationFormUuid();
1574
-
1575
-        if (empty($FSC_UUID)) {
1576
-            return [];
1577
-        }
1578
-
1579
-        return EEM_Form_Section::instance()->get_all(
1580
-            [
1581
-                [
1582
-                    'OR' => [
1583
-                        'FSC_UUID'      => $FSC_UUID, // top level form
1584
-                        'FSC_belongsTo' => $FSC_UUID, // child form sections
1585
-                    ],
1586
-                ],
1587
-                'order_by' => ['FSC_order' => 'ASC'],
1588
-            ]
1589
-        );
1590
-    }
1591
-
1592
-
1593
-    /**
1594
-     * @param string $UUID
1595
-     * @throws EE_Error
1596
-     * @throws ReflectionException
1597
-     */
1598
-    public function setRegistrationFormUuid(string $UUID): void
1599
-    {
1600
-        if (! Cuid::isCuid($UUID)) {
1601
-            throw new InvalidArgumentException(
1602
-                sprintf(
1603
-                /* translators: 1: UUID value, 2: UUID generator function. */
1604
-                    esc_html__(
1605
-                        'The supplied UUID "%1$s" is invalid or missing. Please use %2$s to generate a valid one.',
1606
-                        'event_espresso'
1607
-                    ),
1608
-                    $UUID,
1609
-                    '`Cuid::cuid()`'
1610
-                )
1611
-            );
1612
-        }
1613
-        $this->set('FSC_UUID', $UUID);
1614
-    }
1231
+		if ($echo) {
1232
+			echo wp_kses($status, AllowedTags::getAllowedTags());
1233
+			return '';
1234
+		}
1235
+		return $status;
1236
+	}
1237
+
1238
+
1239
+	/**
1240
+	 * @return bool|int
1241
+	 * @throws EE_Error
1242
+	 * @throws ReflectionException
1243
+	 */
1244
+	public function get_number_of_tickets_sold()
1245
+	{
1246
+		$tkt_sold = 0;
1247
+		if (! $this->ID()) {
1248
+			return 0;
1249
+		}
1250
+		$datetimes = $this->datetimes();
1251
+		foreach ($datetimes as $datetime) {
1252
+			if ($datetime instanceof EE_Datetime) {
1253
+				$tkt_sold += $datetime->sold();
1254
+			}
1255
+		}
1256
+		return $tkt_sold;
1257
+	}
1258
+
1259
+
1260
+	/**
1261
+	 * This just returns a count of all the registrations for this event
1262
+	 *
1263
+	 * @return int
1264
+	 * @throws EE_Error
1265
+	 * @throws ReflectionException
1266
+	 */
1267
+	public function get_count_of_all_registrations(): int
1268
+	{
1269
+		return EEM_Event::instance()->count_related($this, 'Registration');
1270
+	}
1271
+
1272
+
1273
+	/**
1274
+	 * This returns the ticket with the earliest start time that is
1275
+	 * available for this event (across all datetimes attached to the event)
1276
+	 *
1277
+	 * @return EE_Base_Class|EE_Ticket|null
1278
+	 * @throws EE_Error
1279
+	 * @throws ReflectionException
1280
+	 */
1281
+	public function get_ticket_with_earliest_start_time()
1282
+	{
1283
+		$where['Datetime.EVT_ID'] = $this->ID();
1284
+		$query_params             = [$where, 'order_by' => ['TKT_start_date' => 'ASC']];
1285
+		return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1286
+	}
1287
+
1288
+
1289
+	/**
1290
+	 * This returns the ticket with the latest end time that is available
1291
+	 * for this event (across all datetimes attached to the event)
1292
+	 *
1293
+	 * @return EE_Base_Class|EE_Ticket|null
1294
+	 * @throws EE_Error
1295
+	 * @throws ReflectionException
1296
+	 */
1297
+	public function get_ticket_with_latest_end_time()
1298
+	{
1299
+		$where['Datetime.EVT_ID'] = $this->ID();
1300
+		$query_params             = [$where, 'order_by' => ['TKT_end_date' => 'DESC']];
1301
+		return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1302
+	}
1303
+
1304
+
1305
+	/**
1306
+	 * This returns the number of different ticket types currently on sale for this event.
1307
+	 *
1308
+	 * @return int
1309
+	 * @throws EE_Error
1310
+	 * @throws ReflectionException
1311
+	 */
1312
+	public function countTicketsOnSale(): int
1313
+	{
1314
+		$where = [
1315
+			'Datetime.EVT_ID' => $this->ID(),
1316
+			'TKT_start_date'  => ['<', time()],
1317
+			'TKT_end_date'    => ['>', time()],
1318
+		];
1319
+		return EEM_Ticket::instance()->count([$where]);
1320
+	}
1321
+
1322
+
1323
+	/**
1324
+	 * This returns whether there are any tickets on sale for this event.
1325
+	 *
1326
+	 * @return bool true = YES tickets on sale.
1327
+	 * @throws EE_Error
1328
+	 * @throws ReflectionException
1329
+	 */
1330
+	public function tickets_on_sale(): bool
1331
+	{
1332
+		return $this->countTicketsOnSale() > 0;
1333
+	}
1334
+
1335
+
1336
+	/**
1337
+	 * Gets the URL for viewing this event on the front-end. Overrides parent
1338
+	 * to check for an external URL first
1339
+	 *
1340
+	 * @return string
1341
+	 * @throws EE_Error
1342
+	 * @throws ReflectionException
1343
+	 */
1344
+	public function get_permalink(): string
1345
+	{
1346
+		if ($this->external_url()) {
1347
+			return $this->external_url();
1348
+		}
1349
+		return parent::get_permalink();
1350
+	}
1351
+
1352
+
1353
+	/**
1354
+	 * Gets the first term for 'espresso_event_categories' we can find
1355
+	 *
1356
+	 * @param array $query_params
1357
+	 * @return EE_Base_Class|EE_Term|null
1358
+	 * @throws EE_Error
1359
+	 * @throws ReflectionException
1360
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1361
+	 */
1362
+	public function first_event_category(array $query_params = []): ?EE_Term
1363
+	{
1364
+		$query_params[0]['Term_Taxonomy.taxonomy']     = 'espresso_event_categories';
1365
+		$query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1366
+		return EEM_Term::instance()->get_one($query_params);
1367
+	}
1368
+
1369
+
1370
+	/**
1371
+	 * Gets all terms for 'espresso_event_categories' we can find
1372
+	 *
1373
+	 * @param array $query_params
1374
+	 * @return EE_Base_Class[]|EE_Term[]
1375
+	 * @throws EE_Error
1376
+	 * @throws ReflectionException
1377
+	 */
1378
+	public function get_all_event_categories(array $query_params = []): array
1379
+	{
1380
+		$query_params[0]['Term_Taxonomy.taxonomy']     = 'espresso_event_categories';
1381
+		$query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1382
+		return EEM_Term::instance()->get_all($query_params);
1383
+	}
1384
+
1385
+
1386
+	/**
1387
+	 * Adds a question group to this event
1388
+	 *
1389
+	 * @param EE_Question_Group|int $question_group_id_or_obj
1390
+	 * @param bool                  $for_primary if true, the question group will be added for the primary
1391
+	 *                                           registrant, if false will be added for others. default: false
1392
+	 * @return EE_Base_Class|EE_Question_Group
1393
+	 * @throws EE_Error
1394
+	 * @throws InvalidArgumentException
1395
+	 * @throws InvalidDataTypeException
1396
+	 * @throws InvalidInterfaceException
1397
+	 * @throws ReflectionException
1398
+	 */
1399
+	public function add_question_group($question_group_id_or_obj, bool $for_primary = false): EE_Question_Group
1400
+	{
1401
+		// If the row already exists, it will be updated. If it doesn't, it will be inserted.
1402
+		// That's in EE_HABTM_Relation::add_relation_to().
1403
+		return $this->_add_relation_to(
1404
+			$question_group_id_or_obj,
1405
+			'Question_Group',
1406
+			[
1407
+				EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary) => true,
1408
+			]
1409
+		);
1410
+	}
1411
+
1412
+
1413
+	/**
1414
+	 * Removes a question group from the event
1415
+	 *
1416
+	 * @param EE_Question_Group|int $question_group_id_or_obj
1417
+	 * @param bool                  $for_primary if true, the question group will be removed from the primary
1418
+	 *                                           registrant, if false will be removed from others. default: false
1419
+	 * @return EE_Base_Class|EE_Question_Group|int
1420
+	 * @throws EE_Error
1421
+	 * @throws InvalidArgumentException
1422
+	 * @throws ReflectionException
1423
+	 * @throws InvalidDataTypeException
1424
+	 * @throws InvalidInterfaceException
1425
+	 */
1426
+	public function remove_question_group($question_group_id_or_obj, bool $for_primary = false)
1427
+	{
1428
+		// If the question group is used for the other type (primary or additional)
1429
+		// then just update it. If not, delete it outright.
1430
+		$existing_relation = $this->get_first_related(
1431
+			'Event_Question_Group',
1432
+			[
1433
+				[
1434
+					'QSG_ID' => EEM_Question_Group::instance()->ensure_is_ID($question_group_id_or_obj),
1435
+				],
1436
+			]
1437
+		);
1438
+		$field_to_update   = EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary);
1439
+		$other_field       = EEM_Event_Question_Group::instance()->fieldNameForContext(! $for_primary);
1440
+		if ($existing_relation->get($other_field) === false) {
1441
+			// Delete it. It's now no longer for primary or additional question groups.
1442
+			return $this->_remove_relation_to($question_group_id_or_obj, 'Question_Group');
1443
+		}
1444
+		// Just update it. They'll still use this question group for the other category
1445
+		$existing_relation->save(
1446
+			[
1447
+				$field_to_update => false,
1448
+			]
1449
+		);
1450
+		return $question_group_id_or_obj;
1451
+	}
1452
+
1453
+
1454
+	/**
1455
+	 * Gets all the question groups, ordering them by QSG_order ascending
1456
+	 *
1457
+	 * @param array $query_params
1458
+	 * @return EE_Base_Class[]|EE_Question_Group[]
1459
+	 * @throws EE_Error
1460
+	 * @throws ReflectionException
1461
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1462
+	 */
1463
+	public function question_groups(array $query_params = []): array
1464
+	{
1465
+		$query_params = ! empty($query_params) ? $query_params : ['order_by' => ['QSG_order' => 'ASC']];
1466
+		return $this->get_many_related('Question_Group', $query_params);
1467
+	}
1468
+
1469
+
1470
+	/**
1471
+	 * Implementation for EEI_Has_Icon interface method.
1472
+	 *
1473
+	 * @return string
1474
+	 * @see EEI_Visual_Representation for comments
1475
+	 */
1476
+	public function get_icon(): string
1477
+	{
1478
+		return '<span class="dashicons dashicons-flag"></span>';
1479
+	}
1480
+
1481
+
1482
+	/**
1483
+	 * Implementation for EEI_Admin_Links interface method.
1484
+	 *
1485
+	 * @return string
1486
+	 * @throws EE_Error
1487
+	 * @throws ReflectionException
1488
+	 * @see EEI_Admin_Links for comments
1489
+	 */
1490
+	public function get_admin_details_link(): string
1491
+	{
1492
+		return $this->get_admin_edit_link();
1493
+	}
1494
+
1495
+
1496
+	/**
1497
+	 * Implementation for EEI_Admin_Links interface method.
1498
+	 *
1499
+	 * @return string
1500
+	 * @throws EE_Error
1501
+	 * @throws ReflectionException
1502
+	 * @see EEI_Admin_Links for comments
1503
+	 */
1504
+	public function get_admin_edit_link(): string
1505
+	{
1506
+		return EEH_URL::add_query_args_and_nonce(
1507
+			[
1508
+				'page'   => 'espresso_events',
1509
+				'action' => 'edit',
1510
+				'post'   => $this->ID(),
1511
+			],
1512
+			admin_url('admin.php')
1513
+		);
1514
+	}
1515
+
1516
+
1517
+	/**
1518
+	 * Implementation for EEI_Admin_Links interface method.
1519
+	 *
1520
+	 * @return string
1521
+	 * @see EEI_Admin_Links for comments
1522
+	 */
1523
+	public function get_admin_settings_link(): string
1524
+	{
1525
+		return EEH_URL::add_query_args_and_nonce(
1526
+			[
1527
+				'page'   => 'espresso_events',
1528
+				'action' => 'default_event_settings',
1529
+			],
1530
+			admin_url('admin.php')
1531
+		);
1532
+	}
1533
+
1534
+
1535
+	/**
1536
+	 * Implementation for EEI_Admin_Links interface method.
1537
+	 *
1538
+	 * @return string
1539
+	 * @see EEI_Admin_Links for comments
1540
+	 */
1541
+	public function get_admin_overview_link(): string
1542
+	{
1543
+		return EEH_URL::add_query_args_and_nonce(
1544
+			[
1545
+				'page'   => 'espresso_events',
1546
+				'action' => 'default',
1547
+			],
1548
+			admin_url('admin.php')
1549
+		);
1550
+	}
1551
+
1552
+
1553
+	/**
1554
+	 * @return string|null
1555
+	 * @throws EE_Error
1556
+	 * @throws ReflectionException
1557
+	 */
1558
+	public function registrationFormUuid(): ?string
1559
+	{
1560
+		return $this->get('FSC_UUID');
1561
+	}
1562
+
1563
+
1564
+	/**
1565
+	 * Gets all the form sections for this event
1566
+	 *
1567
+	 * @return EE_Base_Class[]|EE_Form_Section[]
1568
+	 * @throws EE_Error
1569
+	 * @throws ReflectionException
1570
+	 */
1571
+	public function registrationForm(): array
1572
+	{
1573
+		$FSC_UUID = $this->registrationFormUuid();
1574
+
1575
+		if (empty($FSC_UUID)) {
1576
+			return [];
1577
+		}
1578
+
1579
+		return EEM_Form_Section::instance()->get_all(
1580
+			[
1581
+				[
1582
+					'OR' => [
1583
+						'FSC_UUID'      => $FSC_UUID, // top level form
1584
+						'FSC_belongsTo' => $FSC_UUID, // child form sections
1585
+					],
1586
+				],
1587
+				'order_by' => ['FSC_order' => 'ASC'],
1588
+			]
1589
+		);
1590
+	}
1591
+
1592
+
1593
+	/**
1594
+	 * @param string $UUID
1595
+	 * @throws EE_Error
1596
+	 * @throws ReflectionException
1597
+	 */
1598
+	public function setRegistrationFormUuid(string $UUID): void
1599
+	{
1600
+		if (! Cuid::isCuid($UUID)) {
1601
+			throw new InvalidArgumentException(
1602
+				sprintf(
1603
+				/* translators: 1: UUID value, 2: UUID generator function. */
1604
+					esc_html__(
1605
+						'The supplied UUID "%1$s" is invalid or missing. Please use %2$s to generate a valid one.',
1606
+						'event_espresso'
1607
+					),
1608
+					$UUID,
1609
+					'`Cuid::cuid()`'
1610
+				)
1611
+			);
1612
+		}
1613
+		$this->set('FSC_UUID', $UUID);
1614
+	}
1615 1615
 }
Please login to merge, or discard this patch.