Completed
Branch BUG-10738-inconsistency-in-ses... (cda363)
by
unknown
13:38 queued 12s
created

EE_Event   F

Complexity

Total Complexity 145

Size/Duplication

Total Lines 1289
Duplicated Lines 5.51 %

Coupling/Cohesion

Components 2
Dependencies 12

Importance

Changes 0
Metric Value
dl 71
loc 1289
rs 3.0857
c 0
b 0
f 0
wmc 145
lcom 2
cbo 12

81 Methods

Rating   Name   Duplication   Size   Complexity  
A set_slug() 0 4 1
A set_modified() 0 4 1
A set_event_phone() 0 4 1
A modified() 0 4 1
A new_instance() 0 5 2
A new_instance_from_db() 0 4 1
A getAvailableSpacesCalculator() 0 7 2
A set() 0 10 2
B set_status() 0 29 6
A datetimes() 0 4 1
A datetimes_in_chronological_order() 0 4 1
A datetimes_ordered() 0 9 1
A first_datetime() 0 4 1
A primary_datetime() 0 12 2
B tickets() 0 21 5
A active_tickets() 0 9 1
A additional_limit() 0 4 1
A allow_overflow() 0 4 1
A created() 0 4 1
A description() 0 4 1
A description_filtered() 0 4 1
A display_description() 0 4 1
A display_ticket_selector() 0 4 1
A external_url() 0 4 1
A member_only() 0 4 1
A phone() 0 4 1
A name() 0 4 1
A order() 0 4 1
A default_registration_status() 0 7 2
A short_description() 0 9 3
A slug() 0 4 1
A timezone_string() 0 4 1
A visible_on() 0 4 1
A wp_user() 0 4 1
A donations() 0 4 1
A set_additional_limit() 0 4 1
A set_created() 0 4 1
A set_description() 0 4 1
A set_display_description() 0 4 1
A set_display_ticket_selector() 0 4 1
A set_external_url() 0 4 1
A set_member_only() 0 4 1
A set_name() 0 4 1
A set_order() 0 4 1
A set_short_description() 0 4 1
A set_timezone_string() 0 4 1
A set_visible_on() 0 4 1
A set_wp_user() 0 4 1
A set_default_registration_status() 0 4 1
A set_donations() 0 4 1
A add_venue() 0 4 1
A remove_venue() 0 4 1
A venues() 0 4 1
B _has_ID_and_is_published() 0 13 6
B is_upcoming() 25 26 6
B is_active() 25 26 6
B is_expired() 21 22 6
A is_inactive() 0 8 2
A spaces_remaining() 0 13 2
B perform_sold_out_status_check() 0 28 5
A spaces_remaining_for_sale() 0 4 1
A total_available_spaces() 0 13 2
A is_sold_out() 0 7 2
A is_postponed() 0 4 1
A is_cancelled() 0 4 1
C get_active_status() 0 51 11
A pretty_active_status() 0 14 2
A get_number_of_tickets_sold() 0 14 4
A get_count_of_all_registrations() 0 4 1
A get_ticket_with_earliest_start_time() 0 6 1
A get_ticket_with_latest_end_time() 0 6 1
B tickets_on_sale() 0 13 5
A get_permalink() 0 7 2
A first_event_category() 0 6 1
A get_all_event_categories() 0 6 1
A question_groups() 0 5 2
A get_icon() 0 4 1
A get_admin_details_link() 0 4 1
A get_admin_edit_link() 0 10 1
A get_admin_settings_link() 0 9 1
A get_admin_overview_link() 0 9 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like EE_Event often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EE_Event, and based on these observations, apply Extract Interface, too.

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
            // 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
     * @throws DomainException
849
     * @throws UnexpectedEntityException
850
     */
851
    public function spaces_remaining($tickets = array(), $filtered = true)
852
    {
853
        $this->getAvailableSpacesCalculator()->setActiveTickets($tickets);
854
        $spaces_remaining = $this->getAvailableSpacesCalculator()->spacesRemaining();
855
        return $filtered
856
            ? apply_filters(
857
                'FHEE_EE_Event__spaces_remaining',
858
                $spaces_remaining,
859
                $this,
860
                $tickets
861
            )
862
            : $spaces_remaining;
863
    }
864
865
866
    /**
867
     *    perform_sold_out_status_check
868
     *    checks all of this events's datetime  reg_limit - sold values to determine if ANY datetimes have spaces available...
869
     *    if NOT, then the event status will get toggled to 'sold_out'
870
     *
871
     * @return bool    return the ACTUAL sold out state.
872
     * @throws EE_Error
873
     * @throws DomainException
874
     * @throws UnexpectedEntityException
875
     */
876
    public function perform_sold_out_status_check()
