Completed
Branch BUG/work-with-wp-41305 (56ac34)
by
unknown
288:30 queued 222:48
created

EE_Event::order()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
use EventEspresso\core\domain\services\event\EventSpacesCalculator;
4
use EventEspresso\core\exceptions\UnexpectedEntityException;
5
6
/**
7
 * EE_Event
8
 *
9
 * @package               Event Espresso
10
 * @subpackage            includes/models/
11
 * @author                Mike Nelson
12
 */
13
class EE_Event extends EE_CPT_Base implements EEI_Line_Item_Object, EEI_Admin_Links, EEI_Has_Icon, EEI_Event
14
{
15
16
    /**
17
     * cached value for the the logical active status for the event
18
     *
19
     * @see get_active_status()
20
     * @var string
21
     */
22
    protected $_active_status = '';
23
24
    /**
25
     * This is just used for caching the Primary Datetime for the Event on initial retrieval
26
     *
27
     * @var EE_Datetime
28
     */
29
    protected $_Primary_Datetime;
30
31
    /**
32
     * @var EventSpacesCalculator $available_spaces_calculator
33
     */
34
    protected $available_spaces_calculator;
35
36
37
    /**
38
     * @param array  $props_n_values          incoming values
39
     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
40
     *                                        used.)
41
     * @param array  $date_formats            incoming date_formats in an array where the first value is the
42
     *                                        date_format and the second value is the time format
43
     * @return EE_Event
44
     * @throws EE_Error
45
     */
46
    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
47
    {
48
        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
49
        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
50
    }
51
52
53
    /**
54
     * @param array  $props_n_values  incoming values from the database
55
     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
56
     *                                the website will be used.
57
     * @return EE_Event
58
     * @throws EE_Error
59
     */
60
    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
61
    {
62
        return new self($props_n_values, true, $timezone);
63
    }
64
65
66
    /**
67
     * @return EventSpacesCalculator
68
     * @throws \EE_Error
69
     */
70
    public function getAvailableSpacesCalculator()
71
    {
72
        if (! $this->available_spaces_calculator instanceof EventSpacesCalculator) {
73
            $this->available_spaces_calculator = new EventSpacesCalculator($this);
74
        }
75
        return $this->available_spaces_calculator;
76
    }
77
78
79
    /**
80
     * Overrides parent set() method so that all calls to set( 'status', $status ) can be routed to internal methods
81
     *
82
     * @param string $field_name
83
     * @param mixed  $field_value
84
     * @param bool   $use_default
85
     * @throws EE_Error
86
     */
87
    public function set($field_name, $field_value, $use_default = false)
88
    {
89
        switch ($field_name) {
90
            case 'status':
91
                $this->set_status($field_value, $use_default);
92
                break;
93
            default:
94
                parent::set($field_name, $field_value, $use_default);
95
        }
96
    }
97
98
99
    /**
100
     *    set_status
101
     * Checks if event status is being changed to SOLD OUT
102
     * and updates event meta data with previous event status
103
     * so that we can revert things if/when the event is no longer sold out
104
     *
105
     * @access public
106
     * @param string $new_status
107
     * @param bool   $use_default
108
     * @return void
109
     * @throws EE_Error
110
     */
111
    public function set_status($new_status = null, $use_default = false)
112
    {
113
        // if nothing is set, and we aren't explicitly wanting to reset the status, then just leave
114
        if (empty($new_status) && ! $use_default) {
115
            return;
116
        }
117
        // get current Event status
118
        $old_status = $this->status();
119
        // if status has changed
120
        if ($old_status !== $new_status) {
121
            // TO sold_out
122
            if ($new_status === EEM_Event::sold_out) {
123
                // save the previous event status so that we can revert if the event is no longer sold out
124
                $this->add_post_meta('_previous_event_status', $old_status);
125
                do_action('AHEE__EE_Event__set_status__to_sold_out', $this, $old_status, $new_status);
126
                // OR FROM  sold_out
127
            } elseif ($old_status === EEM_Event::sold_out) {
128
                $this->delete_post_meta('_previous_event_status');
129
                do_action('AHEE__EE_Event__set_status__from_sold_out', $this, $old_status, $new_status);
130
            }
131
            // clear out the active status so that it gets reset the next time it is requested
132
            $this->_active_status = null;
133
            // update status
134
            parent::set('status', $new_status, $use_default);
135
            do_action('AHEE__EE_Event__set_status__after_update', $this);
136
            return;
137
        }
138
        // even though the old value matches the new value, it's still good to
139
        // allow the parent set method to have a say
140
        parent::set('status', $new_status, $use_default);
141
    }
142
143
144
    /**
145
     * Gets all the datetimes for this event
146
     *
147
     * @param array $query_params like EEM_Base::get_all
148
     * @return EE_Base_Class[]|EE_Datetime[]
149
     * @throws EE_Error
150
     */
151
    public function datetimes($query_params = array())
152
    {
153
        return $this->get_many_related('Datetime', $query_params);
154
    }
155
156
157
    /**
158
     * Gets all the datetimes for this event, ordered by DTT_EVT_start in ascending order
159
     *
160
     * @return EE_Base_Class[]|EE_Datetime[]
161
     * @throws EE_Error
162
     */
163
    public function datetimes_in_chronological_order()
164
    {
165
        return $this->get_many_related('Datetime', array('order_by' => array('DTT_EVT_start' => 'ASC')));
166
    }
167
168
169
    /**
170
     * Gets all the datetimes for this event, ordered by the DTT_order on the datetime.
171
     * @darren, we should probably UNSET timezone on the EEM_Datetime model
172
     * after running our query, so that this timezone isn't set for EVERY query
173
     * on EEM_Datetime for the rest of the request, no?
174
     *
175
     * @param boolean $show_expired whether or not to include expired events
176
     * @param boolean $show_deleted whether or not to include deleted events
177
     * @param null    $limit
178
     * @return EE_Datetime[]
179
     * @throws EE_Error
180
     */
181
    public function datetimes_ordered($show_expired = true, $show_deleted = false, $limit = null)
182
    {
183
        return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_event_ordered_by_DTT_order(
184
            $this->ID(),
185
            $show_expired,
186
            $show_deleted,
187
            $limit
188
        );
189
    }
190
191
192
    /**
193
     * Returns one related datetime. Mostly only used by some legacy code.
194
     *
195
     * @return EE_Base_Class|EE_Datetime
196
     * @throws EE_Error
197
     */
198
    public function first_datetime()
199
    {
200
        return $this->get_first_related('Datetime');
201
    }
202
203
204
    /**
205
     * Returns the 'primary' datetime for the event
206
     *
207
     * @param bool $try_to_exclude_expired
208
     * @param bool $try_to_exclude_deleted
209
     * @return EE_Datetime
210
     * @throws EE_Error
211
     */
212
    public function primary_datetime($try_to_exclude_expired = true, $try_to_exclude_deleted = true)
213
    {
214
        if (! empty($this->_Primary_Datetime)) {
215
            return $this->_Primary_Datetime;
216
        }
217
        $this->_Primary_Datetime = EEM_Datetime::instance($this->_timezone)->get_primary_datetime_for_event(
218
            $this->ID(),
219
            $try_to_exclude_expired,
220
            $try_to_exclude_deleted
221
        );
222
        return $this->_Primary_Datetime;
223
    }
224
225
226
    /**
227
     * Gets all the tickets available for purchase of this event
228
     *
229
     * @param array $query_params like EEM_Base::get_all
230
     * @return EE_Base_Class[]|EE_Ticket[]
231
     * @throws EE_Error
232
     */
233
    public function tickets($query_params = array())
234
    {
235
        // first get all datetimes
236
        $datetimes = $this->datetimes_ordered();
237
        if (! $datetimes) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $datetimes of type EE_Datetime[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
238
            return array();
239
        }
240
        $datetime_ids = array();
241
        foreach ($datetimes as $datetime) {
242
            $datetime_ids[] = $datetime->ID();
243
        }
244
        $where_params = array('Datetime.DTT_ID' => array('IN', $datetime_ids));
245
        // if incoming $query_params has where conditions let's merge but not override existing.
246
        if (is_array($query_params) && isset($query_params[0])) {
247
            $where_params = array_merge($query_params[0], $where_params);
248
            unset($query_params[0]);
249
        }
250
        // now add $where_params to $query_params
251
        $query_params[0] = $where_params;
252
        return EEM_Ticket::instance()->get_all($query_params);
253
    }
254
255
256
    /**
257
     * get all unexpired untrashed tickets
258
     *
259
     * @return EE_Ticket[]
260
     * @throws EE_Error
261
     */
262
    public function active_tickets()
263
    {
264
        return $this->tickets(
265
            array(
266
                array(
267
                    'TKT_end_date' => array('>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')),
268
                    'TKT_deleted'  => false,
269
                ),
270
            )
271
        );
272
    }
