Completed
Branch BUG-10878-event-spaces-remaini... (17f80a)
by
unknown
13:41
created

EE_Event::set_status()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 29
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 15
nc 5
nop 2
dl 0
loc 29
rs 8.439
c 0
b 0
f 0
1
<?php
2
3
use EventEspresso\core\domain\services\event\EventSpacesCalculator;
4
5
6
if (!defined('EVENT_ESPRESSO_VERSION')) {
7
    exit('No direct script access allowed');
8
}
9
10
11
/**
12
 * EE_Event
13
 *
14
 * @package               Event Espresso
15
 * @subpackage            includes/models/
16
 * @author                Mike Nelson
17
 */
18
class EE_Event extends EE_CPT_Base implements EEI_Line_Item_Object, EEI_Admin_Links, EEI_Has_Icon, EEI_Event
19
{
20
21
    /**
22
     * cached value for the the logical active status for the event
23
     *
24
     * @see get_active_status()
25
     * @var string
26
     */
27
    protected $_active_status = '';
28
29
    /**
30
     * This is just used for caching the Primary Datetime for the Event on initial retrieval
31
     *
32
     * @var EE_Datetime
33
     */
34
    protected $_Primary_Datetime;
35
36
    /**
37
     * @var EventSpacesCalculator $available_spaces_calculator
38
     */
39
    protected $available_spaces_calculator;
40
41
42
    /**
43
     * @param array $props_n_values incoming values
44
     * @param string $timezone incoming timezone (if not set the timezone set for the website will be
45
     *                                        used.)
46
     * @param array $date_formats incoming date_formats in an array where the first value is the
47
     *                                        date_format and the second value is the time format
48
     * @return EE_Event
49
     * @throws EE_Error
50
     */
51
    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
52
    {
53
        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
54
        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
55
    }
56
57
58
    /**
59
     * @param array $props_n_values incoming values from the database
60
     * @param string $timezone incoming timezone as set by the model.  If not set the timezone for
61
     *                                the website will be used.
62
     * @return EE_Event
63
     * @throws EE_Error
64
     */
65
    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
66
    {
67
        return new self($props_n_values, true, $timezone);
68
    }
69
70
71
72
    /**
73
     * @return EventSpacesCalculator
74
     * @throws \EE_Error
75
     */
76
    public function getAvailableSpacesCalculator()
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
    /**
87
     * Overrides parent set() method so that all calls to set( 'status', $status ) can be routed to internal methods
88
     *
89
     * @param string $field_name
90
     * @param mixed $field_value
91
     * @param bool $use_default
92
     * @throws EE_Error
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
     * @access public
113
     * @param string $new_status
114
     * @param bool $use_default
115
     * @return void
116
     * @throws EE_Error
117
     */
118
    public function set_status($new_status = null, $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($new_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 !== $new_status) {
128
            // TO sold_out
129
            if ($new_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, $new_status);
133
                // OR FROM  sold_out
134
            } else if ($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, $new_status);
137
            }
138
            // update status
139
            parent::set('status', $new_status, $use_default);
140
            do_action('AHEE__EE_Event__set_status__after_update', $this);
141
            return;
142
        }
143
        // even though the old value matches the new value, it's still good to
144
        // allow the parent set method to have a say
145
        parent::set('status', $new_status, $use_default);
146
    }
147
148
149
    /**
150
     * Gets all the datetimes for this event
151
     *
152
     * @param array $query_params like EEM_Base::get_all
153
     * @return EE_Base_Class[]|EE_Datetime[]
154
     * @throws EE_Error
155
     */
156
    public function datetimes($query_params = array())
157
    {
158
        return $this->get_many_related('Datetime', $query_params);
159
    }
160
161
162
    /**
163
     * Gets all the datetimes for this event, ordered by DTT_EVT_start in ascending order
164
     *
165
     * @return EE_Base_Class[]|EE_Datetime[]
166
     * @throws EE_Error
167
     */
168
    public function datetimes_in_chronological_order()
169
    {
170
        return $this->get_many_related('Datetime', array('order_by' => array('DTT_EVT_start' => 'ASC')));
171
    }
172
173
174
    /**
175
     * Gets all the datetimes for this event, ordered by the DTT_order on the datetime.
176
     * @darren, we should probably UNSET timezone on the EEM_Datetime model
177
     * after running our query, so that this timezone isn't set for EVERY query
178
     * on EEM_Datetime for the rest of the request, no?
179
     *
180
     * @param boolean $show_expired whether or not to include expired events
181
     * @param boolean $show_deleted whether or not to include deleted events
182
     * @param null $limit
183
     * @return EE_Datetime[]
184
     * @throws EE_Error
185
     */
