Completed
Branch TASK/update-about-page (5cee29)
by
unknown
34:34 queued 26:08
created

EE_Datetime::parent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
use EventEspresso\core\exceptions\InvalidDataTypeException;
4
use EventEspresso\core\exceptions\InvalidInterfaceException;
5
6
/**
7
 * EE_Datetime class
8
 *
9
 * @package     Event Espresso
10
 * @subpackage  includes/classes/EE_Datetime.class.php
11
 * @author      Brent Christensen
12
 */
13
class EE_Datetime extends EE_Soft_Delete_Base_Class
14
{
15
16
    /**
17
     * constant used by get_active_status, indicates datetime has no more available spaces
18
     */
19
    const sold_out = 'DTS';
20
21
    /**
22
     * constant used by get_active_status, indicating datetime is still active (even is not over, can be registered-for)
23
     */
24
    const active = 'DTA';
25
26
    /**
27
     * constant used by get_active_status, indicating the datetime cannot be used for registrations yet, but has not
28
     * expired
29
     */
30
    const upcoming = 'DTU';
31
32
    /**
33
     * Datetime is postponed
34
     */
35
    const postponed = 'DTP';
36
37
    /**
38
     * Datetime is cancelled
39
     */
40
    const cancelled = 'DTC';
41
42
    /**
43
     * constant used by get_active_status, indicates datetime has expired (event is over)
44
     */
45
    const expired = 'DTE';
46
47
    /**
48
     * constant used in various places indicating that an event is INACTIVE (not yet ready to be published)
49
     */
50
    const inactive = 'DTI';
51
52
53
    /**
54
     * @param array  $props_n_values    incoming values
55
     * @param string $timezone          incoming timezone (if not set the timezone set for the website will be used.)
56
     * @param array  $date_formats      incoming date_formats in an array where the first value is the date_format
57
     *                                  and the second value is the time format
58
     * @return EE_Datetime
59
     * @throws ReflectionException
60
     * @throws InvalidArgumentException
61
     * @throws InvalidInterfaceException
62
     * @throws InvalidDataTypeException
63
     * @throws EE_Error
64
     */
65 View Code Duplication
    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
66
    {
67
        $has_object = parent::_check_for_object(
68
            $props_n_values,
69
            __CLASS__,
70
            $timezone,
71
            $date_formats
72
        );
73
        return $has_object
74
            ? $has_object
75
            : new self($props_n_values, false, $timezone, $date_formats);
76
    }
77
78
79
    /**
80
     * @param array  $props_n_values  incoming values from the database
81
     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
82
     *                                the website will be used.
83
     * @return EE_Datetime
84
     * @throws ReflectionException
85
     * @throws InvalidArgumentException
86
     * @throws InvalidInterfaceException
87
     * @throws InvalidDataTypeException
88
     * @throws EE_Error
89
     */
90
    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
91
    {
92
        return new self($props_n_values, true, $timezone);
93
    }
94
95
96
    /**
97
     * @param $name
98
     * @throws ReflectionException
99
     * @throws InvalidArgumentException
100
     * @throws InvalidInterfaceException
101
     * @throws InvalidDataTypeException
102
     * @throws EE_Error
103
     */
104
    public function set_name($name)
105
    {
106
        $this->set('DTT_name', $name);
107
    }
108
109
110
    /**
111
     * @param $description
112
     * @throws ReflectionException
113
     * @throws InvalidArgumentException
114
     * @throws InvalidInterfaceException
115
     * @throws InvalidDataTypeException
116
     * @throws EE_Error
117
     */
118
    public function set_description($description)
119
    {
120
        $this->set('DTT_description', $description);
121
    }
122
123
124
    /**
125
     * Set event start date
126
     * set the start date for an event
127
     *
128
     * @param string $date a string representation of the event's date ex:  Dec. 25, 2025 or 12-25-2025
129
     * @throws ReflectionException
130
     * @throws InvalidArgumentException
131
     * @throws InvalidInterfaceException
132
     * @throws InvalidDataTypeException
133
     * @throws EE_Error
134
     */
135
    public function set_start_date($date)
136
    {
137
        $this->_set_date_for($date, 'DTT_EVT_start');
138
    }
139
140
141
    /**
142
     * Set event start time
143
     * set the start time for an event
144
     *
145
     * @param string $time a string representation of the event time ex:  9am  or  7:30 PM
146
     * @throws ReflectionException
147
     * @throws InvalidArgumentException
148
     * @throws InvalidInterfaceException
149
     * @throws InvalidDataTypeException
150
     * @throws EE_Error
151
     */
152
    public function set_start_time($time)
153
    {
154
        $this->_set_time_for($time, 'DTT_EVT_start');
155
    }
156
157
158
    /**
159
     * Set event end date
160
     * set the end date for an event
161
     *
162
     * @param string $date a string representation of the event's date ex:  Dec. 25, 2025 or 12-25-2025
163
     * @throws ReflectionException
164
     * @throws InvalidArgumentException
165
     * @throws InvalidInterfaceException
166
     * @throws InvalidDataTypeException
167
     * @throws EE_Error
168
     */
169
    public function set_end_date($date)
170
    {
171
        $this->_set_date_for($date, 'DTT_EVT_end');
172
    }
173
174
175
    /**
176
     * Set event end time
177
     * set the end time for an event
178
     *
179
     * @param string $time a string representation of the event time ex:  9am  or  7:30 PM
180
     * @throws ReflectionException
181
     * @throws InvalidArgumentException
182
     * @throws InvalidInterfaceException
183
     * @throws InvalidDataTypeException
184
     * @throws EE_Error
185
     */
186
    public function set_end_time($time)
187
    {
188
        $this->_set_time_for($time, 'DTT_EVT_end');
189
    }
190
191
192
    /**
193
     * Set registration limit
194
     * set the maximum number of attendees that can be registered for this datetime slot
195
     *
196
     * @param int $reg_limit
197
     * @throws ReflectionException
198
     * @throws InvalidArgumentException
199
     * @throws InvalidInterfaceException
200
     * @throws InvalidDataTypeException
201
     * @throws EE_Error
202
     */
203
    public function set_reg_limit($reg_limit)
204
    {
205
        $this->set('DTT_reg_limit', $reg_limit);
206
    }
207
208
209
    /**
210
     * get the number of tickets sold for this datetime slot
211
     *
212
     * @return mixed int on success, FALSE on fail
213
     * @throws ReflectionException
214
     * @throws InvalidArgumentException
215
     * @throws InvalidInterfaceException
216
     * @throws InvalidDataTypeException
217
     * @throws EE_Error
218
     */
219
    public function sold()
220
    {
221
        return $this->get_raw('DTT_sold');
222
    }
223
224
225
    /**
226
     * @param int $sold
227
     * @throws ReflectionException
228
     * @throws InvalidArgumentException
229
     * @throws InvalidInterfaceException
230
     * @throws InvalidDataTypeException
231
     * @throws EE_Error
232
     */
233
    public function set_sold($sold)
234
    {
235
        // sold can not go below zero
236
        $sold = max(0, $sold);
237
        $this->set('DTT_sold', $sold);
238
    }
239
240
241
    /**
242
     * Increments sold by amount passed by $qty, and persists it immediately to the database.
243
     * Simultaneously decreases the reserved count, unless $also_decrease_reserved is false.
244
     *
245
     * @param int $qty
246
     * @param boolean $also_decrease_reserved
247
     * @return boolean indicating success
248
     * @throws ReflectionException
249
     * @throws InvalidArgumentException
250
     * @throws InvalidInterfaceException
251
     * @throws InvalidDataTypeException
252
     * @throws EE_Error
253
     */
254
    public function increaseSold($qty = 1, $also_decrease_reserved = true)
255
    {
256
        $qty = absint($qty);
257
        if ($also_decrease_reserved) {
258
            $success = $this->adjustNumericFieldsInDb(
259
                [
260
                    'DTT_reserved' => $qty * -1,
261
                    'DTT_sold' => $qty
262
                ]
263
            );
264
        } else {
265
            $success = $this->adjustNumericFieldsInDb(
266
                [
267
                    'DTT_sold' => $qty
268
                ]
269
            );
270
        }
271
272
        do_action(
273
            'AHEE__EE_Datetime__increase_sold',
274
            $this,
275
            $qty,
276
            $this->sold(),
277
            $success
278
        );
279
        return $success;
280
    }
281
282
283
    /**
284
     * Decrements (subtracts) sold amount passed by $qty directly in the DB and on the model object. (Ie, no need
285
     * to save afterwards.)
286
     *
287
     * @param int $qty
288
     * @return boolean indicating success
289
     * @throws ReflectionException
290
     * @throws InvalidArgumentException
291
     * @throws InvalidInterfaceException
292
     * @throws InvalidDataTypeException
293
     * @throws EE_Error
294
     */
295
    public function decreaseSold($qty = 1)
296
    {
297
        $qty = absint($qty);
298
        $success = $this->adjustNumericFieldsInDb(
299
            [
300
                'DTT_sold' => $qty * -1
301
            ]
302
        );
303
        do_action(
304
            'AHEE__EE_Datetime__decrease_sold',
305
            $this,
306
            $qty,
307
            $this->sold(),
308
            $success
309
        );
310
        return $success;
311
    }
312
313
314
    /**
315
     * Gets qty of reserved tickets for this datetime
316
     *
317
     * @return int
318
     * @throws ReflectionException
319
     * @throws InvalidArgumentException
320
     * @throws InvalidInterfaceException
321
     * @throws InvalidDataTypeException
322
     * @throws EE_Error
323
     */
324
    public function reserved()
325
    {
326
        return $this->get_raw('DTT_reserved');
327
    }
328
329
330
    /**
331
     * Sets qty of reserved tickets for this datetime
332
     *
333
     * @param int $reserved
334
     * @throws ReflectionException
335
     * @throws InvalidArgumentException
336
     * @throws InvalidInterfaceException
337
     * @throws InvalidDataTypeException
338
     * @throws EE_Error
339
     */
340
    public function set_reserved($reserved)
341
    {
342
        // reserved can not go below zero
343
        $reserved = max(0, (int) $reserved);
344
        $this->set('DTT_reserved', $reserved);
345
    }
346
347
348
    /**
349
     * Increments reserved by amount passed by $qty, and persists it immediately to the database.
350
     *
351
     * @param int $qty
352
     * @return boolean indicating success
353
     * @throws ReflectionException
354
     * @throws InvalidArgumentException
355
     * @throws InvalidInterfaceException
356
     * @throws InvalidDataTypeException
357
     * @throws EE_Error
358
     */
359
    public function increaseReserved($qty = 1)
360
    {
361
        $qty = absint($qty);
362
        $success = $this->incrementFieldConditionallyInDb(
363
            'DTT_reserved',
364
            'DTT_sold',
365
            'DTT_reg_limit',
366
            $qty
367
        );
368
        do_action(
369
            'AHEE__EE_Datetime__increase_reserved',
370
            $this,
371
            $qty,
372
            $this->reserved(),
373
            $success
374
        );
375
        return $success;
376
    }
377
378
379
    /**
380
     * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
381
     *
382
     * @param int $qty
383
     * @return boolean indicating success
384
     * @throws ReflectionException
385
     * @throws InvalidArgumentException
386
     * @throws InvalidInterfaceException
387
     * @throws InvalidDataTypeException
388
     * @throws EE_Error
389
     */
390
    public function decreaseReserved($qty = 1)
391
    {
392
        $qty = absint($qty);
393
        $success = $this->adjustNumericFieldsInDb(
394
            [
395
                'DTT_reserved' => $qty * -1
396
            ]
397
        );
398
        do_action(
399
            'AHEE__EE_Datetime__decrease_reserved',
400
            $this,
401
            $qty,
402
            $this->reserved(),
403
            $success
404
        );
405
        return $success;
406
    }
407
408
409
    /**
410
     * total sold and reserved tickets
411
     *
412
     * @return int
413
     * @throws ReflectionException
414
     * @throws InvalidArgumentException
415
     * @throws InvalidInterfaceException
416
     * @throws InvalidDataTypeException
417
     * @throws EE_Error
418
     */
419
    public function sold_and_reserved()
420
    {
421
        return $this->sold() + $this->reserved();
422
    }
423
424
425
    /**
426
     * returns the datetime name
427
     *
428
     * @return string
429
     * @throws ReflectionException
430
     * @throws InvalidArgumentException
431
     * @throws InvalidInterfaceException
432
     * @throws InvalidDataTypeException
433
     * @throws EE_Error
434
     */
435
    public function name()
436
    {
437
        return $this->get('DTT_name');
438
    }
439
440
441
    /**
442
     * returns the datetime description
443
     *
444
     * @return string
445
     * @throws ReflectionException
446
     * @throws InvalidArgumentException
447
     * @throws InvalidInterfaceException
448
     * @throws InvalidDataTypeException
449
     * @throws EE_Error
450
     */
451
    public function description()
452
    {
453
        return $this->get('DTT_description');
454
    }
455
456
457
    /**
458
     * This helper simply returns whether the event_datetime for the current datetime is a primary datetime
459
     *
460
     * @return boolean  TRUE if is primary, FALSE if not.
461
     * @throws ReflectionException
462
     * @throws InvalidArgumentException
463
     * @throws InvalidInterfaceException
464
     * @throws InvalidDataTypeException
465
     * @throws EE_Error
466
     */
467
    public function is_primary()
468
    {
469
        return $this->get('DTT_is_primary');
470
    }
471
472
473
    /**
474
     * This helper simply returns the order for the datetime
475
     *
476
     * @return int  The order of the datetime for this event.
477
     * @throws ReflectionException
478
     * @throws InvalidArgumentException
479
     * @throws InvalidInterfaceException
480
     * @throws InvalidDataTypeException
481
     * @throws EE_Error
482
     */
483
    public function order()
484
    {
485
        return $this->get('DTT_order');
486
    }
487
488
489
    /**
490
     * This helper simply returns the parent id for the datetime
491
     *
492
     * @return int
493
     * @throws ReflectionException
494
     * @throws InvalidArgumentException
495
     * @throws InvalidInterfaceException
496
     * @throws InvalidDataTypeException
497
     * @throws EE_Error
498
     */
499
    public function parent()
500
    {
501
        return $this->get('DTT_parent');
502
    }
503
504
505
    /**
506
     * show date and/or time
507
     *
508
     * @param string $date_or_time    whether to display a date or time or both
509
     * @param string $start_or_end    whether to display start or end datetimes
510
     * @param string $dt_frmt
511
     * @param string $tm_frmt
512
     * @param bool   $echo            whether we echo or return (note echoing uses "pretty" formats,
513
     *                                otherwise we use the standard formats)
514
     * @return string|bool  string on success, FALSE on fail
515
     * @throws ReflectionException
516
     * @throws InvalidArgumentException
517
     * @throws InvalidInterfaceException
518
     * @throws InvalidDataTypeException
519
     * @throws EE_Error
520
     */
521
    private function _show_datetime(
522
        $date_or_time = null,
523
        $start_or_end = 'start',
524
        $dt_frmt = '',
525
        $tm_frmt = '',
526
        $echo = false
527
    ) {
528
        $field_name = "DTT_EVT_{$start_or_end}";
529
        $dtt = $this->_get_datetime(
530
            $field_name,
531
            $dt_frmt,
532
            $tm_frmt,
533
            $date_or_time,
534
            $echo
535
        );
536
        if (! $echo) {
537
            return $dtt;
538
        }
539
        return '';
540
    }
541
542
543
    /**
544
     * get event start date.  Provide either the date format, or NULL to re-use the
545
     * last-used format, or '' to use the default date format
546
     *
547
     * @param string $dt_frmt string representation of date format defaults to 'F j, Y'
548
     * @return mixed            string on success, FALSE on fail
549
     * @throws ReflectionException
550
     * @throws InvalidArgumentException
551
     * @throws InvalidInterfaceException
552
     * @throws InvalidDataTypeException
553
     * @throws EE_Error
554
     */
555
    public function start_date($dt_frmt = '')
556
    {
557
        return $this->_show_datetime('D', 'start', $dt_frmt);
558
    }
559
560
561
    /**
562
     * Echoes start_date()
563
     *
564
     * @param string $dt_frmt
565
     * @throws ReflectionException
566
     * @throws InvalidArgumentException
567
     * @throws InvalidInterfaceException
568
     * @throws InvalidDataTypeException
569
     * @throws EE_Error
570
     */
571
    public function e_start_date($dt_frmt = '')
572
    {
573
        $this->_show_datetime('D', 'start', $dt_frmt, null, true);
574
    }
575
576
577
    /**
578
     * get end date. Provide either the date format, or NULL to re-use the
579
     * last-used format, or '' to use the default date format
580
     *
581
     * @param string $dt_frmt string representation of date format defaults to 'F j, Y'
582
     * @return mixed            string on success, FALSE on fail
583
     * @throws ReflectionException
584
     * @throws InvalidArgumentException
585
     * @throws InvalidInterfaceException
586
     * @throws InvalidDataTypeException
587
     * @throws EE_Error
588
     */
589
    public function end_date($dt_frmt = '')
590
    {
591
        return $this->_show_datetime('D', 'end', $dt_frmt);
592
    }
593
594
595
    /**
596
     * Echoes the end date. See end_date()
597
     *
598
     * @param string $dt_frmt
599
     * @throws ReflectionException
600
     * @throws InvalidArgumentException
601
     * @throws InvalidInterfaceException
602
     * @throws InvalidDataTypeException
603
     * @throws EE_Error
604
     */
605
    public function e_end_date($dt_frmt = '')
606
    {
607
        $this->_show_datetime('D', 'end', $dt_frmt, null, true);
608
    }
609
610
611
    /**
612
     * get date_range - meaning the start AND end date
613
     *
614
     * @access public
615
     * @param string $dt_frmt     string representation of date format defaults to WP settings
616
     * @param string $conjunction conjunction junction what's your function ?
617
     *                            this string joins the start date with the end date ie: Jan 01 "to" Dec 31
618
     * @return mixed              string on success, FALSE on fail
619
     * @throws ReflectionException
620
     * @throws InvalidArgumentException
621
     * @throws InvalidInterfaceException
622
     * @throws InvalidDataTypeException
623
     * @throws EE_Error
624
     */
625 View Code Duplication
    public function date_range($dt_frmt = '', $conjunction = ' - ')
626
    {
627
        $dt_frmt = ! empty($dt_frmt) ? $dt_frmt : $this->_dt_frmt;
628
        $start = str_replace(
629
            ' ',
630
            '&nbsp;',
631
            $this->get_i18n_datetime('DTT_EVT_start', $dt_frmt)
632
        );
633
        $end = str_replace(
634
            ' ',
635
            '&nbsp;',
636
            $this->get_i18n_datetime('DTT_EVT_end', $dt_frmt)
637
        );
638
        return $start !== $end ? $start . $conjunction . $end : $start;
639
    }
640
641
642
    /**
643
     * @param string $dt_frmt
644
     * @param string $conjunction
645
     * @throws ReflectionException
646
     * @throws InvalidArgumentException
647
     * @throws InvalidInterfaceException
648
     * @throws InvalidDataTypeException
649
     * @throws EE_Error
650
     */
651
    public function e_date_range($dt_frmt = '', $conjunction = ' - ')
652
    {
653
        echo $this->date_range($dt_frmt, $conjunction);
654
    }
655
656
657
    /**
658
     * get start time
659
     *
660
     * @param string $tm_format - string representation of time format defaults to 'g:i a'
661
     * @return mixed        string on success, FALSE on fail
662
     * @throws ReflectionException
663
     * @throws InvalidArgumentException
664
     * @throws InvalidInterfaceException
665
     * @throws InvalidDataTypeException
666
     * @throws EE_Error
667
     */
668
    public function start_time($tm_format = '')
669
    {
670
        return $this->_show_datetime('T', 'start', null, $tm_format);
671
    }
672
673
674
    /**
675
     * @param string $tm_format
676
     * @throws ReflectionException
677
     * @throws InvalidArgumentException
678
     * @throws InvalidInterfaceException
679
     * @throws InvalidDataTypeException
680
     * @throws EE_Error
681
     */
682
    public function e_start_time($tm_format = '')
683
    {
684
        $this->_show_datetime('T', 'start', null, $tm_format, true);
685
    }
686
687
688
    /**
689
     * get end time
690
     *
691
     * @param string $tm_format string representation of time format defaults to 'g:i a'
692
     * @return mixed                string on success, FALSE on fail
693
     * @throws ReflectionException
694
     * @throws InvalidArgumentException
695
     * @throws InvalidInterfaceException
696
     * @throws InvalidDataTypeException
697
     * @throws EE_Error
698
     */
699
    public function end_time($tm_format = '')
700
    {
701
        return $this->_show_datetime('T', 'end', null, $tm_format);
702
    }
703
704
705
    /**
706
     * @param string $tm_format
707
     * @throws ReflectionException
708
     * @throws InvalidArgumentException
709
     * @throws InvalidInterfaceException
710
     * @throws InvalidDataTypeException
711
     * @throws EE_Error
712
     */
713
    public function e_end_time($tm_format = '')
714
    {
715
        $this->_show_datetime('T', 'end', null, $tm_format, true);
716
    }
717
718
719
    /**
720
     * get time_range
721
     *
722
     * @access public
723
     * @param string $tm_format   string representation of time format defaults to 'g:i a'
724
     * @param string $conjunction conjunction junction what's your function ?
725
     *                            this string joins the start date with the end date ie: Jan 01 "to" Dec 31
726
     * @return mixed              string on success, FALSE on fail
727
     * @throws ReflectionException
728
     * @throws InvalidArgumentException
729
     * @throws InvalidInterfaceException
730
     * @throws InvalidDataTypeException
731
     * @throws EE_Error
732
     */
733 View Code Duplication
    public function time_range($tm_format = '', $conjunction = ' - ')
734
    {
735
        $tm_format = ! empty($tm_format) ? $tm_format : $this->_tm_frmt;
736
        $start = str_replace(
737
            ' ',
738
            '&nbsp;',
739
            $this->get_i18n_datetime('DTT_EVT_start', $tm_format)
740
        );
741
        $end = str_replace(
742
            ' ',
743
            '&nbsp;',
744
            $this->get_i18n_datetime('DTT_EVT_end', $tm_format)
745
        );
746
        return $start !== $end ? $start . $conjunction . $end : $start;
747
    }
748
749
750
    /**
751
     * @param string $tm_format
752
     * @param string $conjunction
753
     * @throws ReflectionException
754
     * @throws InvalidArgumentException
755
     * @throws InvalidInterfaceException
756
     * @throws InvalidDataTypeException
757
     * @throws EE_Error
758
     */
759
    public function e_time_range($tm_format = '', $conjunction = ' - ')
760
    {
761
        echo $this->time_range($tm_format, $conjunction);
762
    }
763
764
765
    /**
766
     * This returns a range representation of the date and times.
767
     * Output is dependent on the difference (or similarity) between DTT_EVT_start and DTT_EVT_end.
768
     * Also, the return value is localized.
769
     *
770
     * @param string $dt_format
771
     * @param string $tm_format
772
     * @param string $conjunction used between two different dates or times.
773
     *                            ex: Dec 1{$conjunction}}Dec 6, or 2pm{$conjunction}3pm
774
     * @param string $separator   used between the date and time formats.
775
     *                            ex: Dec 1, 2016{$separator}2pm
776
     * @return string
777
     * @throws ReflectionException
778
     * @throws InvalidArgumentException
779
     * @throws InvalidInterfaceException
780
     * @throws InvalidDataTypeException
781
     * @throws EE_Error
782
     */
783
    public function date_and_time_range(
784
        $dt_format = '',
785
        $tm_format = '',
786
        $conjunction = ' - ',
787
        $separator = ' '
788
    ) {
789
        $dt_format = ! empty($dt_format) ? $dt_format : $this->_dt_frmt;
790
        $tm_format = ! empty($tm_format) ? $tm_format : $this->_tm_frmt;
791
        $full_format = $dt_format . $separator . $tm_format;
792
        // the range output depends on various conditions
793
        switch (true) {
794
            // start date timestamp and end date timestamp are the same.
795
            case ($this->get_raw('DTT_EVT_start') === $this->get_raw('DTT_EVT_end')):
796
                $output = $this->get_i18n_datetime('DTT_EVT_start', $full_format);
797
                break;
798
            // start and end date are the same but times are different
799
            case ($this->start_date() === $this->end_date()):
800
                $output = $this->get_i18n_datetime('DTT_EVT_start', $full_format)
801
                          . $conjunction
802
                          . $this->get_i18n_datetime('DTT_EVT_end', $tm_format);
803
                break;
804
            // all other conditions
805
            default:
806
                $output = $this->get_i18n_datetime('DTT_EVT_start', $full_format)
807
                          . $conjunction
808
                          . $this->get_i18n_datetime('DTT_EVT_end', $full_format);
809
                break;
810
        }
811
        return $output;
812
    }
813
814
815
    /**
816
     * This echos the results of date and time range.
817
     *
818
     * @see date_and_time_range() for more details on purpose.
819
     * @param string $dt_format
820
     * @param string $tm_format
821
     * @param string $conjunction
822
     * @return void
823
     * @throws ReflectionException
824
     * @throws InvalidArgumentException
825
     * @throws InvalidInterfaceException
826
     * @throws InvalidDataTypeException
827
     * @throws EE_Error
828
     */
829
    public function e_date_and_time_range($dt_format = '', $tm_format = '', $conjunction = ' - ')
830
    {
831
        echo $this->date_and_time_range($dt_format, $tm_format, $conjunction);
832
    }
833
834
835
    /**
836
     * get start date and start time
837
     *
838
     * @param    string $dt_format - string representation of date format defaults to 'F j, Y'
839
     * @param    string $tm_format - string representation of time format defaults to 'g:i a'
840
     * @return    mixed    string on success, FALSE on fail
841
     * @throws ReflectionException
842
     * @throws InvalidArgumentException
843
     * @throws InvalidInterfaceException
844
     * @throws InvalidDataTypeException
845
     * @throws EE_Error
846
     */
847
    public function start_date_and_time($dt_format = '', $tm_format = '')
848
    {
849
        return $this->_show_datetime('', 'start', $dt_format, $tm_format);
850
    }
851
852
853
    /**
854
     * @param string $dt_frmt
855
     * @param string $tm_format
856
     * @throws ReflectionException
857
     * @throws InvalidArgumentException
858
     * @throws InvalidInterfaceException
859
     * @throws InvalidDataTypeException
860
     * @throws EE_Error
861
     */
862
    public function e_start_date_and_time($dt_frmt = '', $tm_format = '')
863
    {
864
        $this->_show_datetime('', 'start', $dt_frmt, $tm_format, true);
865
    }
866
867
868
    /**
869
     * Shows the length of the event (start to end time).
870
     * Can be shown in 'seconds','minutes','hours', or 'days'.
871
     * By default, rounds up. (So if you use 'days', and then event
872
     * only occurs for 1 hour, it will return 1 day).
873
     *
874
     * @param string $units 'seconds','minutes','hours','days'
875
     * @param bool   $round_up
876
     * @return float|int|mixed
877
     * @throws ReflectionException
878
     * @throws InvalidArgumentException
879
     * @throws InvalidInterfaceException
880
     * @throws InvalidDataTypeException
881
     * @throws EE_Error
882
     */
883
    public function length($units = 'seconds', $round_up = false)
884
    {
885
        $start = $this->get_raw('DTT_EVT_start');
886
        $end = $this->get_raw('DTT_EVT_end');
887
        $length_in_units = $end - $start;
888
        switch ($units) {
889
            // NOTE: We purposefully don't use "break;" in order to chain the divisions
890
            /** @noinspection PhpMissingBreakStatementInspection */
891
            // phpcs:disable PSR2.ControlStructures.SwitchDeclaration.TerminatingComment
892
            case 'days':
893
                $length_in_units /= 24;
894
            /** @noinspection PhpMissingBreakStatementInspection */
895
            case 'hours':
896
                // fall through is intentional
897
                $length_in_units /= 60;
898
            /** @noinspection PhpMissingBreakStatementInspection */
899
            case 'minutes':
900
                // fall through is intentional
901
                $length_in_units /= 60;
902
            case 'seconds':
903
            default:
904
                $length_in_units = ceil($length_in_units);
905
        }
906
        // phpcs:enable
907
        if ($round_up) {
908
            $length_in_units = max($length_in_units, 1);
909
        }
910
        return $length_in_units;
911
    }
912
913
914
    /**
915
     *        get end date and time
916
     *
917
     * @param string $dt_frmt   - string representation of date format defaults to 'F j, Y'
918
     * @param string $tm_format - string representation of time format defaults to 'g:i a'
919
     * @return    mixed                string on success, FALSE on fail
920
     * @throws ReflectionException
921
     * @throws InvalidArgumentException
922
     * @throws InvalidInterfaceException
923
     * @throws InvalidDataTypeException
924
     * @throws EE_Error
925
     */
926
    public function end_date_and_time($dt_frmt = '', $tm_format = '')
927
    {
928
        return $this->_show_datetime('', 'end', $dt_frmt, $tm_format);
929
    }
930
931
932
    /**
933
     * @param string $dt_frmt
934
     * @param string $tm_format
935
     * @throws ReflectionException
936
     * @throws InvalidArgumentException
937
     * @throws InvalidInterfaceException
938
     * @throws InvalidDataTypeException
939
     * @throws EE_Error
940
     */
941
    public function e_end_date_and_time($dt_frmt = '', $tm_format = '')
942
    {
943
        $this->_show_datetime('', 'end', $dt_frmt, $tm_format, true);
944
    }
945
946
947
    /**
948
     *        get start timestamp
949
     *
950
     * @return        int
951
     * @throws ReflectionException
952
     * @throws InvalidArgumentException
953
     * @throws InvalidInterfaceException
954
     * @throws InvalidDataTypeException
955
     * @throws EE_Error
956
     */
957
    public function start()
958
    {
959
        return $this->get_raw('DTT_EVT_start');
960
    }
961
962
963
    /**
964
     *        get end timestamp
965
     *
966
     * @return        int
967
     * @throws ReflectionException
968
     * @throws InvalidArgumentException
969
     * @throws InvalidInterfaceException
970
     * @throws InvalidDataTypeException
971
     * @throws EE_Error
972
     */
973
    public function end()
974
    {
975
        return $this->get_raw('DTT_EVT_end');
976
    }
977
978
979
    /**
980
     *    get the registration limit for this datetime slot
981
     *
982
     * @return        mixed        int on success, FALSE on fail
983
     * @throws ReflectionException
984
     * @throws InvalidArgumentException
985
     * @throws InvalidInterfaceException
986
     * @throws InvalidDataTypeException
987
     * @throws EE_Error
988
     */
989
    public function reg_limit()
990
    {
991
        return $this->get_raw('DTT_reg_limit');
992
    }
993
994
995
    /**
996
     *    have the tickets sold for this datetime, met or exceed the registration limit ?
997
     *
998
     * @return        boolean
999
     * @throws ReflectionException
1000
     * @throws InvalidArgumentException
1001
     * @throws InvalidInterfaceException
1002
     * @throws InvalidDataTypeException
1003
     * @throws EE_Error
1004
     */
1005
    public function sold_out()
1006
    {
1007
        return $this->reg_limit() > 0 && $this->sold() >= $this->reg_limit();
1008
    }
1009
1010
1011
    /**
1012
     * return the total number of spaces remaining at this venue.
1013
     * This only takes the venue's capacity into account, NOT the tickets available for sale
1014
     *
1015
     * @param bool $consider_tickets Whether to consider tickets remaining when determining if there are any spaces left
1016
     *                               Because if all tickets attached to this datetime have no spaces left,
1017
     *                               then this datetime IS effectively sold out.
1018
     *                               However, there are cases where we just want to know the spaces
1019
     *                               remaining for this particular datetime, hence the flag.
1020
     * @return int
1021
     * @throws ReflectionException
1022
     * @throws InvalidArgumentException
1023
     * @throws InvalidInterfaceException
1024
     * @throws InvalidDataTypeException
1025
     * @throws EE_Error
1026
     */
1027
    public function spaces_remaining($consider_tickets = false)
1028
    {
1029
        // tickets remaining available for purchase
1030
        // no need for special checks for infinite, because if DTT_reg_limit == EE_INF, then EE_INF - x = EE_INF
1031
        $dtt_remaining = $this->reg_limit() - $this->sold_and_reserved();
1032
        if (! $consider_tickets) {
1033
            return $dtt_remaining;
1034
        }
1035
        $tickets_remaining = $this->tickets_remaining();
1036
        return min($dtt_remaining, $tickets_remaining);
1037
    }
1038
1039
1040
    /**
1041
     * Counts the total tickets available
1042
     * (from all the different types of tickets which are available for this datetime).
1043
     *
1044
     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1045
     * @return int
1046
     * @throws ReflectionException
1047
     * @throws InvalidArgumentException
1048
     * @throws InvalidInterfaceException
1049
     * @throws InvalidDataTypeException
1050
     * @throws EE_Error
1051
     */
1052
    public function tickets_remaining($query_params = array())
1053
    {
1054
        $sum = 0;
1055
        $tickets = $this->tickets($query_params);
1056
        if (! empty($tickets)) {
1057
            foreach ($tickets as $ticket) {
1058
                if ($ticket instanceof EE_Ticket) {
1059
                    // get the actual amount of tickets that can be sold
1060
                    $qty = $ticket->qty('saleable');
1061
                    if ($qty === EE_INF) {
1062
                        return EE_INF;
1063
                    }
1064
                    // no negative ticket quantities plz
1065
                    if ($qty > 0) {
1066
                        $sum += $qty;
1067
                    }
1068
                }
1069
            }
1070
        }
1071
        return $sum;
1072
    }
1073
1074
1075
    /**
1076
     * Gets the count of all the tickets available at this datetime (not ticket types)
1077
     * before any were sold
1078
     *
1079
     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1080
     * @return int
1081
     * @throws ReflectionException
1082
     * @throws InvalidArgumentException
1083
     * @throws InvalidInterfaceException
1084
     * @throws InvalidDataTypeException
1085
     * @throws EE_Error
1086
     */
1087
    public function sum_tickets_initially_available($query_params = array())
1088
    {
1089
        return $this->sum_related('Ticket', $query_params, 'TKT_qty');
1090
    }
1091
1092
1093
    /**
1094
     * Returns the lesser-of-the two: spaces remaining at this datetime, or
1095
     * the total tickets remaining (a sum of the tickets remaining for each ticket type
1096
     * that is available for this datetime).
1097
     *
1098
     * @return int
1099
     * @throws ReflectionException
1100
     * @throws InvalidArgumentException
1101
     * @throws InvalidInterfaceException
1102
     * @throws InvalidDataTypeException
1103
     * @throws EE_Error
1104
     */
1105
    public function total_tickets_available_at_this_datetime()
1106
    {
1107
        return $this->spaces_remaining(true);
1108
    }
1109
1110
1111
    /**
1112
     * This simply compares the internal dtt for the given string with NOW
1113
     * and determines if the date is upcoming or not.
1114
     *
1115
     * @access public
1116
     * @return boolean
1117
     * @throws ReflectionException
1118
     * @throws InvalidArgumentException
1119
     * @throws InvalidInterfaceException
1120
     * @throws InvalidDataTypeException
1121
     * @throws EE_Error
1122
     */
1123
    public function is_upcoming()
1124
    {
1125
        return ($this->get_raw('DTT_EVT_start') > time());
1126
    }
1127
1128
1129
    /**
1130
     * This simply compares the internal datetime for the given string with NOW
1131
     * and returns if the date is active (i.e. start and end time)
1132
     *
1133
     * @return boolean
1134
     * @throws ReflectionException
1135
     * @throws InvalidArgumentException
1136
     * @throws InvalidInterfaceException
1137
     * @throws InvalidDataTypeException
1138
     * @throws EE_Error
1139
     */
1140
    public function is_active()
1141
    {
1142
        return ($this->get_raw('DTT_EVT_start') < time() && $this->get_raw('DTT_EVT_end') > time());
1143
    }
1144
1145
1146
    /**
1147
     * This simply compares the internal dtt for the given string with NOW
1148
     * and determines if the date is expired or not.
1149
     *
1150
     * @return boolean
1151
     * @throws ReflectionException
1152
     * @throws InvalidArgumentException
1153
     * @throws InvalidInterfaceException
1154
     * @throws InvalidDataTypeException
1155
     * @throws EE_Error
1156
     */
1157
    public function is_expired()
1158
    {
1159
        return ($this->get_raw('DTT_EVT_end') < time());
1160
    }
1161
1162
1163
    /**
1164
     * This returns the active status for whether an event is active, upcoming, or expired
1165
     *
1166
     * @return int return value will be one of the EE_Datetime status constants.
1167
     * @throws ReflectionException
1168
     * @throws InvalidArgumentException
1169
     * @throws InvalidInterfaceException
1170
     * @throws InvalidDataTypeException
1171
     * @throws EE_Error
1172
     */
1173
    public function get_active_status()
1174
    {
1175
        $total_tickets_for_this_dtt = $this->total_tickets_available_at_this_datetime();
1176
        if ($total_tickets_for_this_dtt !== false && $total_tickets_for_this_dtt < 1) {
1177
            return EE_Datetime::sold_out;
1178
        }
1179
        if ($this->is_expired()) {
1180
            return EE_Datetime::expired;
1181
        }
1182
        if ($this->is_upcoming()) {
1183
            return EE_Datetime::upcoming;
1184
        }
1185
        if ($this->is_active()) {
1186
            return EE_Datetime::active;
1187
        }
1188
        return null;
1189
    }
1190
1191
1192
    /**
1193
     * This returns a nice display name for the datetime that is contingent on the span between the dates and times.
1194
     *
1195
     * @param  boolean $use_dtt_name if TRUE then we'll use DTT->name() if its not empty.
1196
     * @return string
1197
     * @throws ReflectionException
1198
     * @throws InvalidArgumentException
1199
     * @throws InvalidInterfaceException
1200
     * @throws InvalidDataTypeException
1201
     * @throws EE_Error
1202
     */
1203
    public function get_dtt_display_name($use_dtt_name = false)
1204
    {
1205
        if ($use_dtt_name) {
1206
            $dtt_name = $this->name();
1207
            if (! empty($dtt_name)) {
1208
                return $dtt_name;
1209
            }
1210
        }
1211
        // first condition is to see if the months are different
1212
        if (date('m', $this->get_raw('DTT_EVT_start')) !== date('m', $this->get_raw('DTT_EVT_end'))
1213
        ) {
1214
            $display_date = $this->start_date('M j\, Y g:i a') . ' - ' . $this->end_date('M j\, Y g:i a');
1215
            // next condition is if its the same month but different day
1216
        } else {
1217
            if (date('m', $this->get_raw('DTT_EVT_start')) === date('m', $this->get_raw('DTT_EVT_end'))
1218
                && date('d', $this->get_raw('DTT_EVT_start')) !== date('d', $this->get_raw('DTT_EVT_end'))
1219
            ) {
1220
                $display_date = $this->start_date('M j\, g:i a') . ' - ' . $this->end_date('M j\, g:i a Y');
1221
            } else {
1222
                $display_date = $this->start_date('F j\, Y')
1223
                                . ' @ '
1224
                                . $this->start_date('g:i a')
1225
                                . ' - '
1226
                                . $this->end_date('g:i a');
1227
            }
1228
        }
1229
        return $display_date;
1230
    }
1231
1232
1233
    /**
1234
     * Gets all the tickets for this datetime
1235
     *
1236
     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1237
     * @return EE_Base_Class[]|EE_Ticket[]
1238
     * @throws ReflectionException
1239
     * @throws InvalidArgumentException
1240
     * @throws InvalidInterfaceException
1241
     * @throws InvalidDataTypeException
1242
     * @throws EE_Error
1243
     */
1244
    public function tickets($query_params = array())
1245
    {
1246
        return $this->get_many_related('Ticket', $query_params);
1247
    }
1248
1249
1250
    /**
1251
     * Gets all the ticket types currently available for purchase
1252
     *
1253
     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1254
     * @return EE_Ticket[]
1255
     * @throws ReflectionException
1256
     * @throws InvalidArgumentException
1257
     * @throws InvalidInterfaceException
1258
     * @throws InvalidDataTypeException
1259
     * @throws EE_Error
1260
     */
1261
    public function ticket_types_available_for_purchase($query_params = array())
1262
    {
1263
        // first check if datetime is valid
1264
        if ($this->sold_out() || ! ($this->is_upcoming() || $this->is_active())) {
1265
            return array();
1266
        }
1267
        if (empty($query_params)) {
1268
            $query_params = array(
1269
                array(
1270
                    'TKT_start_date' => array('<=', EEM_Ticket::instance()->current_time_for_query('TKT_start_date')),
1271
                    'TKT_end_date'   => array('>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')),
1272
                    'TKT_deleted'    => false,
1273
                ),
1274
            );
1275
        }
1276
        return $this->tickets($query_params);
1277
    }