273
274
275
    /**
276
     * @return bool
277
     * @throws EE_Error
278
     */
279
    public function additional_limit()
280
    {
281
        return $this->get('EVT_additional_limit');
282
    }
283
284
285
    /**
286
     * @return bool
287
     * @throws EE_Error
288
     */
289
    public function allow_overflow()
290
    {
291
        return $this->get('EVT_allow_overflow');
292
    }
293
294
295
    /**
296
     * @return bool
297
     * @throws EE_Error
298
     */
299
    public function created()
300
    {
301
        return $this->get('EVT_created');
302
    }
303
304
305
    /**
306
     * @return bool
307
     * @throws EE_Error
308
     */
309
    public function description()
310
    {
311
        return $this->get('EVT_desc');
312
    }
313
314
315
    /**
316
     * Runs do_shortcode and wpautop on the description
317
     *
318
     * @return string of html
319
     * @throws EE_Error
320
     */
321
    public function description_filtered()
322
    {
323
        return $this->get_pretty('EVT_desc');
324
    }
325
326
327
    /**
328
     * @return bool
329
     * @throws EE_Error
330
     */
331
    public function display_description()
332
    {
333
        return $this->get('EVT_display_desc');
334
    }
335
336
337
    /**
338
     * @return bool
339
     * @throws EE_Error
340
     */