877
    {
878
        // get all unexpired untrashed tickets
879
        $tickets = $this->active_tickets();
880
        // if all the tickets are just expired, then don't update the event status to sold out
881
        if (empty($tickets)) {
882
            return true;
883
        }
884
        $spaces_remaining = $this->spaces_remaining($tickets);
885
        if ($spaces_remaining < 1) {
886
            $this->set_status(EEM_Event::sold_out);
887
            $this->save();
888
            $sold_out = true;
889
        } else {
890
            $sold_out = false;
891
            // was event previously marked as sold out ?
892
            if ($this->status() === EEM_Event::sold_out) {
893
                // revert status to previous value, if it was set
894
                $previous_event_status = $this->get_post_meta('_previous_event_status', true);
895
                if ($previous_event_status) {
896
                    $this->set_status($previous_event_status);
897
                    $this->save();
898
                }
899
            }
900
        }
901
        do_action('AHEE__EE_Event__perform_sold_out_status_check__end', $this, $sold_out, $spaces_remaining, $tickets);
902
        return $sold_out;
903
    }
904
905
906
907
    /**
908
     * This returns the total remaining spaces for sale on this event.
909
     *
910
     * @uses EE_Event::total_available_spaces()
911
     * @return float|int
912
     * @throws EE_Error
913
     * @throws DomainException
914
     * @throws UnexpectedEntityException
915
     */
916
    public function spaces_remaining_for_sale()
917
    {
918
        return $this->total_available_spaces(true);
919
    }
920
921
922
923
    /**
924
     * This returns the total spaces available for an event
925
     * while considering all the qtys on the tickets and the reg limits
926
     * on the datetimes attached to this event.
927
     *
928
     * @param   bool $consider_sold Whether to consider any tickets that have already sold in our calculation.
929
     *                              If this is false, then we return the most tickets that could ever be sold
930
     *                              for this event with the datetime and tickets setup on the event under optimal
931
     *                              selling conditions.  Otherwise we return a live calculation of spaces available
932
     *                              based on tickets sold.  Depending on setup and stage of sales, this
933
     *                              may appear to equal remaining tickets.  However, the more tickets are
934
     *                              sold out, the more accurate the "live" total is.
935
     * @return float|int
936
     * @throws EE_Error
937
     * @throws DomainException
938
     * @throws UnexpectedEntityException
939
     */
940
    public function total_available_spaces($consider_sold = false)
941
    {
942
        $spaces_available = $consider_sold
943
            ? $this->getAvailableSpacesCalculator()->spacesRemaining()
944
            : $this->getAvailableSpacesCalculator()->totalSpacesAvailable();
945
        return apply_filters(
946
            'FHEE_EE_Event__total_available_spaces__spaces_available',
947
            $spaces_available,
948
            $this,
949
            $this->getAvailableSpacesCalculator()->getDatetimes(),
950
            $this->getAvailableSpacesCalculator()->getActiveTickets()
951
        );
952
    }
953
954
955
    /**
956
     * Checks if the event is set to sold out
957
     *
958
     * @param  bool $actual whether or not to perform calculations to not only figure the
959
     *                      actual status but also to flip the status if necessary to sold
960
     *                      out If false, we just check the existing status of the event
961
     * @return boolean
962
     * @throws EE_Error
963
     */
964
    public function is_sold_out($actual = false)
965
    {
966
        if (!$actual) {
967
            return $this->status() === EEM_Event::sold_out;
968
        }
969
        return $this->perform_sold_out_status_check();
970
    }
971
972
973
    /**
974
     * Checks if the event is marked as postponed
975
     *
976
     * @return boolean
977
     */
978
    public function is_postponed()
979
    {
980
        return $this->status() === EEM_Event::postponed;
981
    }
982
983
984
    /**
985
     * Checks if the event is marked as cancelled
986
     *
987
     * @return boolean
988
     */
989
    public function is_cancelled()
990
    {
991
        return $this->status() === EEM_Event::cancelled;
992
    }
993
994
995
    /**
996
     * Get the logical active status in a hierarchical order for all the datetimes.  Note
997
     * Basically, we order the datetimes by EVT_start_date.  Then first test on whether the event is published.  If its
998
     * NOT published then we test for whether its expired or not.  IF it IS published then we test first on whether an
999
     * event has any active dates.  If no active dates then we check for any upcoming dates.  If no upcoming dates then
1000
     * the event is considered expired.
1001
     * NOTE: this method does NOT calculate whether the datetimes are sold out when event is published.  Sold Out is a status
1002
     * set on the EVENT when it is not published and thus is done
1003
     *
1004
     * @param bool $reset
1005
     * @return bool | string - based on EE_Datetime active constants or FALSE if error.
1006
     * @throws EE_Error
1007
     */
1008
    public function get_active_status($reset = false)