186
    public function datetimes_ordered($show_expired = true, $show_deleted = false, $limit = null)
187
    {
188
        return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_event_ordered_by_DTT_order(
189
            $this->ID(),
190
            $show_expired,
191
            $show_deleted,
192
            $limit
193
        );
194
    }
195
196
197
    /**
198
     * Returns one related datetime. Mostly only used by some legacy code.
199
     *
200
     * @return EE_Base_Class|EE_Datetime
201
     * @throws EE_Error
202
     */
203
    public function first_datetime()
204
    {
205
        return $this->get_first_related('Datetime');
206
    }
207
208
209
    /**
210
     * Returns the 'primary' datetime for the event
211
     *
212
     * @param bool $try_to_exclude_expired
213
     * @param bool $try_to_exclude_deleted
214
     * @return EE_Datetime
215
     * @throws EE_Error
216
     */
217
    public function primary_datetime($try_to_exclude_expired = true, $try_to_exclude_deleted = true)
218
    {
219
        if (!empty ($this->_Primary_Datetime)) {
220
            return $this->_Primary_Datetime;
221
        }
222
        $this->_Primary_Datetime = EEM_Datetime::instance($this->_timezone)->get_primary_datetime_for_event(
223
            $this->ID(),
224
            $try_to_exclude_expired,
225
            $try_to_exclude_deleted
226
        );
227
        return $this->_Primary_Datetime;
228
    }
229
230
231
    /**
232
     * Gets all the tickets available for purchase of this event
233
     *
234
     * @param array $query_params like EEM_Base::get_all
235
     * @return EE_Base_Class[]|EE_Ticket[]
236
     * @throws EE_Error
237
     */
238
    public function tickets($query_params = array())
239
    {
240
        //first get all datetimes
241
        $datetimes = $this->datetimes_ordered();
242
        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...
243
            return array();
244
        }
245
        $datetime_ids = array();
246
        foreach ($datetimes as $datetime) {
247
            $datetime_ids[] = $datetime->ID();
248
        }
249
        $where_params = array('Datetime.DTT_ID' => array('IN', $datetime_ids));
250
        //if incoming $query_params has where conditions let's merge but not override existing.
251
        if (is_array($query_params) && isset($query_params[0])) {
252
            $where_params = array_merge($query_params[0], $where_params);
253
            unset($query_params[0]);
254
        }
255
        //now add $where_params to $query_params
256
        $query_params[0] = $where_params;
257
        return EEM_Ticket::instance()->get_all($query_params);
258
    }
259
260
261
    /**
262
     * get all unexpired untrashed tickets
263
     *
264
     * @return EE_Ticket[]
265
     * @throws EE_Error
266
     */
267
    public function active_tickets()
268
    {
269
        return $this->tickets(array(
270
            array(
271
                'TKT_end_date' => array('>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')),
272
                'TKT_deleted' => false,
273
            ),
274
        ));
275
    }
276
277
278
    /**
279
     * @return bool
280
     * @throws EE_Error
281
     */
282
    public function additional_limit()
283
    {
284
        return $this->get('EVT_additional_limit');
285
    }
286
287
288
    /**
289
     * @return bool
290
     * @throws EE_Error
291
     */
292
    public function allow_overflow()
293
    {
294
        return $this->get('EVT_allow_overflow');
295
    }
296
297
298
    /**
299
     * @return bool
300
     * @throws EE_Error
301
     */
302
    public function created()
303
    {
304
        return $this->get('EVT_created');
305
    }
306
307
308
    /**
309
     * @return bool
310
     * @throws EE_Error
311
     */
312
    public function description()
313
    {
314
        return $this->get('EVT_desc');
315
    }
316
317
318
    /**
319
     * Runs do_shortcode and wpautop on the description
320
     *
321
     * @return string of html
322
     * @throws EE_Error
323
     */
324
    public function description_filtered()
325
    {
326
        return $this->get_pretty('EVT_desc');
327
    }
328
329
330
    /**
331
     * @return bool
332
     * @throws EE_Error
333
     */
334
    public function display_description()
335
    {
336
        return $this->get('EVT_display_desc');
337
    }
338
339
340
    /**
341
     * @return bool
342
     * @throws EE_Error
343
     */
344
    public function display_ticket_selector()
345
    {
346
        return (bool)$this->get('EVT_display_ticket_selector');
347
    }
348
349
350
    /**
351
     * @return bool
352
     * @throws EE_Error
353
     */
354
    public function external_url()
355
    {
356
        return $this->get('EVT_external_URL');
357
    }