341
    public function display_ticket_selector()
342
    {
343
        return (bool) $this->get('EVT_display_ticket_selector');
344
    }
345
346
347
    /**
348
     * @return bool
349
     * @throws EE_Error
350
     */
351
    public function external_url()
352
    {
353
        return $this->get('EVT_external_URL');
354
    }
355
356
357
    /**
358
     * @return bool
359
     * @throws EE_Error
360
     */
361
    public function member_only()
362
    {
363
        return $this->get('EVT_member_only');
364
    }
365
366
367
    /**
368
     * @return bool
369
     * @throws EE_Error
370
     */
371
    public function phone()
372
    {
373
        return $this->get('EVT_phone');
374
    }
375
376
377
    /**
378
     * @return bool
379
     * @throws EE_Error
380
     */
381
    public function modified()
382
    {
383
        return $this->get('EVT_modified');
384
    }
385
386
387
    /**
388
     * @return bool
389
     * @throws EE_Error
390
     */
391
    public function name()
392
    {
393
        return $this->get('EVT_name');
394
    }
395
396
397
    /**
398
     * @return bool
399
     * @throws EE_Error
400
     */
401
    public function order()
402
    {
403
        return $this->get('EVT_order');
404
    }
405
406
407
    /**
408
     * @return bool|string
409
     * @throws EE_Error
410
     */
411
    public function default_registration_status()
412
    {
413
        $event_default_registration_status = $this->get('EVT_default_registration_status');
414
        return ! empty($event_default_registration_status)
415
            ? $event_default_registration_status
416
            : EE_Registry::instance()->CFG->registration->default_STS_ID;
417
    }
418
419
420
    /**
421
     * @param int  $num_words
422
     * @param null $more
423
     * @param bool $not_full_desc
424
     * @return bool|string
425
     * @throws EE_Error
426
     */
427
    public function short_description($num_words = 55, $more = null, $not_full_desc = false)
428
    {
429
        $short_desc = $this->get('EVT_short_desc');
430
        if (! empty($short_desc) || $not_full_desc) {
431
            return $short_desc;
432
        }
433
        $full_desc = $this->get('EVT_desc');
434
        return wp_trim_words($full_desc, $num_words, $more);
435
    }
436
437
438
    /**
439
     * @return bool
440
     * @throws EE_Error
441
     */
442
    public function slug()
443
    {
444
        return $this->get('EVT_slug');
445
    }
446
447
448
    /**
449
     * @return bool
450
     * @throws EE_Error
451
     */
452
    public function timezone_string()
453
    {
454
        return $this->get('EVT_timezone_string');
455
    }
456
457
458
    /**
459
     * @return bool
460
     * @throws EE_Error
461
     */
462
    public function visible_on()
463
    {
464
        return $this->get('EVT_visible_on');
465
    }
466
467
468
    /**
469
     * @return int
470
     * @throws EE_Error
471
     */
472
    public function wp_user()
473
    {
474
        return $this->get('EVT_wp_user');
475
    }
476
477
478
    /**
479
     * @return bool
480
     * @throws EE_Error
481
     */
482
    public function donations()
483
    {
484
        return $this->get('EVT_donations');
485
    }
486
487
488
    /**
489
     * @param $limit
490
     * @throws EE_Error
491
     */
492
    public function set_additional_limit($limit)
493
    {
494
        $this->set('EVT_additional_limit', $limit);
495
    }
496
497
498
    /**
499
     * @param $created
500
     * @throws EE_Error
501
     */
502
    public function set_created($created)
503
    {
504
        $this->set('EVT_created', $created);
505
    }
506
507
508
    /**
509
     * @param $desc
510
     * @throws EE_Error
511
     */
512
    public function set_description($desc)
513
    {
514
        $this->set('EVT_desc', $desc);
515
    }
516
517
518
    /**
519
     * @param $display_desc
520
     * @throws EE_Error
521
     */
522
    public function set_display_description($display_desc)
523
    {
524
        $this->set('EVT_display_desc', $display_desc);
525
    }
526
527
528
    /**
529
     * @param $display_ticket_selector
530
     * @throws EE_Error
531
     */
532
    public function set_display_ticket_selector($display_ticket_selector)
533
    {
534
        $this->set('EVT_display_ticket_selector', $display_ticket_selector);
535
    }
536
537
538
    /**
539
     * @param $external_url
540
     * @throws EE_Error
541
     */
542
    public function set_external_url($external_url)
543
    {
544
        $this->set('EVT_external_URL', $external_url);
545
    }
546
547
548
    /**
549
     * @param $member_only
550
     * @throws EE_Error
551
     */
552
    public function set_member_only($member_only)
553
    {
554
        $this->set('EVT_member_only', $member_only);
555
    }
556
557
558
    /**
559
     * @param $event_phone
560
     * @throws EE_Error
561
     */
562
    public function set_event_phone($event_phone)
563
    {
564
        $this->set('EVT_phone', $event_phone);
565
    }
566
567
568
    /**
569
     * @param $modified
570
     * @throws EE_Error
571
     */
572
    public function set_modified($modified)