1009
    {
1010
        // if the active status has already been set, then just use that value (unless we are resetting it)
1011
        if (!empty($this->_active_status) && !$reset) {
1012
            return $this->_active_status;
1013
        }
1014
        //first check if event id is present on this object
1015
        if (!$this->ID()) {
1016
            return false;
1017
        }
1018
        $where_params_for_event = array(array('EVT_ID' => $this->ID()));
1019
        //if event is published:
1020
        if ($this->status() === 'publish') {
1021
            //active?
1022
            if (EEM_Datetime::instance()->get_datetime_count_for_status(EE_Datetime::active, $where_params_for_event) > 0) {
1023
                $this->_active_status = EE_Datetime::active;
1024
            } else {
1025
                //upcoming?
1026
                if (EEM_Datetime::instance()->get_datetime_count_for_status(EE_Datetime::upcoming, $where_params_for_event) > 0) {
1027
                    $this->_active_status = EE_Datetime::upcoming;
1028
                } else {
1029
                    //expired?
1030
                    if (
1031
                        EEM_Datetime::instance()->get_datetime_count_for_status(EE_Datetime::expired, $where_params_for_event) > 0
1032
                    ) {
1033
                        $this->_active_status = EE_Datetime::expired;
1034
                    } else {
1035
                        //it would be odd if things make it this far because it basically means there are no datetime's
1036
                        //attached to the event.  So in this case it will just be considered inactive.
1037
                        $this->_active_status = EE_Datetime::inactive;
1038
                    }
1039
                }
1040
            }
1041
        } else {
1042
            //the event is not published, so let's just set it's active status according to its' post status
1043
            switch ($this->status()) {
1044
                case EEM_Event::sold_out :
1045
                    $this->_active_status = EE_Datetime::sold_out;
1046
                    break;
1047
                case EEM_Event::cancelled :
1048
                    $this->_active_status = EE_Datetime::cancelled;
1049
                    break;
1050
                case EEM_Event::postponed :
1051
                    $this->_active_status = EE_Datetime::postponed;
1052
                    break;
1053
                default :
1054
                    $this->_active_status = EE_Datetime::inactive;
1055
            }
1056
        }
1057
        return $this->_active_status;
1058
    }
1059
1060
1061
    /**
1062
     *    pretty_active_status
1063
     *
1064
     * @access public
1065
     * @param boolean $echo whether to return (FALSE), or echo out the result (TRUE)
1066
     * @return mixed void|string
1067
     * @throws EE_Error
1068
     */
1069
    public function pretty_active_status($echo = true)
1070
    {
1071
        $active_status = $this->get_active_status();
1072
        $status = '<span class="ee-status event-active-status-'
1073
            . $active_status
1074
            . '">'
1075
            . EEH_Template::pretty_status($active_status, false, 'sentence')
1076
            . '</span>';
1077
        if ($echo) {
1078
            echo $status;
1079
            return '';
1080
        }
1081
        return $status;
1082
    }
1083
1084
1085
    /**
1086
     * @return bool|int
1087
     * @throws EE_Error
1088
     */
1089
    public function get_number_of_tickets_sold()
1090
    {
1091
        $tkt_sold = 0;
1092
        if (!$this->ID()) {
1093
            return 0;
1094
        }
1095
        $datetimes = $this->datetimes();
1096
        foreach ($datetimes as $datetime) {
1097
            if ($datetime instanceof EE_Datetime) {
1098
                $tkt_sold += $datetime->sold();
1099
            }
1100
        }
1101
        return $tkt_sold;
1102
    }
1103
1104
1105
    /**
1106
     * This just returns a count of all the registrations for this event
1107
     *
1108
     * @access  public
1109
     * @return int
1110
     * @throws EE_Error
1111
     */
1112
    public function get_count_of_all_registrations()
1113
    {
1114
        return EEM_Event::instance()->count_related($this, 'Registration');
1115
    }
1116
1117
1118
    /**
1119
     * This returns the ticket with the earliest start time that is
1120
     * available for this event (across all datetimes attached to the event)
1121
     *
1122
     * @return EE_Base_Class|EE_Ticket|null
1123
     * @throws EE_Error
1124
     */
1125
    public function get_ticket_with_earliest_start_time()
1126
    {
1127
        $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...
1128
        $query_params = array($where, 'order_by' => array('TKT_start_date' => 'ASC'));
1129
        return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1130
    }
1131
1132
1133
    /**
1134
     * This returns the ticket with the latest end time that is available
1135
     * 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_latest_end_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_end_date' => 'DESC'));
1144
        return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1145
    }
1146
1147
1148
    /**
1149
     * This returns whether there are any tickets on sale for this event.
1150
     *
1151
     * @return bool true = YES tickets on sale.
1152
     * @throws EE_Error
1153
     */