358
359
360
    /**
361
     * @return bool
362
     * @throws EE_Error
363
     */
364
    public function member_only()
365
    {
366
        return $this->get('EVT_member_only');
367
    }
368
369
370
    /**
371
     * @return bool
372
     * @throws EE_Error
373
     */
374
    public function phone()
375
    {
376
        return $this->get('EVT_phone');
377
    }
378
379
380
    /**
381
     * @return bool
382
     * @throws EE_Error
383
     */
384
    public function modified()
385
    {
386
        return $this->get('EVT_modified');
387
    }
388
389
390
    /**
391
     * @return bool
392
     * @throws EE_Error
393
     */
394
    public function name()
395
    {
396
        return $this->get('EVT_name');
397
    }
398
399
400
    /**
401
     * @return bool
402
     * @throws EE_Error
403
     */
404
    public function order()
405
    {
406
        return $this->get('EVT_order');
407
    }
408
409
410
    /**
411
     * @return bool|string
412
     * @throws EE_Error
413
     */
414
    public function default_registration_status()
415
    {
416
        $event_default_registration_status = $this->get('EVT_default_registration_status');
417
        return !empty($event_default_registration_status)
418
            ? $event_default_registration_status
419
            : EE_Registry::instance()->CFG->registration->default_STS_ID;
420
    }
421
422
423
    /**
424
     * @param int $num_words
425
     * @param null $more
426
     * @param bool $not_full_desc
427
     * @return bool|string
428
     * @throws EE_Error
429
     */
430
    public function short_description($num_words = 55, $more = null, $not_full_desc = false)
431
    {
432
        $short_desc = $this->get('EVT_short_desc');
433
        if (!empty($short_desc) || $not_full_desc) {
434
            return $short_desc;
435
        }
436
        $full_desc = $this->get('EVT_desc');
437
        return wp_trim_words($full_desc, $num_words, $more);
438
    }
439
440
441
    /**
442
     * @return bool
443
     * @throws EE_Error
444
     */
445
    public function slug()
446
    {
447
        return $this->get('EVT_slug');
448
    }
449
450
451
    /**
452
     * @return bool
453
     * @throws EE_Error
454
     */
455
    public function timezone_string()
456
    {
457
        return $this->get('EVT_timezone_string');
458
    }
459
460
461
    /**
462
     * @return bool
463
     * @throws EE_Error
464
     */
465
    public function visible_on()
466
    {
467
        return $this->get('EVT_visible_on');
468
    }
469
470
471
    /**
472
     * @return int
473
     * @throws EE_Error
474
     */
475
    public function wp_user()
476
    {
477
        return $this->get('EVT_wp_user');
478
    }
479
480
481
    /**
482
     * @return bool
483
     * @throws EE_Error
484
     */
485
    public function donations()
486
    {
487
        return $this->get('EVT_donations');
488
    }
489
490
491
    /**
492
     * @param $limit
493
     * @throws EE_Error
494
     */
495
    public function set_additional_limit($limit)
496
    {
497
        $this->set('EVT_additional_limit', $limit);
498
    }
499
500
501
    /**
502
     * @param $created
503
     * @throws EE_Error
504
     */
505
    public function set_created($created)
506
    {
507
        $this->set('EVT_created', $created);
508
    }
509
510
511
    /**
512
     * @param $desc
513
     * @throws EE_Error
514
     */
515
    public function set_description($desc)
516
    {
517
        $this->set('EVT_desc', $desc);
518
    }
519
520
521
    /**
522
     * @param $display_desc
523
     * @throws EE_Error
524
     */
525
    public function set_display_description($display_desc)
526
    {
527
        $this->set('EVT_display_desc', $display_desc);
528
    }
529
530
531
    /**
532
     * @param $display_ticket_selector
533
     * @throws EE_Error
534
     */
535
    public function set_display_ticket_selector($display_ticket_selector)
536
    {
537
        $this->set('EVT_display_ticket_selector', $display_ticket_selector);
538
    }
539
540
541
    /**
542
     * @param $external_url
543
     * @throws EE_Error
544
     */
545
    public function set_external_url($external_url)
546
    {
547
        $this->set('EVT_external_URL', $external_url);
548
    }
549
550
551
    /**
552
     * @param $member_only
553
     * @throws EE_Error
554
     */
555
    public function set_member_only($member_only)
556
    {
557
        $this->set('EVT_member_only', $member_only);
558
    }
559
560
561
    /**
562
     * @param $event_phone
563
     * @throws EE_Error
564
     */
565
    public function set_event_phone($event_phone)
566
    {
567
        $this->set('EVT_phone', $event_phone);
568
    }