573
    {
574
        $this->set('EVT_modified', $modified);
575
    }
576
577
578
    /**
579
     * @param $name
580
     * @throws EE_Error
581
     */
582
    public function set_name($name)
583
    {
584
        $this->set('EVT_name', $name);
585
    }
586
587
588
    /**
589
     * @param $order
590
     * @throws EE_Error
591
     */
592
    public function set_order($order)
593
    {
594
        $this->set('EVT_order', $order);
595
    }
596
597
598
    /**
599
     * @param $short_desc
600
     * @throws EE_Error
601
     */
602
    public function set_short_description($short_desc)
603
    {
604
        $this->set('EVT_short_desc', $short_desc);
605
    }
606
607
608
    /**
609
     * @param $slug
610
     * @throws EE_Error
611
     */
612
    public function set_slug($slug)
613
    {
614
        $this->set('EVT_slug', $slug);
615
    }
616
617
618
    /**
619
     * @param $timezone_string
620
     * @throws EE_Error
621
     */
622
    public function set_timezone_string($timezone_string)
623
    {
624
        $this->set('EVT_timezone_string', $timezone_string);
625
    }
626
627
628
    /**
629
     * @param $visible_on
630
     * @throws EE_Error
631
     */
632
    public function set_visible_on($visible_on)
633
    {
634
        $this->set('EVT_visible_on', $visible_on);
635
    }
636
637
638
    /**
639
     * @param $wp_user
640
     * @throws EE_Error
641
     */
642
    public function set_wp_user($wp_user)
643
    {
644
        $this->set('EVT_wp_user', $wp_user);
645
    }
646
647
648
    /**
649
     * @param $default_registration_status
650
     * @throws EE_Error
651
     */
652
    public function set_default_registration_status($default_registration_status)
653
    {
654
        $this->set('EVT_default_registration_status', $default_registration_status);
655
    }
656
657
658
    /**
659
     * @param $donations
660
     * @throws EE_Error
661
     */
662
    public function set_donations($donations)
663
    {
664
        $this->set('EVT_donations', $donations);
665
    }
666
667
668
    /**
669
     * Adds a venue to this event
670
     *
671
     * @param EE_Venue /int $venue_id_or_obj
672
     * @return EE_Base_Class|EE_Venue
673
     * @throws EE_Error
674
     */
675
    public function add_venue($venue_id_or_obj)
676
    {
677
        return $this->_add_relation_to($venue_id_or_obj, 'Venue');
678
    }
679
680
681
    /**
682
     * Removes a venue from the event
683
     *
684
     * @param EE_Venue /int $venue_id_or_obj
685
     * @return EE_Base_Class|EE_Venue
686
     * @throws EE_Error
687
     */
688
    public function remove_venue($venue_id_or_obj)
689
    {
690
        return $this->_remove_relation_to($venue_id_or_obj, 'Venue');
691
    }
692
693
694
    /**
695
     * Gets all the venues related ot the event. May provide additional $query_params if desired
696
     *
697
     * @param array $query_params like EEM_Base::get_all's $query_params
698
     * @return EE_Base_Class[]|EE_Venue[]
699
     * @throws EE_Error
700
     */
701
    public function venues($query_params = array())
702
    {
703
        return $this->get_many_related('Venue', $query_params);
704
    }
705
706
707
    /**
708
     * check if event id is present and if event is published
709
     *
710
     * @access public
711
     * @return boolean true yes, false no
712
     * @throws EE_Error
713
     */
714
    private function _has_ID_and_is_published()
715
    {
716
        // first check if event id is present and not NULL,
717
        // then check if this event is published (or any of the equivalent "published" statuses)
718
        return
719
            $this->ID() && $this->ID() !== null
720
            && (
721
                $this->status() === 'publish'
722
                || $this->status() === EEM_Event::sold_out
723
                || $this->status() === EEM_Event::postponed
724
                || $this->status() === EEM_Event::cancelled
725
            );
726
    }
727
728
729
    /**
730
     * This simply compares the internal dates with NOW and determines if the event is upcoming or not.
731
     *
732
     * @access public
733
     * @return boolean true yes, false no
734
     * @throws EE_Error
735
     */
736 View Code Duplication
    public function is_upcoming()
737
    {
738
        // check if event id is present and if this event is published
739
        if ($this->is_inactive()) {
740
            return false;
741
        }
742
        // set initial value
743
        $upcoming = false;
744
        // next let's get all datetimes and loop through them
745
        $datetimes = $this->datetimes_in_chronological_order();
746
        foreach ($datetimes as $datetime) {
747
            if ($datetime instanceof EE_Datetime) {
748
                // if this dtt is expired then we continue cause one of the other datetimes might be upcoming.
749
                if ($datetime->is_expired()) {
750
                    continue;
751
                }
752
                // if this dtt is active then we return false.
753
                if ($datetime->is_active()) {
754
                    return false;
755
                }
756
                // otherwise let's check upcoming status
757
                $upcoming = $datetime->is_upcoming();
758
            }
759
        }
760
        return $upcoming;
761
    }
