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