569
570
571
    /**
572
     * @param $modified
573
     * @throws EE_Error
574
     */
575
    public function set_modified($modified)
576
    {
577
        $this->set('EVT_modified', $modified);
578
    }
579
580
581
    /**
582
     * @param $name
583
     * @throws EE_Error
584
     */
585
    public function set_name($name)
586
    {
587
        $this->set('EVT_name', $name);
588
    }
589
590
591
    /**
592
     * @param $order
593
     * @throws EE_Error
594
     */
595
    public function set_order($order)
596
    {
597
        $this->set('EVT_order', $order);
598
    }
599
600
601
    /**
602
     * @param $short_desc
603
     * @throws EE_Error
604
     */
605
    public function set_short_description($short_desc)
606
    {
607
        $this->set('EVT_short_desc', $short_desc);
608
    }
609
610
611
    /**
612
     * @param $slug
613
     * @throws EE_Error
614
     */
615
    public function set_slug($slug)
616
    {
617
        $this->set('EVT_slug', $slug);
618
    }
619
620
621
    /**
622
     * @param $timezone_string
623
     * @throws EE_Error
624
     */
625
    public function set_timezone_string($timezone_string)
626
    {
627
        $this->set('EVT_timezone_string', $timezone_string);
628
    }
629
630
631
    /**
632
     * @param $visible_on
633
     * @throws EE_Error
634
     */
635
    public function set_visible_on($visible_on)
636
    {
637
        $this->set('EVT_visible_on', $visible_on);
638
    }
639
640
641
    /**
642
     * @param $wp_user
643
     * @throws EE_Error
644
     */
645
    public function set_wp_user($wp_user)
646
    {
647
        $this->set('EVT_wp_user', $wp_user);
648
    }
649
650
651
    /**
652
     * @param $default_registration_status
653
     * @throws EE_Error
654
     */
655
    public function set_default_registration_status($default_registration_status)
656
    {
657
        $this->set('EVT_default_registration_status', $default_registration_status);
658
    }
659
660
661
    /**
662
     * @param $donations
663
     * @throws EE_Error
664
     */
665
    public function set_donations($donations)
666
    {
667
        $this->set('EVT_donations', $donations);
668
    }
669
670
671
    /**
672
     * Adds a venue to this event
673
     *
674
     * @param EE_Venue /int $venue_id_or_obj
675
     * @return EE_Base_Class|EE_Venue
676
     * @throws EE_Error
677
     */
678
    public function add_venue($venue_id_or_obj)
679
    {
680
        return $this->_add_relation_to($venue_id_or_obj, 'Venue');
681
    }
682
683
684
    /**
685
     * Removes a venue from the event
686
     *
687
     * @param EE_Venue /int $venue_id_or_obj
688
     * @return EE_Base_Class|EE_Venue
689
     * @throws EE_Error
690
     */
691
    public function remove_venue($venue_id_or_obj)
692
    {
693
        return $this->_remove_relation_to($venue_id_or_obj, 'Venue');
694
    }
695
696
697
    /**
698
     * Gets all the venues related ot the event. May provide additional $query_params if desired
699
     *
700
     * @param array $query_params like EEM_Base::get_all's $query_params
701
     * @return EE_Base_Class[]|EE_Venue[]
702
     * @throws EE_Error
703
     */
704
    public function venues($query_params = array())
705
    {
706
        return $this->get_many_related('Venue', $query_params);
707
    }
708
709
710
    /**
711
     * check if event id is present and if event is published
712
     *
713
     * @access public
714
     * @return boolean true yes, false no
715
     * @throws EE_Error
716
     */
717
    private function _has_ID_and_is_published()
718
    {
719
        // first check if event id is present and not NULL,
720
        // then check if this event is published (or any of the equivalent "published" statuses)
721
        return
722
            $this->ID() && $this->ID() !== null
723
            && (
724
                $this->status() === 'publish'
725
                || $this->status() === EEM_Event::sold_out
726
                || $this->status() === EEM_Event::postponed
727
                || $this->status() === EEM_Event::cancelled
728
            );
729
    }
730
731
732
    /**
733
     * This simply compares the internal dates with NOW and determines if the event is upcoming or not.
734
     *
735
     * @access public
736
     * @return boolean true yes, false no
737
     * @throws EE_Error
738
     */
739 View Code Duplication
    public function is_upcoming()
