Completed
Branch BUG/11302/correct-error-messag... (694f28)
by
unknown
29:47 queued 12:21
created

EE_Event::add_question_group()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

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