1278
1279
1280
    /**
1281
     * @return EE_Base_Class|EE_Event
1282
     * @throws ReflectionException
1283
     * @throws InvalidArgumentException
1284
     * @throws InvalidInterfaceException
1285
     * @throws InvalidDataTypeException
1286
     * @throws EE_Error
1287
     */
1288
    public function event()
1289
    {
1290
        return $this->get_first_related('Event');
1291
    }
1292
1293
1294
    /**
1295
     * Updates the DTT_sold attribute (and saves) based on the number of registrations for this datetime
1296
     * (via the tickets).
1297
     *
1298
     * @return int
1299
     * @throws ReflectionException
1300
     * @throws InvalidArgumentException
1301
     * @throws InvalidInterfaceException
1302
     * @throws InvalidDataTypeException
1303
     * @throws EE_Error
1304
     */
1305 View Code Duplication
    public function update_sold()
1306
    {
1307
        $count_regs_for_this_datetime = EEM_Registration::instance()->count(
1308
            array(
1309
                array(
1310
                    'STS_ID'                 => EEM_Registration::status_id_approved,
1311
                    'REG_deleted'            => 0,
1312
                    'Ticket.Datetime.DTT_ID' => $this->ID(),
1313
                ),
1314
            )
1315
        );
1316
        $this->set_sold($count_regs_for_this_datetime);
1317
        $this->save();
1318
        return $count_regs_for_this_datetime;
1319
    }