740
    {
741
        // check if event id is present and if this event is published
742
        if ($this->is_inactive()) {
743
            return false;
744
        }
745
        // set initial value
746
        $upcoming = false;
747
        //next let's get all datetimes and loop through them
748
        $datetimes = $this->datetimes_in_chronological_order();
749
        foreach ($datetimes as $datetime) {
750
            if ($datetime instanceof EE_Datetime) {
751
                //if this dtt is expired then we continue cause one of the other datetimes might be upcoming.
752
                if ($datetime->is_expired()) {
753
                    continue;
754
                }
755
                //if this dtt is active then we return false.
756
                if ($datetime->is_active()) {
757
                    return false;
758
                }
759
                //otherwise let's check upcoming status
760
                $upcoming = $datetime->is_upcoming();
761
            }
762
        }
763
        return $upcoming;
764
    }
765
766
767
    /**
768
     * @return bool
769
     * @throws EE_Error
770
     */
771 View Code Duplication
    public function is_active()
772
    {
773
        // check if event id is present and if this event is published
774
        if ($this->is_inactive()) {
775
            return false;
776
        }
777
        // set initial value
778
        $active = false;
779
        //next let's get all datetimes and loop through them
780
        $datetimes = $this->datetimes_in_chronological_order();
781
        foreach ($datetimes as $datetime) {
782
            if ($datetime instanceof EE_Datetime) {
783
                //if this dtt is expired then we continue cause one of the other datetimes might be active.
784
                if ($datetime->is_expired()) {
785
                    continue;
786
                }
787
                //if this dtt is upcoming then we return false.
788
                if ($datetime->is_upcoming()) {
789
                    return false;
790
                }
791
                //otherwise let's check active status
792
                $active = $datetime->is_active();
793
            }
794
        }
795
        return $active;
796
    }
797
798
799
    /**
800
     * @return bool
801
     * @throws EE_Error
802
     */
803 View Code Duplication
    public function is_expired()
804
    {
805
        // check if event id is present and if this event is published
806
        if ($this->is_inactive()) {
807
            return false;
808
        }
809
        // set initial value
810
        $expired = false;
811
        //first let's get all datetimes and loop through them
812
        $datetimes = $this->datetimes_in_chronological_order();
813
        foreach ($datetimes as $datetime) {
814
            if ($datetime instanceof EE_Datetime) {
815
                //if this dtt is upcoming or active then we return false.
816
                if ($datetime->is_upcoming() || $datetime->is_active()) {
817
                    return false;
818
                }
819
                //otherwise let's check active status
820
                $expired = $datetime->is_expired();
821
            }
822
        }
823
        return $expired;
824
    }
825
826
827
    /**
828
     * @return bool
829
     * @throws EE_Error
830
     */
831
    public function is_inactive()
832
    {
833
        // check if event id is present and if this event is published
834
        if ($this->_has_ID_and_is_published()) {
835
            return false;
836
        }
837
        return true;
838
    }
839
840
841
    /**
842
     * calculate spaces remaining based on "saleable" tickets
843
     *
844
     * @param array $tickets
845
     * @param bool $filtered
846
     * @return int|float
847
     * @throws EE_Error
848
     */
849
    public function spaces_remaining($tickets = array(), $filtered = true)
850
    {
851
        $this->getAvailableSpacesCalculator()->setActiveTickets($tickets);
852
        $spaces_remaining = $this->getAvailableSpacesCalculator()->spacesRemaining();
853
        return $filtered
854
            ? apply_filters(
855
                'FHEE_EE_Event__spaces_remaining',
856
                $spaces_remaining,
857
                $this,
858
                $tickets
859
            )
860
            : $spaces_remaining;
861
    }
862
863
864
    /**
865
     *    perform_sold_out_status_check
866
     *    checks all of this events's datetime  reg_limit - sold values to determine if ANY datetimes have spaces available...
867
     *    if NOT, then the event status will get toggled to 'sold_out'
868
     *
869
     * @access public
870
     * @return bool    return the ACTUAL sold out state.
871
     * @throws EE_Error
872
     */
873
    public function perform_sold_out_status_check()
874
    {
875
        // get all unexpired untrashed tickets
876
        $tickets = $this->active_tickets();
877
        // if all the tickets are just expired, then don't update the event status to sold out
878
        if (empty($tickets)) {
879
            return true;
880
        }
881
        $spaces_remaining = $this->spaces_remaining($tickets);
882
        if ($spaces_remaining < 1) {
883
            $this->set_status(EEM_Event::sold_out);
884
            $this->save();
885
            $sold_out = true;
886
        } else {
887
            $sold_out = false;
888
            // was event previously marked as sold out ?
889
            if ($this->status() === EEM_Event::sold_out) {
890
                // revert status to previous value, if it was set
891
                $previous_event_status = $this->get_post_meta('_previous_event_status', true);
892
                if ($previous_event_status) {
893
                    $this->set_status($previous_event_status);
894
                    $this->save();
895
                }
896
            }
897
        }
898
        do_action('AHEE__EE_Event__perform_sold_out_status_check__end', $this, $sold_out, $spaces_remaining, $tickets);
899
        return $sold_out;
900
    }