762
763
764
    /**
765
     * @return bool
766
     * @throws EE_Error
767
     */
768 View Code Duplication
    public function is_active()
769
    {
770
        // check if event id is present and if this event is published
771
        if ($this->is_inactive()) {
772
            return false;
773
        }
774
        // set initial value
775
        $active = false;
776
        // next let's get all datetimes and loop through them
777
        $datetimes = $this->datetimes_in_chronological_order();
778
        foreach ($datetimes as $datetime) {
779
            if ($datetime instanceof EE_Datetime) {
780
                // if this dtt is expired then we continue cause one of the other datetimes might be active.
781
                if ($datetime->is_expired()) {
782
                    continue;
783
                }
784
                // if this dtt is upcoming then we return false.
785
                if ($datetime->is_upcoming()) {
786
                    return false;
787
                }
788
                // otherwise let's check active status
789
                $active = $datetime->is_active();
790
            }
791
        }
792
        return $active;
793
    }
794
795
796
    /**
797
     * @return bool
798
     * @throws EE_Error
799
     */
800 View Code Duplication
    public function is_expired()
801
    {
802
        // check if event id is present and if this event is published
803
        if ($this->is_inactive()) {
804
            return false;
805
        }
806
        // set initial value
807
        $expired = false;
808
        // first let's get all datetimes and loop through them
809
        $datetimes = $this->datetimes_in_chronological_order();
810
        foreach ($datetimes as $datetime) {
811
            if ($datetime instanceof EE_Datetime) {
812
                // if this dtt is upcoming or active then we return false.
813
                if ($datetime->is_upcoming() || $datetime->is_active()) {
814
                    return false;
815
                }
816
                // otherwise let's check active status
817
                $expired = $datetime->is_expired();
818
            }
819
        }
820
        return $expired;
821
    }
822
823
824
    /**
825
     * @return bool
826
     * @throws EE_Error
827
     */
828
    public function is_inactive()
829
    {
830
        // check if event id is present and if this event is published
831
        if ($this->_has_ID_and_is_published()) {
832
            return false;
833
        }
834
        return true;
835
    }
836
837
838
    /**
839
     * calculate spaces remaining based on "saleable" tickets
840
     *
841
     * @param array $tickets
842
     * @param bool  $filtered
843
     * @return int|float
844
     * @throws EE_Error
845
     * @throws DomainException
846
     * @throws UnexpectedEntityException
847
     */
848
    public function spaces_remaining($tickets = array(), $filtered = true)
849
    {
850
        $this->getAvailableSpacesCalculator()->setActiveTickets($tickets);
851
        $spaces_remaining = $this->getAvailableSpacesCalculator()->spacesRemaining();
852
        return $filtered
853
            ? apply_filters(
854
                'FHEE_EE_Event__spaces_remaining',
855
                $spaces_remaining,
856
                $this,
857
                $tickets
858
            )
859
            : $spaces_remaining;
860
    }
861
862
863
    /**
864
     *    perform_sold_out_status_check
865
     *    checks all of this events's datetime  reg_limit - sold values to determine if ANY datetimes have spaces
866
     *    available... if NOT, then the event status will get toggled to 'sold_out'
867
     *
868
     * @return bool    return the ACTUAL sold out state.
869
     * @throws EE_Error
870
     * @throws DomainException
871
     * @throws UnexpectedEntityException
872
     */
873
    public function perform_sold_out_status_check()
874
    {
875
        // get all unexpired untrashed tickets
876
        $tickets = $this->tickets(
877
            array(
878
                array('TKT_deleted' => false),
879
                'order_by' => array('TKT_qty' => 'ASC'),
880
            )
881
        );
882
        $all_expired = true;
883
        foreach ($tickets as $ticket) {
884
            if (! $ticket->is_expired()) {
885
                $all_expired = false;
886
                break;
887
            }
888
        }
889
        // if all the tickets are just expired, then don't update the event status to sold out
890
        if ($all_expired) {
891
            return true;
892
        }
893
        $spaces_remaining = $this->spaces_remaining($tickets);
894
        if ($spaces_remaining < 1) {
895
            $this->set_status(EEM_Event::sold_out);
896
            $this->save();
897
            $sold_out = true;
898
        } else {
899
            $sold_out = false;
900
            // was event previously marked as sold out ?
901
            if ($this->status() === EEM_Event::sold_out) {
902
                // revert status to previous value, if it was set
903
                $previous_event_status = $this->get_post_meta('_previous_event_status', true);
904
                if ($previous_event_status) {
905
                    $this->set_status($previous_event_status);
906
                    $this->save();
907
                }
908
            }
909
        }
910
        do_action('AHEE__EE_Event__perform_sold_out_status_check__end', $this, $sold_out, $spaces_remaining, $tickets);
911
        return $sold_out;
912
    }
913
914
915
    /**
916
     * This returns the total remaining spaces for sale on this event.
917
     *
918
     * @uses EE_Event::total_available_spaces()
919
     * @return float|int
920
     * @throws EE_Error
921
     * @throws DomainException
922
     * @throws UnexpectedEntityException
923
     */
924
    public function spaces_remaining_for_sale()