1320
1321
1322
    /*******************************************************************
1323
     ***********************  DEPRECATED METHODS  **********************
1324
     *******************************************************************/
1325
1326
1327
    /**
1328
     * Increments sold by amount passed by $qty, and persists it immediately to the database.
1329
     *
1330
     * @deprecated $VID:$
1331
     * @param int $qty
1332
     * @return boolean
1333
     * @throws ReflectionException
1334
     * @throws InvalidArgumentException
1335
     * @throws InvalidInterfaceException
1336
     * @throws InvalidDataTypeException
1337
     * @throws EE_Error
1338
     */
1339
    public function increase_sold($qty = 1)
1340
    {
1341
        EE_Error::doing_it_wrong(
1342
            __FUNCTION__,
1343
            esc_html__('Please use EE_Datetime::increaseSold() instead', 'event_espresso'),
1344
            '$VID:$',
1345
            '5.0.0.p'
1346
        );
1347
        return $this->increaseSold($qty);
1348
    }
1349
1350
1351
    /**
1352
     * Decrements (subtracts) sold amount passed by $qty directly in the DB and on the model object. (Ie, no need
1353
     * to save afterwards.)
1354
     *
1355
     * @deprecated $VID:$
1356
     * @param int $qty
1357
     * @return boolean
1358
     * @throws ReflectionException
1359
     * @throws InvalidArgumentException
1360
     * @throws InvalidInterfaceException
1361
     * @throws InvalidDataTypeException
1362
     * @throws EE_Error
1363
     */