901
902
903
904
    /**
905
     * This returns the total remaining spaces for sale on this event.
906
     *
907
     * @uses EE_Event::total_available_spaces()
908
     * @return float|int
909
     * @throws EE_Error
910
     */
911
    public function spaces_remaining_for_sale()
912
    {
913
        return $this->total_available_spaces(true);
914
    }
915
916
917
918
    /**
919
     * This returns the total spaces available for an event
920
     * while considering all the qtys on the tickets and the reg limits
921
     * on the datetimes attached to this event.
922
     *
923
     * @param   bool $consider_sold Whether to consider any tickets that have already sold in our calculation.
924
     *                              If this is false, then we return the most tickets that could ever be sold
925
     *                              for this event with the datetime and tickets setup on the event under optimal
926
     *                              selling conditions.  Otherwise we return a live calculation of spaces available
927
     *                              based on tickets sold.  Depending on setup and stage of sales, this
928
     *                              may appear to equal remaining tickets.  However, the more tickets are
929
     *                              sold out, the more accurate the "live" total is.
930
     * @return  int|float  (Note: if EE_INF is returned its considered a float by PHP)
931
     * @throws EE_Error
932
     */
933
    public function total_available_spaces($consider_sold = false)
934
    {
935
        $spaces_available = $consider_sold
936
            ? $this->getAvailableSpacesCalculator()->spacesRemaining()
937
            : $this->getAvailableSpacesCalculator()->totalSpacesAvailable();
938
        return apply_filters(
939
            'FHEE_EE_Event__total_available_spaces__spaces_available',
940
            $spaces_available,
941
            $this,
942
            $this->getAvailableSpacesCalculator()->getDatetimes(),
943
            $this->getAvailableSpacesCalculator()->getActiveTickets()
944
        );
945
    }
946
947
948
    /**
949
     * Checks if the event is set to sold out
950
     *
951
     * @param  bool $actual whether or not to perform calculations to not only figure the
952
     *                      actual status but also to flip the status if necessary to sold
953
     *                      out If false, we just check the existing status of the event
954
     * @return boolean
955
     * @throws EE_Error
956
     */
957
    public function is_sold_out($actual = false)
958
    {
959
        if (!$actual) {
960
            return $this->status() === EEM_Event::sold_out;
961
        }
962
        return $this->perform_sold_out_status_check();
963
    }
964
965
966
    /**
967
     * Checks if the event is marked as postponed
968
     *
969
     * @return boolean
970
     */
971
    public function is_postponed()
972
    {
973
        return $this->status() === EEM_Event::postponed;
974
    }
975
976
977
    /**
978
     * Checks if the event is marked as cancelled
979
     *
980
     * @return boolean
981
     */
982
    public function is_cancelled()
983
    {
984
        return $this->status() === EEM_Event::cancelled;
985
    }
986
987
988
    /**
989
     * Get the logical active status in a hierarchical order for all the datetimes.  Note
990
     * Basically, we order the datetimes by EVT_start_date.  Then first test on whether the event is published.  If its
991
     * NOT published then we test for whether its expired or not.  IF it IS published then we test first on whether an
992
     * event has any active dates.  If no active dates then we check for any upcoming dates.  If no upcoming dates then
993
     * the event is considered expired.
994
     * NOTE: this method does NOT calculate whether the datetimes are sold out when event is published.  Sold Out is a status
995
     * set on the EVENT when it is not published and thus is done
996
     *
997
     * @param bool $reset
998
     * @return bool | string - based on EE_Datetime active constants or FALSE if error.
999
     * @throws EE_Error
1000
     */
1001
    public function get_active_status($reset = false)