925
    {
926
        return $this->total_available_spaces(true);
927
    }
928
929
930
    /**
931
     * This returns the total spaces available for an event
932
     * while considering all the qtys on the tickets and the reg limits
933
     * on the datetimes attached to this event.
934
     *
935
     * @param   bool $consider_sold Whether to consider any tickets that have already sold in our calculation.
936
     *                              If this is false, then we return the most tickets that could ever be sold
937
     *                              for this event with the datetime and tickets setup on the event under optimal
938
     *                              selling conditions.  Otherwise we return a live calculation of spaces available
939
     *                              based on tickets sold.  Depending on setup and stage of sales, this
940
     *                              may appear to equal remaining tickets.  However, the more tickets are
941
     *                              sold out, the more accurate the "live" total is.
942
     * @return float|int
943
     * @throws EE_Error
944
     * @throws DomainException
945
     * @throws UnexpectedEntityException
946
     */
947
    public function total_available_spaces($consider_sold = false)
948
    {
949
        $spaces_available = $consider_sold
950
            ? $this->getAvailableSpacesCalculator()->spacesRemaining()
951
            : $this->getAvailableSpacesCalculator()->totalSpacesAvailable();
952
        return apply_filters(
953
            'FHEE_EE_Event__total_available_spaces__spaces_available',
954
            $spaces_available,
955
            $this,
956
            $this->getAvailableSpacesCalculator()->getDatetimes(),
957
            $this->getAvailableSpacesCalculator()->getActiveTickets()
958
        );
959
    }
960
961
962
    /**
963
     * Checks if the event is set to sold out
964
     *
965
     * @param  bool $actual whether or not to perform calculations to not only figure the
966
     *                      actual status but also to flip the status if necessary to sold
967
     *                      out If false, we just check the existing status of the event
968
     * @return boolean
969
     * @throws EE_Error
970
     */
971
    public function is_sold_out($actual = false)
972
    {
973
        if (! $actual) {
974
            return $this->status() === EEM_Event::sold_out;
975
        }
976
        return $this->perform_sold_out_status_check();
977
    }
978
979
980
    /**
981
     * Checks if the event is marked as postponed
982
     *
983
     * @return boolean
984
     */
985
    public function is_postponed()
986
    {
987
        return $this->status() === EEM_Event::postponed;
988
    }
989
990
991
    /**
992
     * Checks if the event is marked as cancelled
993
     *
994
     * @return boolean
995
     */
996
    public function is_cancelled()
997
    {
998
        return $this->status() === EEM_Event::cancelled;
999
    }
1000
1001
1002
    /**
1003
     * Get the logical active status in a hierarchical order for all the datetimes.  Note
1004
     * Basically, we order the datetimes by EVT_start_date.  Then first test on whether the event is published.  If its
1005
     * NOT published then we test for whether its expired or not.  IF it IS published then we test first on whether an
1006
     * event has any active dates.  If no active dates then we check for any upcoming dates.  If no upcoming dates then
1007
     * the event is considered expired.
1008
     * NOTE: this method does NOT calculate whether the datetimes are sold out when event is published.  Sold Out is a
1009
     * status set on the EVENT when it is not published and thus is done
1010
     *
1011
     * @param bool $reset
1012
     * @return bool | string - based on EE_Datetime active constants or FALSE if error.
1013
     * @throws EE_Error
1014
     */
1015
    public function get_active_status($reset = false)
1016
    {
1017
        // if the active status has already been set, then just use that value (unless we are resetting it)
1018
        if (! empty($this->_active_status) && ! $reset) {
1019
            return $this->_active_status;
1020
        }
1021
        // first check if event id is present on this object
1022
        if (! $this->ID()) {
1023
            return false;
1024
        }
1025
        $where_params_for_event = array(array('EVT_ID' => $this->ID()));
1026
        // if event is published:
1027
        if ($this->status() === 'publish') {
1028
            // active?
1029
            if (EEM_Datetime::instance()->get_datetime_count_for_status(
1030
                EE_Datetime::active,
1031
                $where_params_for_event
1032
            ) > 0) {
1033
                $this->_active_status = EE_Datetime::active;
1034
            } else {
1035
                // upcoming?
1036
                if (EEM_Datetime::instance()->get_datetime_count_for_status(
1037
                    EE_Datetime::upcoming,
1038
                    $where_params_for_event
1039
                ) > 0) {
1040
                    $this->_active_status = EE_Datetime::upcoming;
1041
                } else {
1042
                    // expired?
1043
                    if (EEM_Datetime::instance()->get_datetime_count_for_status(
1044
                        EE_Datetime::expired,
1045
                        $where_params_for_event
1046
                    ) > 0
1047
                    ) {
1048
                        $this->_active_status = EE_Datetime::expired;
1049
                    } else {
1050
                        // it would be odd if things make it this far because it basically means there are no datetime's
1051
                        // attached to the event.  So in this case it will just be considered inactive.
1052
                        $this->_active_status = EE_Datetime::inactive;
1053
                    }
1054
                }
1055
            }
1056
        } else {
1057
            // the event is not published, so let's just set it's active status according to its' post status
1058
            switch ($this->status()) {
1059
                case EEM_Event::sold_out:
1060
                    $this->_active_status = EE_Datetime::sold_out;
1061
                    break;
1062
                case EEM_Event::cancelled:
1063
                    $this->_active_status = EE_Datetime::cancelled;
1064
                    break;
1065
                case EEM_Event::postponed:
1066
                    $this->_active_status = EE_Datetime::postponed;
1067
                    break;
1068
                default:
1069
                    $this->_active_status = EE_Datetime::inactive;
1070
            }
1071
        }
1072
        return $this->_active_status;
1073
    }