1364
    public function decrease_sold($qty = 1)
1365
    {
1366
        EE_Error::doing_it_wrong(
1367
            __FUNCTION__,
1368
            esc_html__('Please use EE_Datetime::decreaseSold() instead', 'event_espresso'),
1369
            '$VID:$',
1370
            '5.0.0.p'
1371
        );
1372
        return $this->decreaseSold($qty);
1373
    }
1374
1375
1376
    /**
1377
     * Increments reserved by amount passed by $qty, and persists it immediately to the database.
1378
     *
1379
     * @deprecated $VID:$
1380
     * @param int $qty
1381
     * @return boolean indicating success
1382
     * @throws ReflectionException
1383
     * @throws InvalidArgumentException
1384
     * @throws InvalidInterfaceException
1385
     * @throws InvalidDataTypeException
1386
     * @throws EE_Error
1387
     */
1388
    public function increase_reserved($qty = 1)
1389
    {
1390
        EE_Error::doing_it_wrong(
1391
            __FUNCTION__,
1392
            esc_html__('Please use EE_Datetime::increaseReserved() instead', 'event_espresso'),
1393
            '$VID:$',
1394
            '5.0.0.p'
1395
        );
1396
        return $this->increaseReserved($qty);
1397
    }
1398
1399
1400
    /**
1401
     * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
1402
     *
1403
     * @deprecated $VID:$
1404
     * @param int $qty
1405
     * @return boolean
1406
     * @throws ReflectionException
1407
     * @throws InvalidArgumentException
1408
     * @throws InvalidInterfaceException
1409
     * @throws InvalidDataTypeException
1410
     * @throws EE_Error
1411
     */
1412
    public function decrease_reserved($qty = 1)
1413
    {
1414
        EE_Error::doing_it_wrong(
1415
            __FUNCTION__,
1416
            esc_html__('Please use EE_Datetime::decreaseReserved() instead', 'event_espresso'),
1417
            '$VID:$',
1418
            '5.0.0.p'
1419
        );
1420
        return $this->decreaseReserved($qty);
1421
    }
1422
}
1423