1002
    {
1003
        // if the active status has already been set, then just use that value (unless we are resetting it)
1004
        if (!empty($this->_active_status) && !$reset) {
1005
            return $this->_active_status;
1006
        }
1007
        //first check if event id is present on this object
1008
        if (!$this->ID()) {
1009
            return false;
1010
        }
1011
        $where_params_for_event = array(array('EVT_ID' => $this->ID()));
1012
        //if event is published:
1013
        if ($this->status() === 'publish') {
1014
            //active?
1015
            if (EEM_Datetime::instance()->get_datetime_count_for_status(EE_Datetime::active, $where_params_for_event) > 0) {
1016
                $this->_active_status = EE_Datetime::active;
1017
            } else {
1018
                //upcoming?
1019
                if (EEM_Datetime::instance()->get_datetime_count_for_status(EE_Datetime::upcoming, $where_params_for_event) > 0) {
1020
                    $this->_active_status = EE_Datetime::upcoming;
1021
                } else {
1022
                    //expired?
1023
                    if (
1024
                        EEM_Datetime::instance()->get_datetime_count_for_status(EE_Datetime::expired, $where_params_for_event) > 0
1025
                    ) {
1026
                        $this->_active_status = EE_Datetime::expired;
1027
                    } else {
1028
                        //it would be odd if things make it this far because it basically means there are no datetime's
1029
                        //attached to the event.  So in this case it will just be considered inactive.
1030
                        $this->_active_status = EE_Datetime::inactive;
1031
                    }
1032
                }
1033
            }
1034
        } else {
1035
            //the event is not published, so let's just set it's active status according to its' post status
1036
            switch ($this->status()) {
1037
                case EEM_Event::sold_out :
1038
                    $this->_active_status = EE_Datetime::sold_out;
1039
                    break;
1040
                case EEM_Event::cancelled :
1041
                    $this->_active_status = EE_Datetime::cancelled;
1042
                    break;
1043
                case EEM_Event::postponed :
1044
                    $this->_active_status = EE_Datetime::postponed;
1045
                    break;
1046
                default :
1047
                    $this->_active_status = EE_Datetime::inactive;
1048
            }
1049
        }
1050
        return $this->_active_status;
1051
    }
1052
1053
1054
    /**
1055
     *    pretty_active_status
1056
     *
1057
     * @access public
1058
     * @param boolean $echo whether to return (FALSE), or echo out the result (TRUE)
1059
     * @return mixed void|string
1060
     * @throws EE_Error
1061
     */
1062
    public function pretty_active_status($echo = true)
1063
    {
1064
        $active_status = $this->get_active_status();
1065
        $status = '<span class="ee-status event-active-status-'
1066
            . $active_status
1067
            . '">'
1068
            . EEH_Template::pretty_status($active_status, false, 'sentence')
1069
            . '</span>';
1070
        if ($echo) {
1071
            echo $status;
1072
            return '';
1073
        }
1074
        return $status;
1075
    }
1076
1077
1078
    /**
1079
     * @return bool|int
1080
     * @throws EE_Error
1081
     */
1082
    public function get_number_of_tickets_sold()
1083
    {
1084
        $tkt_sold = 0;
1085
        if (!$this->ID()) {
1086
            return 0;
1087
        }
1088
        $datetimes = $this->datetimes();
1089
        foreach ($datetimes as $datetime) {
1090
            if ($datetime instanceof EE_Datetime) {
1091
                $tkt_sold += $datetime->sold();
1092
            }
1093
        }
1094
        return $tkt_sold;
1095
    }
1096
1097
1098
    /**
1099
     * This just returns a count of all the registrations for this event
1100
     *
1101
     * @access  public
1102
     * @return int
1103
     * @throws EE_Error
1104
     */
1105
    public function get_count_of_all_registrations()
1106
    {
1107
        return EEM_Event::instance()->count_related($this, 'Registration');
1108
    }
1109
1110
1111
    /**
1112
     * This returns the ticket with the earliest start time that is
1113
     * available for this event (across all datetimes attached to the event)
1114
     *
1115
     * @return EE_Base_Class|EE_Ticket|null
1116
     * @throws EE_Error
1117
     */
1118
    public function get_ticket_with_earliest_start_time()
1119
    {
1120
        $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...
1121
        $query_params = array($where, 'order_by' => array('TKT_start_date' => 'ASC'));
1122
        return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1123
    }
1124
1125
1126
    /**
1127
     * This returns the ticket with the latest end time that is available
1128
     * for this event (across all datetimes attached to the event)
1129
     *
1130
     * @return EE_Base_Class|EE_Ticket|null
1131
     * @throws EE_Error
1132
     */
1133
    public function get_ticket_with_latest_end_time()
1134
    {
1135
        $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...
1136
        $query_params = array($where, 'order_by' => array('TKT_end_date' => 'DESC'));
1137
        return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1138
    }
1139
1140
1141
    /**
1142
     * This returns whether there are any tickets on sale for this event.
1143
     *
1144
     * @return bool true = YES tickets on sale.
1145
     * @throws EE_Error
1146
     */
1147
    public function tickets_on_sale()