1074
1075
1076
    /**
1077
     *    pretty_active_status
1078
     *
1079
     * @access public
1080
     * @param boolean $echo whether to return (FALSE), or echo out the result (TRUE)
1081
     * @return mixed void|string
1082
     * @throws EE_Error
1083
     */
1084
    public function pretty_active_status($echo = true)
1085
    {
1086
        $active_status = $this->get_active_status();
1087
        $status = '<span class="ee-status event-active-status-'
1088
                  . $active_status
1089
                  . '">'
1090
                  . EEH_Template::pretty_status($active_status, false, 'sentence')
1091
                  . '</span>';
1092
        if ($echo) {
1093
            echo $status;
1094
            return '';
1095
        }
1096
        return $status;
1097
    }
1098
1099
1100
    /**
1101
     * @return bool|int
1102
     * @throws EE_Error
1103
     */
1104
    public function get_number_of_tickets_sold()
1105
    {
1106
        $tkt_sold = 0;
1107
        if (! $this->ID()) {
1108
            return 0;
1109
        }
1110
        $datetimes = $this->datetimes();
1111
        foreach ($datetimes as $datetime) {
1112
            if ($datetime instanceof EE_Datetime) {
1113
                $tkt_sold += $datetime->sold();
1114
            }
1115
        }
1116
        return $tkt_sold;
1117
    }
1118
1119
1120
    /**
1121
     * This just returns a count of all the registrations for this event
1122
     *
1123
     * @access  public
1124
     * @return int
1125
     * @throws EE_Error
1126
     */
1127
    public function get_count_of_all_registrations()
1128
    {
1129
        return EEM_Event::instance()->count_related($this, 'Registration');
1130
    }
1131
1132
1133
    /**
1134
     * This returns the ticket with the earliest start time that is
1135
     * available for this event (across all datetimes attached to the event)
1136
     *
1137
     * @return EE_Base_Class|EE_Ticket|null
1138
     * @throws EE_Error
1139
     */
1140
    public function get_ticket_with_earliest_start_time()
1141
    {
1142
        $where['Datetime.EVT_ID'] = $this->ID();
0 ignored issues
show
Coding Style Comprehensibility introduced by
$where was never initialized. Although not strictly required by PHP, it is generally a good practice to add $where = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1143
        $query_params = array($where, 'order_by' => array('TKT_start_date' => 'ASC'));
1144
        return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1145
    }
1146
1147
1148
    /**
1149
     * This returns the ticket with the latest end time that is available
1150
     * for this event (across all datetimes attached to the event)
1151
     *
1152
     * @return EE_Base_Class|EE_Ticket|null
1153
     * @throws EE_Error
1154
     */
1155
    public function get_ticket_with_latest_end_time()
1156
    {
1157
        $where['Datetime.EVT_ID'] = $this->ID();
0 ignored issues
show
Coding Style Comprehensibility introduced by
$where was never initialized. Although not strictly required by PHP, it is generally a good practice to add $where = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1158
        $query_params = array($where, 'order_by' => array('TKT_end_date' => 'DESC'));
1159
        return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1160
    }
1161
1162
1163
    /**
1164
     * This returns the number of different ticket types currently on sale for this event.
1165
     *
1166
     * @return int
1167
     * @throws EE_Error
1168
     */
1169
    public function countTicketsOnSale()
1170
    {
1171
        $where = array(
1172
            'Datetime.EVT_ID' => $this->ID(),
1173
            'TKT_start_date'  => array('<', time()),
1174
            'TKT_end_date'    => array('>', time()),
1175
        );
1176
        return EEM_Ticket::instance()->count(array($where));
1177
    }
1178
1179
1180
    /**
1181
     * This returns whether there are any tickets on sale for this event.
1182
     *
1183
     * @return bool true = YES tickets on sale.
1184
     * @throws EE_Error
1185
     */
1186
    public function tickets_on_sale()
1187
    {
1188
        return $this->countTicketsOnSale() > 0;
1189
    }
1190
1191
1192
    /**
1193
     * Gets the URL for viewing this event on the front-end. Overrides parent
1194
     * to check for an external URL first
1195
     *
1196
     * @return string
1197
     * @throws EE_Error
1198
     */
1199
    public function get_permalink()
1200
    {
1201
        if ($this->external_url()) {
1202
            return $this->external_url();
1203
        }
1204
        return parent::get_permalink();
1205
    }
1206
1207
1208
    /**
1209
     * Gets the first term for 'espresso_event_categories' we can find
1210
     *
1211
     * @param array $query_params like EEM_Base::get_all
1212
     * @return EE_Base_Class|EE_Term|null
1213
     * @throws EE_Error
1214
     */
