Completed
Branch FET/conditional-update-queries (67a610)
by
unknown
25:02 queued 16:45
created

EE_Datetime::decreaseSold()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17

Duplication

Lines 17
Ratio 100 %

Importance

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