1148
    {
1149
        $earliest_ticket = $this->get_ticket_with_earliest_start_time();
1150
        $latest_ticket = $this->get_ticket_with_latest_end_time();
1151
        if (!$latest_ticket instanceof EE_Ticket && !$earliest_ticket instanceof EE_Ticket) {
1152
            return false;
1153
        }
1154
        //check on sale for these two tickets.
1155
        if ($latest_ticket->is_on_sale() || $earliest_ticket->is_on_sale()) {
1156
            return true;
1157
        }
1158
        return false;
1159
    }
1160
1161
1162
    /**
1163
     * Gets the URL for viewing this event on the front-end. Overrides parent
1164
     * to check for an external URL first
1165
     *
1166
     * @return string
1167
     * @throws EE_Error
1168
     */
1169
    public function get_permalink()
1170
    {
1171
        if ($this->external_url()) {
1172
            return $this->external_url();
1173
        }
1174
        return parent::get_permalink();
1175
    }
1176
1177
1178
    /**
1179
     * Gets the first term for 'espresso_event_categories' we can find
1180
     *
1181
     * @param array $query_params like EEM_Base::get_all
1182
     * @return EE_Base_Class|EE_Term|null
1183
     * @throws EE_Error
1184
     */
1185
    public function first_event_category($query_params = array())
1186
    {
1187
        $query_params[0]['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1188
        $query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1189
        return EEM_Term::instance()->get_one($query_params);
1190
    }
1191
1192
1193
    /**
1194
     * Gets all terms for 'espresso_event_categories' we can find
1195
     *
1196
     * @param array $query_params
1197
     * @return EE_Base_Class[]|EE_Term[]
1198
     * @throws EE_Error
1199
     */
1200
    public function get_all_event_categories($query_params = array())
1201
    {
1202
        $query_params[0]['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1203
        $query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1204
        return EEM_Term::instance()->get_all($query_params);
1205
    }
1206
1207
1208
    /**
1209
     * Gets all the question groups, ordering them by QSG_order ascending
1210
     *
1211
     * @param array $query_params @see EEM_Base::get_all
1212
     * @return EE_Base_Class[]|EE_Question_Group[]
1213
     * @throws EE_Error
1214
     */
1215
    public function question_groups($query_params = array())
1216
    {
1217
        $query_params = !empty($query_params) ? $query_params : array('order_by' => array('QSG_order' => 'ASC'));
1218
        return $this->get_many_related('Question_Group', $query_params);
1219
    }
1220
1221
1222
    /**
1223
     * Implementation for EEI_Has_Icon interface method.
1224
     *
1225
     * @see EEI_Visual_Representation for comments
1226
     * @return string
1227
     */
1228
    public function get_icon()
1229
    {
1230
        return '<span class="dashicons dashicons-flag"></span>';
1231
    }
1232
1233
1234
    /**
1235
     * Implementation for EEI_Admin_Links interface method.
1236
     *
1237
     * @see EEI_Admin_Links for comments
1238
     * @return string
1239
     * @throws EE_Error
1240
     */
1241
    public function get_admin_details_link()
1242
    {
1243
        return $this->get_admin_edit_link();
1244
    }
1245
1246
1247
    /**
1248
     * Implementation for EEI_Admin_Links interface method.
1249
     *
1250
     * @see EEI_Admin_Links for comments
1251
     * @return string
1252
     * @throws EE_Error
1253
     */
1254
    public function get_admin_edit_link()
1255
    {
1256
        return EEH_URL::add_query_args_and_nonce(array(
1257
            'page' => 'espresso_events',
1258
            'action' => 'edit',
1259
            'post' => $this->ID(),
1260
        ),
1261
            admin_url('admin.php')
1262
        );
1263
    }
1264
1265
1266
    /**
1267
     * Implementation for EEI_Admin_Links interface method.
1268
     *
1269
     * @see EEI_Admin_Links for comments
1270
     * @return string
1271
     */
1272
    public function get_admin_settings_link()
1273
    {
1274
        return EEH_URL::add_query_args_and_nonce(array(
1275
            'page' => 'espresso_events',
1276
            'action' => 'default_event_settings',
1277
        ),
1278
            admin_url('admin.php')
1279
        );
1280
    }
1281
1282
1283
    /**
1284
     * Implementation for EEI_Admin_Links interface method.
1285
     *
1286
     * @see EEI_Admin_Links for comments
1287
     * @return string
1288
     */
1289
    public function get_admin_overview_link()
1290
    {
1291
        return EEH_URL::add_query_args_and_nonce(array(
1292
            'page' => 'espresso_events',
1293
            'action' => 'default',
1294
        ),
1295
            admin_url('admin.php')
1296
        );
1297
    }
1298
1299
}
1300