1215
    public function first_event_category($query_params = array())
1216
    {
1217
        $query_params[0]['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1218
        $query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1219
        return EEM_Term::instance()->get_one($query_params);
1220
    }
1221
1222
1223
    /**
1224
     * Gets all terms for 'espresso_event_categories' we can find
1225
     *
1226
     * @param array $query_params
1227
     * @return EE_Base_Class[]|EE_Term[]
1228
     * @throws EE_Error
1229
     */
1230
    public function get_all_event_categories($query_params = array())
1231
    {
1232
        $query_params[0]['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1233
        $query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1234
        return EEM_Term::instance()->get_all($query_params);
1235
    }
1236
1237
1238
    /**
1239
     * Adds a question group to this event
1240
     *
1241
     * @param EE_Question_Group|int $question_group_id_or_obj
1242
     * @param bool                  $for_primary if true, the question group will be added for the primary
1243
     *                                           registrant, if false will be added for others. default: false
1244
     * @return EE_Base_Class|EE_Question_Group
1245
     * @throws EE_Error
1246
     */
1247
    public function add_question_group($question_group_id_or_obj, $for_primary = false)
1248
    {
1249
        $extra = $for_primary
1250
            ? array('EQG_primary' => 1)
1251
            : array();
1252
        return $this->_add_relation_to($question_group_id_or_obj, 'Question_Group', $extra);
1253
    }
1254
1255
1256
    /**
1257
     * Removes a question group from the event
1258
     *
1259
     * @param EE_Question_Group|int $question_group_id_or_obj
1260
     * @param bool                  $for_primary if true, the question group will be removed from the primary
1261
     *                                           registrant, if false will be removed from others. default: false
1262
     * @return EE_Base_Class|EE_Question_Group
1263
     * @throws EE_Error
1264
     */
1265
    public function remove_question_group($question_group_id_or_obj, $for_primary = false)
1266
    {
1267
        $where = $for_primary
1268
            ? array('EQG_primary' => 1)
1269
            : array();
1270
        return $this->_remove_relation_to($question_group_id_or_obj, 'Question_Group', $where);
1271
    }
1272
1273
1274
    /**
1275
     * Gets all the question groups, ordering them by QSG_order ascending
1276
     *
1277
     * @param array $query_params @see EEM_Base::get_all
1278
     * @return EE_Base_Class[]|EE_Question_Group[]
1279
     * @throws EE_Error
1280
     */
1281
    public function question_groups($query_params = array())
1282
    {
1283
        $query_params = ! empty($query_params) ? $query_params : array('order_by' => array('QSG_order' => 'ASC'));
1284
        return $this->get_many_related('Question_Group', $query_params);
1285
    }
1286
1287
1288
    /**
1289
     * Implementation for EEI_Has_Icon interface method.
1290
     *
1291
     * @see EEI_Visual_Representation for comments
1292
     * @return string
1293
     */
1294
    public function get_icon()
1295
    {
1296
        return '<span class="dashicons dashicons-flag"></span>';
1297
    }
1298
1299
1300
    /**
1301
     * Implementation for EEI_Admin_Links interface method.
1302
     *
1303
     * @see EEI_Admin_Links for comments
1304
     * @return string
1305
     * @throws EE_Error
1306
     */
1307
    public function get_admin_details_link()
1308
    {
1309
        return $this->get_admin_edit_link();
1310
    }
1311
1312
1313
    /**
1314
     * Implementation for EEI_Admin_Links interface method.
1315
     *
1316
     * @see EEI_Admin_Links for comments
1317
     * @return string
1318
     * @throws EE_Error
1319
     */
1320
    public function get_admin_edit_link()
1321
    {
1322
        return EEH_URL::add_query_args_and_nonce(
1323
            array(
1324
                'page'   => 'espresso_events',
1325
                'action' => 'edit',
1326
                'post'   => $this->ID(),
1327
            ),
1328
            admin_url('admin.php')
1329
        );
1330
    }
1331
1332
1333
    /**
1334
     * Implementation for EEI_Admin_Links interface method.
1335
     *
1336
     * @see EEI_Admin_Links for comments
1337
     * @return string
1338
     */
1339
    public function get_admin_settings_link()
1340
    {
1341
        return EEH_URL::add_query_args_and_nonce(
1342
            array(
1343
                'page'   => 'espresso_events',
1344
                'action' => 'default_event_settings',
1345
            ),
1346
            admin_url('admin.php')
1347
        );
1348
    }
1349
1350
1351
    /**
1352
     * Implementation for EEI_Admin_Links interface method.
1353
     *
1354
     * @see EEI_Admin_Links for comments
1355
     * @return string
1356
     */
1357
    public function get_admin_overview_link()
1358
    {
1359
        return EEH_URL::add_query_args_and_nonce(
1360
            array(
1361
                'page'   => 'espresso_events',
1362
                'action' => 'default',
1363
            ),
1364
            admin_url('admin.php')
1365
        );
1366
    }
1367
}
1368