1154
    public function tickets_on_sale()
1155
    {
1156
        $earliest_ticket = $this->get_ticket_with_earliest_start_time();
1157
        $latest_ticket = $this->get_ticket_with_latest_end_time();
1158
        if (!$latest_ticket instanceof EE_Ticket && !$earliest_ticket instanceof EE_Ticket) {
1159
            return false;
1160
        }
1161
        //check on sale for these two tickets.
1162
        if ($latest_ticket->is_on_sale() || $earliest_ticket->is_on_sale()) {
1163
            return true;
1164
        }
1165
        return false;
1166
    }
1167
1168
1169
    /**
1170
     * Gets the URL for viewing this event on the front-end. Overrides parent
1171
     * to check for an external URL first
1172
     *
1173
     * @return string
1174
     * @throws EE_Error
1175
     */
1176
    public function get_permalink()
1177
    {
1178
        if ($this->external_url()) {
1179
            return $this->external_url();
1180
        }
1181
        return parent::get_permalink();
1182
    }
1183
1184
1185
    /**
1186
     * Gets the first term for 'espresso_event_categories' we can find
1187
     *
1188
     * @param array $query_params like EEM_Base::get_all
1189
     * @return EE_Base_Class|EE_Term|null
1190
     * @throws EE_Error
1191
     */
1192
    public function first_event_category($query_params = array())
1193
    {
1194
        $query_params[0]['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1195
        $query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1196
        return EEM_Term::instance()->get_one($query_params);
1197
    }
1198
1199
1200
    /**
1201
     * Gets all terms for 'espresso_event_categories' we can find
1202
     *
1203
     * @param array $query_params
1204
     * @return EE_Base_Class[]|EE_Term[]
1205
     * @throws EE_Error
1206
     */
1207
    public function get_all_event_categories($query_params = array())
1208
    {
1209
        $query_params[0]['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1210
        $query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1211
        return EEM_Term::instance()->get_all($query_params);
1212
    }
1213
1214
1215
    /**
1216
     * Gets all the question groups, ordering them by QSG_order ascending
1217
     *
1218
     * @param array $query_params @see EEM_Base::get_all
1219
     * @return EE_Base_Class[]|EE_Question_Group[]
1220
     * @throws EE_Error
1221
     */
1222
    public function question_groups($query_params = array())
1223
    {
1224
        $query_params = !empty($query_params) ? $query_params : array('order_by' => array('QSG_order' => 'ASC'));
1225
        return $this->get_many_related('Question_Group', $query_params);
1226
    }
1227
1228
1229
    /**
1230
     * Implementation for EEI_Has_Icon interface method.
1231
     *
1232
     * @see EEI_Visual_Representation for comments
1233
     * @return string
1234
     */
1235
    public function get_icon()
1236
    {
1237
        return '<span class="dashicons dashicons-flag"></span>';
1238
    }
1239
1240
1241
    /**
1242
     * Implementation for EEI_Admin_Links interface method.
1243
     *
1244
     * @see EEI_Admin_Links for comments
1245
     * @return string
1246
     * @throws EE_Error
1247
     */
1248
    public function get_admin_details_link()
1249
    {
1250
        return $this->get_admin_edit_link();
1251
    }
1252
1253
1254
    /**
1255
     * Implementation for EEI_Admin_Links interface method.
1256
     *
1257
     * @see EEI_Admin_Links for comments
1258
     * @return string
1259
     * @throws EE_Error
1260
     */
1261
    public function get_admin_edit_link()
1262
    {
1263
        return EEH_URL::add_query_args_and_nonce(array(
1264
            'page' => 'espresso_events',
1265
            'action' => 'edit',
1266
            'post' => $this->ID(),
1267
        ),
1268
            admin_url('admin.php')
1269
        );
1270
    }
1271
1272
1273
    /**
1274
     * Implementation for EEI_Admin_Links interface method.
1275
     *
1276
     * @see EEI_Admin_Links for comments
1277
     * @return string
1278
     */
1279
    public function get_admin_settings_link()
1280
    {
1281
        return EEH_URL::add_query_args_and_nonce(array(
1282
            'page' => 'espresso_events',
1283
            'action' => 'default_event_settings',
1284
        ),
1285
            admin_url('admin.php')
1286
        );
1287
    }
1288
1289
1290
    /**
1291
     * Implementation for EEI_Admin_Links interface method.
1292
     *
1293
     * @see EEI_Admin_Links for comments
1294
     * @return string
1295
     */
1296
    public function get_admin_overview_link()
1297
    {
1298
        return EEH_URL::add_query_args_and_nonce(array(
1299
            'page' => 'espresso_events',
1300
            'action' => 'default',
1301
        ),
1302
            admin_url('admin.php')
1303
        );
1304
    }
1305
1306
}
1307