Completed
Pull Request — master (#1046)
by Darren
10:25
created
core/db_models/EEM_Datetime.model.php 2 patches
Indentation   +743 added lines, -743 removed lines patch added patch discarded remove patch
@@ -13,747 +13,747 @@
 block discarded – undo
13 13
 class EEM_Datetime extends EEM_Soft_Delete_Base
14 14
 {
15 15
 
16
-    /**
17
-     * @var EEM_Datetime $_instance
18
-     */
19
-    protected static $_instance;
20
-
21
-
22
-    /**
23
-     * private constructor to prevent direct creation
24
-     *
25
-     * @param string $timezone A string representing the timezone we want to set for returned Date Time Strings
26
-     *                         (and any incoming timezone data that gets saved).
27
-     *                         Note this just sends the timezone info to the date time model field objects.
28
-     *                         Default is NULL
29
-     *                         (and will be assumed using the set timezone in the 'timezone_string' wp option)
30
-     * @throws EE_Error
31
-     * @throws InvalidArgumentException
32
-     * @throws InvalidArgumentException
33
-     */
34
-    protected function __construct($timezone)
35
-    {
36
-        $this->singular_item           = esc_html__('Datetime', 'event_espresso');
37
-        $this->plural_item             = esc_html__('Datetimes', 'event_espresso');
38
-        $this->_tables                 = array(
39
-            'Datetime' => new EE_Primary_Table('esp_datetime', 'DTT_ID'),
40
-        );
41
-        $this->_fields                 = array(
42
-            'Datetime' => array(
43
-                'DTT_ID'          => new EE_Primary_Key_Int_Field(
44
-                    'DTT_ID',
45
-                    esc_html__('Datetime ID', 'event_espresso')
46
-                ),
47
-                'EVT_ID'          => new EE_Foreign_Key_Int_Field(
48
-                    'EVT_ID',
49
-                    esc_html__('Event ID', 'event_espresso'),
50
-                    false,
51
-                    0,
52
-                    'Event'
53
-                ),
54
-                'DTT_name'        => new EE_Plain_Text_Field(
55
-                    'DTT_name',
56
-                    esc_html__('Datetime Name', 'event_espresso'),
57
-                    false,
58
-                    ''
59
-                ),
60
-                'DTT_description' => new EE_Post_Content_Field(
61
-                    'DTT_description',
62
-                    esc_html__('Description for Datetime', 'event_espresso'),
63
-                    false,
64
-                    ''
65
-                ),
66
-                'DTT_EVT_start'   => new EE_Datetime_Field(
67
-                    'DTT_EVT_start',
68
-                    esc_html__('Start time/date of Event', 'event_espresso'),
69
-                    false,
70
-                    EE_Datetime_Field::now,
71
-                    $timezone
72
-                ),
73
-                'DTT_EVT_end'     => new EE_Datetime_Field(
74
-                    'DTT_EVT_end',
75
-                    esc_html__('End time/date of Event', 'event_espresso'),
76
-                    false,
77
-                    EE_Datetime_Field::now,
78
-                    $timezone
79
-                ),
80
-                'DTT_reg_limit'   => new EE_Infinite_Integer_Field(
81
-                    'DTT_reg_limit',
82
-                    esc_html__('Registration Limit for this time', 'event_espresso'),
83
-                    true,
84
-                    EE_INF
85
-                ),
86
-                'DTT_sold'        => new EE_Integer_Field(
87
-                    'DTT_sold',
88
-                    esc_html__('How many sales for this Datetime that have occurred', 'event_espresso'),
89
-                    true,
90
-                    0
91
-                ),
92
-                'DTT_reserved'    => new EE_Integer_Field(
93
-                    'DTT_reserved',
94
-                    esc_html__('Quantity of tickets reserved, but not yet fully purchased', 'event_espresso'),
95
-                    false,
96
-                    0
97
-                ),
98
-                'DTT_is_primary'  => new EE_Boolean_Field(
99
-                    'DTT_is_primary',
100
-                    esc_html__('Flag indicating datetime is primary one for event', 'event_espresso'),
101
-                    false,
102
-                    false
103
-                ),
104
-                'DTT_order'       => new EE_Integer_Field(
105
-                    'DTT_order',
106
-                    esc_html__('The order in which the Datetime is displayed', 'event_espresso'),
107
-                    false,
108
-                    0
109
-                ),
110
-                'DTT_parent'      => new EE_Integer_Field(
111
-                    'DTT_parent',
112
-                    esc_html__('Indicates what DTT_ID is the parent of this DTT_ID', 'event_espresso'),
113
-                    true,
114
-                    0
115
-                ),
116
-                'DTT_deleted'     => new EE_Trashed_Flag_Field(
117
-                    'DTT_deleted',
118
-                    esc_html__('Flag indicating datetime is archived', 'event_espresso'),
119
-                    false,
120
-                    false
121
-                ),
122
-            ),
123
-        );
124
-        $this->_model_relations        = array(
125
-            'Ticket'  => new EE_HABTM_Relation('Datetime_Ticket'),
126
-            'Event'   => new EE_Belongs_To_Relation(),
127
-            'Checkin' => new EE_Has_Many_Relation(),
128
-            'Datetime_Ticket' => new EE_Has_Many_Relation(),
129
-        );
130
-        $path_to_event_model = 'Event';
131
-        $this->model_chain_to_password = $path_to_event_model;
132
-        $this->_model_chain_to_wp_user = $path_to_event_model;
133
-        // this model is generally available for reading
134
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ]       = new EE_Restriction_Generator_Event_Related_Public(
135
-            $path_to_event_model
136
-        );
137
-        $this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = new EE_Restriction_Generator_Event_Related_Protected(
138
-            $path_to_event_model
139
-        );
140
-        $this->_cap_restriction_generators[ EEM_Base::caps_edit ]       = new EE_Restriction_Generator_Event_Related_Protected(
141
-            $path_to_event_model
142
-        );
143
-        $this->_cap_restriction_generators[ EEM_Base::caps_delete ]     = new EE_Restriction_Generator_Event_Related_Protected(
144
-            $path_to_event_model,
145
-            EEM_Base::caps_edit
146
-        );
147
-        parent::__construct($timezone);
148
-    }
149
-
150
-
151
-    /**
152
-     * create new blank datetime
153
-     *
154
-     * @access public
155
-     * @return EE_Datetime[] array on success, FALSE on fail
156
-     * @throws EE_Error
157
-     * @throws InvalidArgumentException
158
-     * @throws InvalidDataTypeException
159
-     * @throws ReflectionException
160
-     * @throws InvalidInterfaceException
161
-     */
162
-    public function create_new_blank_datetime()
163
-    {
164
-        // makes sure timezone is always set.
165
-        $timezone_string = $this->get_timezone();
166
-        /**
167
-         * Filters the initial start date for the new datetime.
168
-         * Any time included in this value will be overridden later so use additional filters to modify the time.
169
-         *
170
-         * @param int $start_date Unixtimestamp representing now + 30 days in seconds.
171
-         * @return int unixtimestamp
172
-         */
173
-        $start_date = apply_filters(
174
-            'FHEE__EEM_Datetime__create_new_blank_datetime__start_date',
175
-            $this->current_time_for_query('DTT_EVT_start', true) + MONTH_IN_SECONDS
176
-        );
177
-        /**
178
-         * Filters the initial end date for the new datetime.
179
-         * Any time included in this value will be overridden later so use additional filters to modify the time.
180
-         *
181
-         * @param int $end_data Unixtimestamp representing now + 30 days in seconds.
182
-         * @return int unixtimestamp
183
-         */
184
-        $end_date = apply_filters(
185
-            'FHEE__EEM_Datetime__create_new_blank_datetime__end_date',
186
-            $this->current_time_for_query('DTT_EVT_end', true) + MONTH_IN_SECONDS
187
-        );
188
-        $blank_datetime = EE_Datetime::new_instance(
189
-            array(
190
-                'DTT_EVT_start' => $start_date,
191
-                'DTT_EVT_end'   => $end_date,
192
-                'DTT_order'     => 1,
193
-                'DTT_reg_limit' => EE_INF,
194
-            ),
195
-            $timezone_string
196
-        );
197
-        /**
198
-         * Filters the initial start time and format for the new EE_Datetime instance.
199
-         *
200
-         * @param array $start_time An array having size 2.  First element is the time, second element is the time
201
-         *                          format.
202
-         * @return array
203
-         */
204
-        $start_time = apply_filters(
205
-            'FHEE__EEM_Datetime__create_new_blank_datetime__start_time',
206
-            ['8am', 'ga']
207
-        );
208
-        /**
209
-         * Filters the initial end time and format for the new EE_Datetime instance.
210
-         *
211
-         * @param array $end_time An array having size 2.  First element is the time, second element is the time
212
-         *                        format
213
-         * @return array
214
-         */
215
-        $end_time = apply_filters(
216
-            'FHEE__EEM_Datetime__create_new_blank_datetime__end_time',
217
-            ['5pm', 'ga']
218
-        );
219
-        $this->validateStartAndEndTimeForBlankDate($start_time, $end_time);
220
-        $blank_datetime->set_start_time(
221
-            $this->convert_datetime_for_query(
222
-                'DTT_EVT_start',
223
-                $start_time[0],
224
-                $start_time[1],
225
-                $timezone_string
226
-            )
227
-        );
228
-        $blank_datetime->set_end_time(
229
-            $this->convert_datetime_for_query(
230
-                'DTT_EVT_end',
231
-                $end_time[0],
232
-                $end_time[1],
233
-                $timezone_string
234
-            )
235
-        );
236
-        return array($blank_datetime);
237
-    }
238
-
239
-
240
-    /**
241
-     * Validates whether the start_time and end_time are in the expected format.
242
-     * @param array $start_time
243
-     * @param array $end_time
244
-     * @throws InvalidArgumentException
245
-     * @throws InvalidDataTypeException
246
-     */
247
-    private function validateStartAndEndTimeForBlankDate($start_time, $end_time)
248
-    {
249
-        if (! is_array($start_time)) {
250
-            throw new InvalidDataTypeException('start_time', $start_time, 'array');
251
-        }
252
-        if (! is_array($end_time)) {
253
-            throw new InvalidDataTypeException('end_time', $end_time, 'array');
254
-        }
255
-        if (count($start_time) !== 2) {
256
-            throw new InvalidArgumentException(
257
-                sprintf(
258
-                    'The variable %1$s is expected to be an array with two elements.  The first item in the '
259
-                    . 'array should be a valid time string, the second item in the array should be a valid time format',
260
-                    '$start_time'
261
-                )
262
-            );
263
-        }
264
-        if (count($end_time) !== 2) {
265
-            throw new InvalidArgumentException(
266
-                sprintf(
267
-                    'The variable %1$s is expected to be an array with two elements.  The first item in the '
268
-                    . 'array should be a valid time string, the second item in the array should be a valid time format',
269
-                    '$end_time'
270
-                )
271
-            );
272
-        }
273
-    }
274
-
275
-
276
-    /**
277
-     * get event start date from db
278
-     *
279
-     * @access public
280
-     * @param  int $EVT_ID
281
-     * @return EE_Datetime[] array on success, FALSE on fail
282
-     * @throws EE_Error
283
-     */
284
-    public function get_all_event_dates($EVT_ID = 0)
285
-    {
286
-        if (! $EVT_ID) { // on add_new_event event_id gets set to 0
287
-            return $this->create_new_blank_datetime();
288
-        }
289
-        $results = $this->get_datetimes_for_event_ordered_by_DTT_order($EVT_ID);
290
-        if (empty($results)) {
291
-            return $this->create_new_blank_datetime();
292
-        }
293
-        return $results;
294
-    }
295
-
296
-
297
-    /**
298
-     * get all datetimes attached to an event ordered by the DTT_order field
299
-     *
300
-     * @public
301
-     * @param  int    $EVT_ID     event id
302
-     * @param boolean $include_expired
303
-     * @param boolean $include_deleted
304
-     * @param  int    $limit      If included then limit the count of results by
305
-     *                            the given number
306
-     * @return EE_Datetime[]
307
-     * @throws EE_Error
308
-     */
309
-    public function get_datetimes_for_event_ordered_by_DTT_order(
310
-        $EVT_ID,
311
-        $include_expired = true,
312
-        $include_deleted = true,
313
-        $limit = null
314
-    ) {
315
-        // sanitize EVT_ID
316
-        $EVT_ID         = absint($EVT_ID);
317
-        $old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object();
318
-        $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
319
-        $where_params = array('Event.EVT_ID' => $EVT_ID);
320
-        $query_params = ! empty($limit)
321
-            ? array(
322
-                $where_params,
323
-                'limit'                    => $limit,
324
-                'order_by'                 => array('DTT_order' => 'ASC'),
325
-                'default_where_conditions' => 'none',
326
-            )
327
-            : array(
328
-                $where_params,
329
-                'order_by'                 => array('DTT_order' => 'ASC'),
330
-                'default_where_conditions' => 'none',
331
-            );
332
-        if (! $include_expired) {
333
-            $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
334
-        }
335
-        if ($include_deleted) {
336
-            $query_params[0]['DTT_deleted'] = array('IN', array(true, false));
337
-        }
338
-        /** @var EE_Datetime[] $result */
339
-        $result = $this->get_all($query_params);
340
-        $this->assume_values_already_prepared_by_model_object($old_assumption);
341
-        return $result;
342
-    }
343
-
344
-
345
-    /**
346
-     * Gets the datetimes for the event (with the given limit), and orders them by "importance".
347
-     * By importance, we mean that the primary datetimes are most important (DEPRECATED FOR NOW),
348
-     * and then the earlier datetimes are the most important.
349
-     * Maybe we'll want this to take into account datetimes that haven't already passed, but we don't yet.
350
-     *
351
-     * @param int $EVT_ID
352
-     * @param int $limit
353
-     * @return EE_Datetime[]|EE_Base_Class[]
354
-     * @throws EE_Error
355
-     */
356
-    public function get_datetimes_for_event_ordered_by_importance($EVT_ID = 0, $limit = null)
357
-    {
358
-        return $this->get_all(
359
-            array(
360
-                array('Event.EVT_ID' => $EVT_ID),
361
-                'limit'                    => $limit,
362
-                'order_by'                 => array('DTT_EVT_start' => 'ASC'),
363
-                'default_where_conditions' => 'none',
364
-            )
365
-        );
366
-    }
367
-
368
-
369
-    /**
370
-     * @param int     $EVT_ID
371
-     * @param boolean $include_expired
372
-     * @param boolean $include_deleted
373
-     * @return EE_Datetime
374
-     * @throws EE_Error
375
-     */
376
-    public function get_oldest_datetime_for_event($EVT_ID, $include_expired = false, $include_deleted = false)
377
-    {
378
-        $results = $this->get_datetimes_for_event_ordered_by_start_time(
379
-            $EVT_ID,
380
-            $include_expired,
381
-            $include_deleted,
382
-            1
383
-        );
384
-        if ($results) {
385
-            return array_shift($results);
386
-        }
387
-        return null;
388
-    }
389
-
390
-
391
-    /**
392
-     * Gets the 'primary' datetime for an event.
393
-     *
394
-     * @param int  $EVT_ID
395
-     * @param bool $try_to_exclude_expired
396
-     * @param bool $try_to_exclude_deleted
397
-     * @return \EE_Datetime
398
-     * @throws EE_Error
399
-     */
400
-    public function get_primary_datetime_for_event(
401
-        $EVT_ID,
402
-        $try_to_exclude_expired = true,
403
-        $try_to_exclude_deleted = true
404
-    ) {
405
-        if ($try_to_exclude_expired) {
406
-            $non_expired = $this->get_oldest_datetime_for_event($EVT_ID, false, false);
407
-            if ($non_expired) {
408
-                return $non_expired;
409
-            }
410
-        }
411
-        if ($try_to_exclude_deleted) {
412
-            $expired_even = $this->get_oldest_datetime_for_event($EVT_ID, true);
413
-            if ($expired_even) {
414
-                return $expired_even;
415
-            }
416
-        }
417
-        return $this->get_oldest_datetime_for_event($EVT_ID, true, true);
418
-    }
419
-
420
-
421
-    /**
422
-     * Gets ALL the datetimes for an event (including trashed ones, for now), ordered
423
-     * only by start date
424
-     *
425
-     * @param int     $EVT_ID
426
-     * @param boolean $include_expired
427
-     * @param boolean $include_deleted
428
-     * @param int     $limit
429
-     * @return EE_Datetime[]
430
-     * @throws EE_Error
431
-     */
432
-    public function get_datetimes_for_event_ordered_by_start_time(
433
-        $EVT_ID,
434
-        $include_expired = true,
435
-        $include_deleted = true,
436
-        $limit = null
437
-    ) {
438
-        // sanitize EVT_ID
439
-        $EVT_ID         = absint($EVT_ID);
440
-        $old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object();
441
-        $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
442
-        $query_params = array(array('Event.EVT_ID' => $EVT_ID), 'order_by' => array('DTT_EVT_start' => 'asc'));
443
-        if (! $include_expired) {
444
-            $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
445
-        }
446
-        if ($include_deleted) {
447
-            $query_params[0]['DTT_deleted'] = array('IN', array(true, false));
448
-        }
449
-        if ($limit) {
450
-            $query_params['limit'] = $limit;
451
-        }
452
-        /** @var EE_Datetime[] $result */
453
-        $result = $this->get_all($query_params);
454
-        $this->assume_values_already_prepared_by_model_object($old_assumption);
455
-        return $result;
456
-    }
457
-
458
-
459
-    /**
460
-     * Gets ALL the datetimes for an ticket (including trashed ones, for now), ordered
461
-     * only by start date
462
-     *
463
-     * @param int     $TKT_ID
464
-     * @param boolean $include_expired
465
-     * @param boolean $include_deleted
466
-     * @param int     $limit
467
-     * @return EE_Datetime[]
468
-     * @throws EE_Error
469
-     */
470
-    public function get_datetimes_for_ticket_ordered_by_start_time(
471
-        $TKT_ID,
472
-        $include_expired = true,
473
-        $include_deleted = true,
474
-        $limit = null
475
-    ) {
476
-        // sanitize TKT_ID
477
-        $TKT_ID         = absint($TKT_ID);
478
-        $old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object();
479
-        $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
480
-        $query_params = array(array('Ticket.TKT_ID' => $TKT_ID), 'order_by' => array('DTT_EVT_start' => 'asc'));
481
-        if (! $include_expired) {
482
-            $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
483
-        }
484
-        if ($include_deleted) {
485
-            $query_params[0]['DTT_deleted'] = array('IN', array(true, false));
486
-        }
487
-        if ($limit) {
488
-            $query_params['limit'] = $limit;
489
-        }
490
-        /** @var EE_Datetime[] $result */
491
-        $result = $this->get_all($query_params);
492
-        $this->assume_values_already_prepared_by_model_object($old_assumption);
493
-        return $result;
494
-    }
495
-
496
-
497
-    /**
498
-     * Gets all the datetimes for a ticket (including trashed ones, for now), ordered by the DTT_order for the
499
-     * datetimes.
500
-     *
501
-     * @param  int      $TKT_ID          ID of ticket to retrieve the datetimes for
502
-     * @param  boolean  $include_expired whether to include expired datetimes or not
503
-     * @param  boolean  $include_deleted whether to include trashed datetimes or not.
504
-     * @param  int|null $limit           if null, no limit, if int then limit results by
505
-     *                                   that number
506
-     * @return EE_Datetime[]
507
-     * @throws EE_Error
508
-     */
509
-    public function get_datetimes_for_ticket_ordered_by_DTT_order(
510
-        $TKT_ID,
511
-        $include_expired = true,
512
-        $include_deleted = true,
513
-        $limit = null
514
-    ) {
515
-        // sanitize id.
516
-        $TKT_ID         = absint($TKT_ID);
517
-        $old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object();
518
-        $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
519
-        $where_params = array('Ticket.TKT_ID' => $TKT_ID);
520
-        $query_params = array($where_params, 'order_by' => array('DTT_order' => 'ASC'));
521
-        if (! $include_expired) {
522
-            $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
523
-        }
524
-        if ($include_deleted) {
525
-            $query_params[0]['DTT_deleted'] = array('IN', array(true, false));
526
-        }
527
-        if ($limit) {
528
-            $query_params['limit'] = $limit;
529
-        }
530
-        /** @var EE_Datetime[] $result */
531
-        $result = $this->get_all($query_params);
532
-        $this->assume_values_already_prepared_by_model_object($old_assumption);
533
-        return $result;
534
-    }
535
-
536
-
537
-    /**
538
-     * Gets the most important datetime for a particular event (ie, the primary event usually. But if for some WACK
539
-     * reason it doesn't exist, we consider the earliest event the most important)
540
-     *
541
-     * @param int $EVT_ID
542
-     * @return EE_Datetime
543
-     * @throws EE_Error
544
-     */
545
-    public function get_most_important_datetime_for_event($EVT_ID)
546
-    {
547
-        $results = $this->get_datetimes_for_event_ordered_by_importance($EVT_ID, 1);
548
-        if ($results) {
549
-            return array_shift($results);
550
-        }
551
-        return null;
552
-    }
553
-
554
-
555
-    /**
556
-     * This returns a wpdb->results        Array of all DTT month and years matching the incoming query params and
557
-     * grouped by month and year.
558
-     *
559
-     * @param  array  $where_params      @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions
560
-     * @param  string $evt_active_status A string representing the evt active status to filter the months by.
561
-     *                                   Can be:
562
-     *                                   - '' = no filter
563
-     *                                   - upcoming = Published events with at least one upcoming datetime.
564
-     *                                   - expired = Events with all datetimes expired.
565
-     *                                   - active = Events that are published and have at least one datetime that
566
-     *                                   starts before now and ends after now.
567
-     *                                   - inactive = Events that are either not published.
568
-     * @return EE_Base_Class[]
569
-     * @throws EE_Error
570
-     * @throws InvalidArgumentException
571
-     * @throws InvalidArgumentException
572
-     */
573
-    public function get_dtt_months_and_years($where_params, $evt_active_status = '')
574
-    {
575
-        $current_time_for_DTT_EVT_start = $this->current_time_for_query('DTT_EVT_start');
576
-        $current_time_for_DTT_EVT_end   = $this->current_time_for_query('DTT_EVT_end');
577
-        switch ($evt_active_status) {
578
-            case 'upcoming':
579
-                $where_params['Event.status'] = 'publish';
580
-                // if there are already query_params matching DTT_EVT_start then we need to modify that to add them.
581
-                if (isset($where_params['DTT_EVT_start'])) {
582
-                    $where_params['DTT_EVT_start*****'] = $where_params['DTT_EVT_start'];
583
-                }
584
-                $where_params['DTT_EVT_start'] = array('>', $current_time_for_DTT_EVT_start);
585
-                break;
586
-            case 'expired':
587
-                if (isset($where_params['Event.status'])) {
588
-                    unset($where_params['Event.status']);
589
-                }
590
-                // get events to exclude
591
-                $exclude_query[0] = array_merge(
592
-                    $where_params,
593
-                    array('DTT_EVT_end' => array('>', $current_time_for_DTT_EVT_end))
594
-                );
595
-                // first get all events that have datetimes where its not expired.
596
-                $event_ids = $this->_get_all_wpdb_results(
597
-                    $exclude_query,
598
-                    OBJECT_K,
599
-                    'Datetime.EVT_ID'
600
-                );
601
-                $event_ids = array_keys($event_ids);
602
-                if (isset($where_params['DTT_EVT_end'])) {
603
-                    $where_params['DTT_EVT_end****'] = $where_params['DTT_EVT_end'];
604
-                }
605
-                $where_params['DTT_EVT_end']  = array('<', $current_time_for_DTT_EVT_end);
606
-                $where_params['Event.EVT_ID'] = array('NOT IN', $event_ids);
607
-                break;
608
-            case 'active':
609
-                $where_params['Event.status'] = 'publish';
610
-                if (isset($where_params['DTT_EVT_start'])) {
611
-                    $where_params['Datetime.DTT_EVT_start******'] = $where_params['DTT_EVT_start'];
612
-                }
613
-                if (isset($where_params['Datetime.DTT_EVT_end'])) {
614
-                    $where_params['Datetime.DTT_EVT_end*****'] = $where_params['DTT_EVT_end'];
615
-                }
616
-                $where_params['DTT_EVT_start'] = array('<', $current_time_for_DTT_EVT_start);
617
-                $where_params['DTT_EVT_end']   = array('>', $current_time_for_DTT_EVT_end);
618
-                break;
619
-            case 'inactive':
620
-                if (isset($where_params['Event.status'])) {
621
-                    unset($where_params['Event.status']);
622
-                }
623
-                if (isset($where_params['OR'])) {
624
-                    $where_params['AND']['OR'] = $where_params['OR'];
625
-                }
626
-                if (isset($where_params['DTT_EVT_end'])) {
627
-                    $where_params['AND']['DTT_EVT_end****'] = $where_params['DTT_EVT_end'];
628
-                    unset($where_params['DTT_EVT_end']);
629
-                }
630
-                if (isset($where_params['DTT_EVT_start'])) {
631
-                    $where_params['AND']['DTT_EVT_start'] = $where_params['DTT_EVT_start'];
632
-                    unset($where_params['DTT_EVT_start']);
633
-                }
634
-                $where_params['AND']['Event.status'] = array('!=', 'publish');
635
-                break;
636
-        }
637
-        $query_params[0]          = $where_params;
638
-        $query_params['group_by'] = array('dtt_year', 'dtt_month');
639
-        $query_params['order_by'] = array('DTT_EVT_start' => 'DESC');
640
-        $query_interval           = EEH_DTT_Helper::get_sql_query_interval_for_offset(
641
-            $this->get_timezone(),
642
-            'DTT_EVT_start'
643
-        );
644
-        $columns_to_select        = array(
645
-            'dtt_year'      => array('YEAR(' . $query_interval . ')', '%s'),
646
-            'dtt_month'     => array('MONTHNAME(' . $query_interval . ')', '%s'),
647
-            'dtt_month_num' => array('MONTH(' . $query_interval . ')', '%s'),
648
-        );
649
-        return $this->_get_all_wpdb_results($query_params, OBJECT, $columns_to_select);
650
-    }
651
-
652
-
653
-    /**
654
-     * Updates the DTT_sold attribute on each datetime (based on the registrations
655
-     * for the tickets for each datetime)
656
-     *
657
-     * @param EE_Base_Class[]|EE_Datetime[] $datetimes
658
-     * @throws EE_Error
659
-     */
660
-    public function update_sold($datetimes)
661
-    {
662
-        EE_Error::doing_it_wrong(
663
-            __FUNCTION__,
664
-            esc_html__(
665
-                'Please use \EEM_Ticket::update_tickets_sold() instead which will in turn correctly update both the Ticket AND Datetime counts.',
666
-                'event_espresso'
667
-            ),
668
-            '4.9.32.rc.005'
669
-        );
670
-        foreach ($datetimes as $datetime) {
671
-            $datetime->update_sold();
672
-        }
673
-    }
674
-
675
-
676
-    /**
677
-     *    Gets the total number of tickets available at a particular datetime
678
-     *    (does NOT take into account the datetime's spaces available)
679
-     *
680
-     * @param int   $DTT_ID
681
-     * @param array $query_params
682
-     * @return int of tickets available. If sold out, return less than 1. If infinite, returns EE_INF,  IF there are NO
683
-     *             tickets attached to datetime then FALSE is returned.
684
-     */
685
-    public function sum_tickets_currently_available_at_datetime($DTT_ID, array $query_params = array())
686
-    {
687
-        $datetime = $this->get_one_by_ID($DTT_ID);
688
-        if ($datetime instanceof EE_Datetime) {
689
-            return $datetime->tickets_remaining($query_params);
690
-        }
691
-        return 0;
692
-    }
693
-
694
-
695
-    /**
696
-     * This returns an array of counts of datetimes in the database for each Datetime status that can be queried.
697
-     *
698
-     * @param  array $stati_to_include If included you can restrict the statuses we return counts for by including the
699
-     *                                 stati you want counts for as values in the array.  An empty array returns counts
700
-     *                                 for all valid stati.
701
-     * @param  array $query_params     If included can be used to refine the conditions for returning the count (i.e.
702
-     *                                 only for Datetimes connected to a specific event, or specific ticket.
703
-     * @return array  The value returned is an array indexed by Datetime Status and the values are the counts.  The
704
-     * @throws EE_Error
705
-     *                                 stati used as index keys are: EE_Datetime::active EE_Datetime::upcoming
706
-     *                                 EE_Datetime::expired
707
-     */
708
-    public function get_datetime_counts_by_status(array $stati_to_include = array(), array $query_params = array())
709
-    {
710
-        // only accept where conditions for this query.
711
-        $_where            = isset($query_params[0]) ? $query_params[0] : array();
712
-        $status_query_args = array(
713
-            EE_Datetime::active   => array_merge(
714
-                $_where,
715
-                array('DTT_EVT_start' => array('<', time()), 'DTT_EVT_end' => array('>', time()))
716
-            ),
717
-            EE_Datetime::upcoming => array_merge(
718
-                $_where,
719
-                array('DTT_EVT_start' => array('>', time()))
720
-            ),
721
-            EE_Datetime::expired  => array_merge(
722
-                $_where,
723
-                array('DTT_EVT_end' => array('<', time()))
724
-            ),
725
-        );
726
-        if (! empty($stati_to_include)) {
727
-            foreach (array_keys($status_query_args) as $status) {
728
-                if (! in_array($status, $stati_to_include, true)) {
729
-                    unset($status_query_args[ $status ]);
730
-                }
731
-            }
732
-        }
733
-        // loop through and query counts for each stati.
734
-        $status_query_results = array();
735
-        foreach ($status_query_args as $status => $status_where_conditions) {
736
-            $status_query_results[ $status ] = EEM_Datetime::count(
737
-                array($status_where_conditions),
738
-                'DTT_ID',
739
-                true
740
-            );
741
-        }
742
-        return $status_query_results;
743
-    }
744
-
745
-
746
-    /**
747
-     * Returns the specific count for a given Datetime status matching any given query_params.
748
-     *
749
-     * @param string $status Valid string representation for Datetime status requested. (Defaults to Active).
750
-     * @param array  $query_params
751
-     * @return int
752
-     * @throws EE_Error
753
-     */
754
-    public function get_datetime_count_for_status($status = EE_Datetime::active, array $query_params = array())
755
-    {
756
-        $count = $this->get_datetime_counts_by_status(array($status), $query_params);
757
-        return ! empty($count[ $status ]) ? $count[ $status ] : 0;
758
-    }
16
+	/**
17
+	 * @var EEM_Datetime $_instance
18
+	 */
19
+	protected static $_instance;
20
+
21
+
22
+	/**
23
+	 * private constructor to prevent direct creation
24
+	 *
25
+	 * @param string $timezone A string representing the timezone we want to set for returned Date Time Strings
26
+	 *                         (and any incoming timezone data that gets saved).
27
+	 *                         Note this just sends the timezone info to the date time model field objects.
28
+	 *                         Default is NULL
29
+	 *                         (and will be assumed using the set timezone in the 'timezone_string' wp option)
30
+	 * @throws EE_Error
31
+	 * @throws InvalidArgumentException
32
+	 * @throws InvalidArgumentException
33
+	 */
34
+	protected function __construct($timezone)
35
+	{
36
+		$this->singular_item           = esc_html__('Datetime', 'event_espresso');
37
+		$this->plural_item             = esc_html__('Datetimes', 'event_espresso');
38
+		$this->_tables                 = array(
39
+			'Datetime' => new EE_Primary_Table('esp_datetime', 'DTT_ID'),
40
+		);
41
+		$this->_fields                 = array(
42
+			'Datetime' => array(
43
+				'DTT_ID'          => new EE_Primary_Key_Int_Field(
44
+					'DTT_ID',
45
+					esc_html__('Datetime ID', 'event_espresso')
46
+				),
47
+				'EVT_ID'          => new EE_Foreign_Key_Int_Field(
48
+					'EVT_ID',
49
+					esc_html__('Event ID', 'event_espresso'),
50
+					false,
51
+					0,
52
+					'Event'
53
+				),
54
+				'DTT_name'        => new EE_Plain_Text_Field(
55
+					'DTT_name',
56
+					esc_html__('Datetime Name', 'event_espresso'),
57
+					false,
58
+					''
59
+				),
60
+				'DTT_description' => new EE_Post_Content_Field(
61
+					'DTT_description',
62
+					esc_html__('Description for Datetime', 'event_espresso'),
63
+					false,
64
+					''
65
+				),
66
+				'DTT_EVT_start'   => new EE_Datetime_Field(
67
+					'DTT_EVT_start',
68
+					esc_html__('Start time/date of Event', 'event_espresso'),
69
+					false,
70
+					EE_Datetime_Field::now,
71
+					$timezone
72
+				),
73
+				'DTT_EVT_end'     => new EE_Datetime_Field(
74
+					'DTT_EVT_end',
75
+					esc_html__('End time/date of Event', 'event_espresso'),
76
+					false,
77
+					EE_Datetime_Field::now,
78
+					$timezone
79
+				),
80
+				'DTT_reg_limit'   => new EE_Infinite_Integer_Field(
81
+					'DTT_reg_limit',
82
+					esc_html__('Registration Limit for this time', 'event_espresso'),
83
+					true,
84
+					EE_INF
85
+				),
86
+				'DTT_sold'        => new EE_Integer_Field(
87
+					'DTT_sold',
88
+					esc_html__('How many sales for this Datetime that have occurred', 'event_espresso'),
89
+					true,
90
+					0
91
+				),
92
+				'DTT_reserved'    => new EE_Integer_Field(
93
+					'DTT_reserved',
94
+					esc_html__('Quantity of tickets reserved, but not yet fully purchased', 'event_espresso'),
95
+					false,
96
+					0
97
+				),
98
+				'DTT_is_primary'  => new EE_Boolean_Field(
99
+					'DTT_is_primary',
100
+					esc_html__('Flag indicating datetime is primary one for event', 'event_espresso'),
101
+					false,
102
+					false
103
+				),
104
+				'DTT_order'       => new EE_Integer_Field(
105
+					'DTT_order',
106
+					esc_html__('The order in which the Datetime is displayed', 'event_espresso'),
107
+					false,
108
+					0
109
+				),
110
+				'DTT_parent'      => new EE_Integer_Field(
111
+					'DTT_parent',
112
+					esc_html__('Indicates what DTT_ID is the parent of this DTT_ID', 'event_espresso'),
113
+					true,
114
+					0
115
+				),
116
+				'DTT_deleted'     => new EE_Trashed_Flag_Field(
117
+					'DTT_deleted',
118
+					esc_html__('Flag indicating datetime is archived', 'event_espresso'),
119
+					false,
120
+					false
121
+				),
122
+			),
123
+		);
124
+		$this->_model_relations        = array(
125
+			'Ticket'  => new EE_HABTM_Relation('Datetime_Ticket'),
126
+			'Event'   => new EE_Belongs_To_Relation(),
127
+			'Checkin' => new EE_Has_Many_Relation(),
128
+			'Datetime_Ticket' => new EE_Has_Many_Relation(),
129
+		);
130
+		$path_to_event_model = 'Event';
131
+		$this->model_chain_to_password = $path_to_event_model;
132
+		$this->_model_chain_to_wp_user = $path_to_event_model;
133
+		// this model is generally available for reading
134
+		$this->_cap_restriction_generators[ EEM_Base::caps_read ]       = new EE_Restriction_Generator_Event_Related_Public(
135
+			$path_to_event_model
136
+		);
137
+		$this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = new EE_Restriction_Generator_Event_Related_Protected(
138
+			$path_to_event_model
139
+		);
140
+		$this->_cap_restriction_generators[ EEM_Base::caps_edit ]       = new EE_Restriction_Generator_Event_Related_Protected(
141
+			$path_to_event_model
142
+		);
143
+		$this->_cap_restriction_generators[ EEM_Base::caps_delete ]     = new EE_Restriction_Generator_Event_Related_Protected(
144
+			$path_to_event_model,
145
+			EEM_Base::caps_edit
146
+		);
147
+		parent::__construct($timezone);
148
+	}
149
+
150
+
151
+	/**
152
+	 * create new blank datetime
153
+	 *
154
+	 * @access public
155
+	 * @return EE_Datetime[] array on success, FALSE on fail
156
+	 * @throws EE_Error
157
+	 * @throws InvalidArgumentException
158
+	 * @throws InvalidDataTypeException
159
+	 * @throws ReflectionException
160
+	 * @throws InvalidInterfaceException
161
+	 */
162
+	public function create_new_blank_datetime()
163
+	{
164
+		// makes sure timezone is always set.
165
+		$timezone_string = $this->get_timezone();
166
+		/**
167
+		 * Filters the initial start date for the new datetime.
168
+		 * Any time included in this value will be overridden later so use additional filters to modify the time.
169
+		 *
170
+		 * @param int $start_date Unixtimestamp representing now + 30 days in seconds.
171
+		 * @return int unixtimestamp
172
+		 */
173
+		$start_date = apply_filters(
174
+			'FHEE__EEM_Datetime__create_new_blank_datetime__start_date',
175
+			$this->current_time_for_query('DTT_EVT_start', true) + MONTH_IN_SECONDS
176
+		);
177
+		/**
178
+		 * Filters the initial end date for the new datetime.
179
+		 * Any time included in this value will be overridden later so use additional filters to modify the time.
180
+		 *
181
+		 * @param int $end_data Unixtimestamp representing now + 30 days in seconds.
182
+		 * @return int unixtimestamp
183
+		 */
184
+		$end_date = apply_filters(
185
+			'FHEE__EEM_Datetime__create_new_blank_datetime__end_date',
186
+			$this->current_time_for_query('DTT_EVT_end', true) + MONTH_IN_SECONDS
187
+		);
188
+		$blank_datetime = EE_Datetime::new_instance(
189
+			array(
190
+				'DTT_EVT_start' => $start_date,
191
+				'DTT_EVT_end'   => $end_date,
192
+				'DTT_order'     => 1,
193
+				'DTT_reg_limit' => EE_INF,
194
+			),
195
+			$timezone_string
196
+		);
197
+		/**
198
+		 * Filters the initial start time and format for the new EE_Datetime instance.
199
+		 *
200
+		 * @param array $start_time An array having size 2.  First element is the time, second element is the time
201
+		 *                          format.
202
+		 * @return array
203
+		 */
204
+		$start_time = apply_filters(
205
+			'FHEE__EEM_Datetime__create_new_blank_datetime__start_time',
206
+			['8am', 'ga']
207
+		);
208
+		/**
209
+		 * Filters the initial end time and format for the new EE_Datetime instance.
210
+		 *
211
+		 * @param array $end_time An array having size 2.  First element is the time, second element is the time
212
+		 *                        format
213
+		 * @return array
214
+		 */
215
+		$end_time = apply_filters(
216
+			'FHEE__EEM_Datetime__create_new_blank_datetime__end_time',
217
+			['5pm', 'ga']
218
+		);
219
+		$this->validateStartAndEndTimeForBlankDate($start_time, $end_time);
220
+		$blank_datetime->set_start_time(
221
+			$this->convert_datetime_for_query(
222
+				'DTT_EVT_start',
223
+				$start_time[0],
224
+				$start_time[1],
225
+				$timezone_string
226
+			)
227
+		);
228
+		$blank_datetime->set_end_time(
229
+			$this->convert_datetime_for_query(
230
+				'DTT_EVT_end',
231
+				$end_time[0],
232
+				$end_time[1],
233
+				$timezone_string
234
+			)
235
+		);
236
+		return array($blank_datetime);
237
+	}
238
+
239
+
240
+	/**
241
+	 * Validates whether the start_time and end_time are in the expected format.
242
+	 * @param array $start_time
243
+	 * @param array $end_time
244
+	 * @throws InvalidArgumentException
245
+	 * @throws InvalidDataTypeException
246
+	 */
247
+	private function validateStartAndEndTimeForBlankDate($start_time, $end_time)
248
+	{
249
+		if (! is_array($start_time)) {
250
+			throw new InvalidDataTypeException('start_time', $start_time, 'array');
251
+		}
252
+		if (! is_array($end_time)) {
253
+			throw new InvalidDataTypeException('end_time', $end_time, 'array');
254
+		}
255
+		if (count($start_time) !== 2) {
256
+			throw new InvalidArgumentException(
257
+				sprintf(
258
+					'The variable %1$s is expected to be an array with two elements.  The first item in the '
259
+					. 'array should be a valid time string, the second item in the array should be a valid time format',
260
+					'$start_time'
261
+				)
262
+			);
263
+		}
264
+		if (count($end_time) !== 2) {
265
+			throw new InvalidArgumentException(
266
+				sprintf(
267
+					'The variable %1$s is expected to be an array with two elements.  The first item in the '
268
+					. 'array should be a valid time string, the second item in the array should be a valid time format',
269
+					'$end_time'
270
+				)
271
+			);
272
+		}
273
+	}
274
+
275
+
276
+	/**
277
+	 * get event start date from db
278
+	 *
279
+	 * @access public
280
+	 * @param  int $EVT_ID
281
+	 * @return EE_Datetime[] array on success, FALSE on fail
282
+	 * @throws EE_Error
283
+	 */
284
+	public function get_all_event_dates($EVT_ID = 0)
285
+	{
286
+		if (! $EVT_ID) { // on add_new_event event_id gets set to 0
287
+			return $this->create_new_blank_datetime();
288
+		}
289
+		$results = $this->get_datetimes_for_event_ordered_by_DTT_order($EVT_ID);
290
+		if (empty($results)) {
291
+			return $this->create_new_blank_datetime();
292
+		}
293
+		return $results;
294
+	}
295
+
296
+
297
+	/**
298
+	 * get all datetimes attached to an event ordered by the DTT_order field
299
+	 *
300
+	 * @public
301
+	 * @param  int    $EVT_ID     event id
302
+	 * @param boolean $include_expired
303
+	 * @param boolean $include_deleted
304
+	 * @param  int    $limit      If included then limit the count of results by
305
+	 *                            the given number
306
+	 * @return EE_Datetime[]
307
+	 * @throws EE_Error
308
+	 */
309
+	public function get_datetimes_for_event_ordered_by_DTT_order(
310
+		$EVT_ID,
311
+		$include_expired = true,
312
+		$include_deleted = true,
313
+		$limit = null
314
+	) {
315
+		// sanitize EVT_ID
316
+		$EVT_ID         = absint($EVT_ID);
317
+		$old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object();
318
+		$this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
319
+		$where_params = array('Event.EVT_ID' => $EVT_ID);
320
+		$query_params = ! empty($limit)
321
+			? array(
322
+				$where_params,
323
+				'limit'                    => $limit,
324
+				'order_by'                 => array('DTT_order' => 'ASC'),
325
+				'default_where_conditions' => 'none',
326
+			)
327
+			: array(
328
+				$where_params,
329
+				'order_by'                 => array('DTT_order' => 'ASC'),
330
+				'default_where_conditions' => 'none',
331
+			);
332
+		if (! $include_expired) {
333
+			$query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
334
+		}
335
+		if ($include_deleted) {
336
+			$query_params[0]['DTT_deleted'] = array('IN', array(true, false));
337
+		}
338
+		/** @var EE_Datetime[] $result */
339
+		$result = $this->get_all($query_params);
340
+		$this->assume_values_already_prepared_by_model_object($old_assumption);
341
+		return $result;
342
+	}
343
+
344
+
345
+	/**
346
+	 * Gets the datetimes for the event (with the given limit), and orders them by "importance".
347
+	 * By importance, we mean that the primary datetimes are most important (DEPRECATED FOR NOW),
348
+	 * and then the earlier datetimes are the most important.
349
+	 * Maybe we'll want this to take into account datetimes that haven't already passed, but we don't yet.
350
+	 *
351
+	 * @param int $EVT_ID
352
+	 * @param int $limit
353
+	 * @return EE_Datetime[]|EE_Base_Class[]
354
+	 * @throws EE_Error
355
+	 */
356
+	public function get_datetimes_for_event_ordered_by_importance($EVT_ID = 0, $limit = null)
357
+	{
358
+		return $this->get_all(
359
+			array(
360
+				array('Event.EVT_ID' => $EVT_ID),
361
+				'limit'                    => $limit,
362
+				'order_by'                 => array('DTT_EVT_start' => 'ASC'),
363
+				'default_where_conditions' => 'none',
364
+			)
365
+		);
366
+	}
367
+
368
+
369
+	/**
370
+	 * @param int     $EVT_ID
371
+	 * @param boolean $include_expired
372
+	 * @param boolean $include_deleted
373
+	 * @return EE_Datetime
374
+	 * @throws EE_Error
375
+	 */
376
+	public function get_oldest_datetime_for_event($EVT_ID, $include_expired = false, $include_deleted = false)
377
+	{
378
+		$results = $this->get_datetimes_for_event_ordered_by_start_time(
379
+			$EVT_ID,
380
+			$include_expired,
381
+			$include_deleted,
382
+			1
383
+		);
384
+		if ($results) {
385
+			return array_shift($results);
386
+		}
387
+		return null;
388
+	}
389
+
390
+
391
+	/**
392
+	 * Gets the 'primary' datetime for an event.
393
+	 *
394
+	 * @param int  $EVT_ID
395
+	 * @param bool $try_to_exclude_expired
396
+	 * @param bool $try_to_exclude_deleted
397
+	 * @return \EE_Datetime
398
+	 * @throws EE_Error
399
+	 */
400
+	public function get_primary_datetime_for_event(
401
+		$EVT_ID,
402
+		$try_to_exclude_expired = true,
403
+		$try_to_exclude_deleted = true
404
+	) {
405
+		if ($try_to_exclude_expired) {
406
+			$non_expired = $this->get_oldest_datetime_for_event($EVT_ID, false, false);
407
+			if ($non_expired) {
408
+				return $non_expired;
409
+			}
410
+		}
411
+		if ($try_to_exclude_deleted) {
412
+			$expired_even = $this->get_oldest_datetime_for_event($EVT_ID, true);
413
+			if ($expired_even) {
414
+				return $expired_even;
415
+			}
416
+		}
417
+		return $this->get_oldest_datetime_for_event($EVT_ID, true, true);
418
+	}
419
+
420
+
421
+	/**
422
+	 * Gets ALL the datetimes for an event (including trashed ones, for now), ordered
423
+	 * only by start date
424
+	 *
425
+	 * @param int     $EVT_ID
426
+	 * @param boolean $include_expired
427
+	 * @param boolean $include_deleted
428
+	 * @param int     $limit
429
+	 * @return EE_Datetime[]
430
+	 * @throws EE_Error
431
+	 */
432
+	public function get_datetimes_for_event_ordered_by_start_time(
433
+		$EVT_ID,
434
+		$include_expired = true,
435
+		$include_deleted = true,
436
+		$limit = null
437
+	) {
438
+		// sanitize EVT_ID
439
+		$EVT_ID         = absint($EVT_ID);
440
+		$old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object();
441
+		$this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
442
+		$query_params = array(array('Event.EVT_ID' => $EVT_ID), 'order_by' => array('DTT_EVT_start' => 'asc'));
443
+		if (! $include_expired) {
444
+			$query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
445
+		}
446
+		if ($include_deleted) {
447
+			$query_params[0]['DTT_deleted'] = array('IN', array(true, false));
448
+		}
449
+		if ($limit) {
450
+			$query_params['limit'] = $limit;
451
+		}
452
+		/** @var EE_Datetime[] $result */
453
+		$result = $this->get_all($query_params);
454
+		$this->assume_values_already_prepared_by_model_object($old_assumption);
455
+		return $result;
456
+	}
457
+
458
+
459
+	/**
460
+	 * Gets ALL the datetimes for an ticket (including trashed ones, for now), ordered
461
+	 * only by start date
462
+	 *
463
+	 * @param int     $TKT_ID
464
+	 * @param boolean $include_expired
465
+	 * @param boolean $include_deleted
466
+	 * @param int     $limit
467
+	 * @return EE_Datetime[]
468
+	 * @throws EE_Error
469
+	 */
470
+	public function get_datetimes_for_ticket_ordered_by_start_time(
471
+		$TKT_ID,
472
+		$include_expired = true,
473
+		$include_deleted = true,
474
+		$limit = null
475
+	) {
476
+		// sanitize TKT_ID
477
+		$TKT_ID         = absint($TKT_ID);
478
+		$old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object();
479
+		$this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
480
+		$query_params = array(array('Ticket.TKT_ID' => $TKT_ID), 'order_by' => array('DTT_EVT_start' => 'asc'));
481
+		if (! $include_expired) {
482
+			$query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
483
+		}
484
+		if ($include_deleted) {
485
+			$query_params[0]['DTT_deleted'] = array('IN', array(true, false));
486
+		}
487
+		if ($limit) {
488
+			$query_params['limit'] = $limit;
489
+		}
490
+		/** @var EE_Datetime[] $result */
491
+		$result = $this->get_all($query_params);
492
+		$this->assume_values_already_prepared_by_model_object($old_assumption);
493
+		return $result;
494
+	}
495
+
496
+
497
+	/**
498
+	 * Gets all the datetimes for a ticket (including trashed ones, for now), ordered by the DTT_order for the
499
+	 * datetimes.
500
+	 *
501
+	 * @param  int      $TKT_ID          ID of ticket to retrieve the datetimes for
502
+	 * @param  boolean  $include_expired whether to include expired datetimes or not
503
+	 * @param  boolean  $include_deleted whether to include trashed datetimes or not.
504
+	 * @param  int|null $limit           if null, no limit, if int then limit results by
505
+	 *                                   that number
506
+	 * @return EE_Datetime[]
507
+	 * @throws EE_Error
508
+	 */
509
+	public function get_datetimes_for_ticket_ordered_by_DTT_order(
510
+		$TKT_ID,
511
+		$include_expired = true,
512
+		$include_deleted = true,
513
+		$limit = null
514
+	) {
515
+		// sanitize id.
516
+		$TKT_ID         = absint($TKT_ID);
517
+		$old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object();
518
+		$this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
519
+		$where_params = array('Ticket.TKT_ID' => $TKT_ID);
520
+		$query_params = array($where_params, 'order_by' => array('DTT_order' => 'ASC'));
521
+		if (! $include_expired) {
522
+			$query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
523
+		}
524
+		if ($include_deleted) {
525
+			$query_params[0]['DTT_deleted'] = array('IN', array(true, false));
526
+		}
527
+		if ($limit) {
528
+			$query_params['limit'] = $limit;
529
+		}
530
+		/** @var EE_Datetime[] $result */
531
+		$result = $this->get_all($query_params);
532
+		$this->assume_values_already_prepared_by_model_object($old_assumption);
533
+		return $result;
534
+	}
535
+
536
+
537
+	/**
538
+	 * Gets the most important datetime for a particular event (ie, the primary event usually. But if for some WACK
539
+	 * reason it doesn't exist, we consider the earliest event the most important)
540
+	 *
541
+	 * @param int $EVT_ID
542
+	 * @return EE_Datetime
543
+	 * @throws EE_Error
544
+	 */
545
+	public function get_most_important_datetime_for_event($EVT_ID)
546
+	{
547
+		$results = $this->get_datetimes_for_event_ordered_by_importance($EVT_ID, 1);
548
+		if ($results) {
549
+			return array_shift($results);
550
+		}
551
+		return null;
552
+	}
553
+
554
+
555
+	/**
556
+	 * This returns a wpdb->results        Array of all DTT month and years matching the incoming query params and
557
+	 * grouped by month and year.
558
+	 *
559
+	 * @param  array  $where_params      @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions
560
+	 * @param  string $evt_active_status A string representing the evt active status to filter the months by.
561
+	 *                                   Can be:
562
+	 *                                   - '' = no filter
563
+	 *                                   - upcoming = Published events with at least one upcoming datetime.
564
+	 *                                   - expired = Events with all datetimes expired.
565
+	 *                                   - active = Events that are published and have at least one datetime that
566
+	 *                                   starts before now and ends after now.
567
+	 *                                   - inactive = Events that are either not published.
568
+	 * @return EE_Base_Class[]
569
+	 * @throws EE_Error
570
+	 * @throws InvalidArgumentException
571
+	 * @throws InvalidArgumentException
572
+	 */
573
+	public function get_dtt_months_and_years($where_params, $evt_active_status = '')
574
+	{
575
+		$current_time_for_DTT_EVT_start = $this->current_time_for_query('DTT_EVT_start');
576
+		$current_time_for_DTT_EVT_end   = $this->current_time_for_query('DTT_EVT_end');
577
+		switch ($evt_active_status) {
578
+			case 'upcoming':
579
+				$where_params['Event.status'] = 'publish';
580
+				// if there are already query_params matching DTT_EVT_start then we need to modify that to add them.
581
+				if (isset($where_params['DTT_EVT_start'])) {
582
+					$where_params['DTT_EVT_start*****'] = $where_params['DTT_EVT_start'];
583
+				}
584
+				$where_params['DTT_EVT_start'] = array('>', $current_time_for_DTT_EVT_start);
585
+				break;
586
+			case 'expired':
587
+				if (isset($where_params['Event.status'])) {
588
+					unset($where_params['Event.status']);
589
+				}
590
+				// get events to exclude
591
+				$exclude_query[0] = array_merge(
592
+					$where_params,
593
+					array('DTT_EVT_end' => array('>', $current_time_for_DTT_EVT_end))
594
+				);
595
+				// first get all events that have datetimes where its not expired.
596
+				$event_ids = $this->_get_all_wpdb_results(
597
+					$exclude_query,
598
+					OBJECT_K,
599
+					'Datetime.EVT_ID'
600
+				);
601
+				$event_ids = array_keys($event_ids);
602
+				if (isset($where_params['DTT_EVT_end'])) {
603
+					$where_params['DTT_EVT_end****'] = $where_params['DTT_EVT_end'];
604
+				}
605
+				$where_params['DTT_EVT_end']  = array('<', $current_time_for_DTT_EVT_end);
606
+				$where_params['Event.EVT_ID'] = array('NOT IN', $event_ids);
607
+				break;
608
+			case 'active':
609
+				$where_params['Event.status'] = 'publish';
610
+				if (isset($where_params['DTT_EVT_start'])) {
611
+					$where_params['Datetime.DTT_EVT_start******'] = $where_params['DTT_EVT_start'];
612
+				}
613
+				if (isset($where_params['Datetime.DTT_EVT_end'])) {
614
+					$where_params['Datetime.DTT_EVT_end*****'] = $where_params['DTT_EVT_end'];
615
+				}
616
+				$where_params['DTT_EVT_start'] = array('<', $current_time_for_DTT_EVT_start);
617
+				$where_params['DTT_EVT_end']   = array('>', $current_time_for_DTT_EVT_end);
618
+				break;
619
+			case 'inactive':
620
+				if (isset($where_params['Event.status'])) {
621
+					unset($where_params['Event.status']);
622
+				}
623
+				if (isset($where_params['OR'])) {
624
+					$where_params['AND']['OR'] = $where_params['OR'];
625
+				}
626
+				if (isset($where_params['DTT_EVT_end'])) {
627
+					$where_params['AND']['DTT_EVT_end****'] = $where_params['DTT_EVT_end'];
628
+					unset($where_params['DTT_EVT_end']);
629
+				}
630
+				if (isset($where_params['DTT_EVT_start'])) {
631
+					$where_params['AND']['DTT_EVT_start'] = $where_params['DTT_EVT_start'];
632
+					unset($where_params['DTT_EVT_start']);
633
+				}
634
+				$where_params['AND']['Event.status'] = array('!=', 'publish');
635
+				break;
636
+		}
637
+		$query_params[0]          = $where_params;
638
+		$query_params['group_by'] = array('dtt_year', 'dtt_month');
639
+		$query_params['order_by'] = array('DTT_EVT_start' => 'DESC');
640
+		$query_interval           = EEH_DTT_Helper::get_sql_query_interval_for_offset(
641
+			$this->get_timezone(),
642
+			'DTT_EVT_start'
643
+		);
644
+		$columns_to_select        = array(
645
+			'dtt_year'      => array('YEAR(' . $query_interval . ')', '%s'),
646
+			'dtt_month'     => array('MONTHNAME(' . $query_interval . ')', '%s'),
647
+			'dtt_month_num' => array('MONTH(' . $query_interval . ')', '%s'),
648
+		);
649
+		return $this->_get_all_wpdb_results($query_params, OBJECT, $columns_to_select);
650
+	}
651
+
652
+
653
+	/**
654
+	 * Updates the DTT_sold attribute on each datetime (based on the registrations
655
+	 * for the tickets for each datetime)
656
+	 *
657
+	 * @param EE_Base_Class[]|EE_Datetime[] $datetimes
658
+	 * @throws EE_Error
659
+	 */
660
+	public function update_sold($datetimes)
661
+	{
662
+		EE_Error::doing_it_wrong(
663
+			__FUNCTION__,
664
+			esc_html__(
665
+				'Please use \EEM_Ticket::update_tickets_sold() instead which will in turn correctly update both the Ticket AND Datetime counts.',
666
+				'event_espresso'
667
+			),
668
+			'4.9.32.rc.005'
669
+		);
670
+		foreach ($datetimes as $datetime) {
671
+			$datetime->update_sold();
672
+		}
673
+	}
674
+
675
+
676
+	/**
677
+	 *    Gets the total number of tickets available at a particular datetime
678
+	 *    (does NOT take into account the datetime's spaces available)
679
+	 *
680
+	 * @param int   $DTT_ID
681
+	 * @param array $query_params
682
+	 * @return int of tickets available. If sold out, return less than 1. If infinite, returns EE_INF,  IF there are NO
683
+	 *             tickets attached to datetime then FALSE is returned.
684
+	 */
685
+	public function sum_tickets_currently_available_at_datetime($DTT_ID, array $query_params = array())
686
+	{
687
+		$datetime = $this->get_one_by_ID($DTT_ID);
688
+		if ($datetime instanceof EE_Datetime) {
689
+			return $datetime->tickets_remaining($query_params);
690
+		}
691
+		return 0;
692
+	}
693
+
694
+
695
+	/**
696
+	 * This returns an array of counts of datetimes in the database for each Datetime status that can be queried.
697
+	 *
698
+	 * @param  array $stati_to_include If included you can restrict the statuses we return counts for by including the
699
+	 *                                 stati you want counts for as values in the array.  An empty array returns counts
700
+	 *                                 for all valid stati.
701
+	 * @param  array $query_params     If included can be used to refine the conditions for returning the count (i.e.
702
+	 *                                 only for Datetimes connected to a specific event, or specific ticket.
703
+	 * @return array  The value returned is an array indexed by Datetime Status and the values are the counts.  The
704
+	 * @throws EE_Error
705
+	 *                                 stati used as index keys are: EE_Datetime::active EE_Datetime::upcoming
706
+	 *                                 EE_Datetime::expired
707
+	 */
708
+	public function get_datetime_counts_by_status(array $stati_to_include = array(), array $query_params = array())
709
+	{
710
+		// only accept where conditions for this query.
711
+		$_where            = isset($query_params[0]) ? $query_params[0] : array();
712
+		$status_query_args = array(
713
+			EE_Datetime::active   => array_merge(
714
+				$_where,
715
+				array('DTT_EVT_start' => array('<', time()), 'DTT_EVT_end' => array('>', time()))
716
+			),
717
+			EE_Datetime::upcoming => array_merge(
718
+				$_where,
719
+				array('DTT_EVT_start' => array('>', time()))
720
+			),
721
+			EE_Datetime::expired  => array_merge(
722
+				$_where,
723
+				array('DTT_EVT_end' => array('<', time()))
724
+			),
725
+		);
726
+		if (! empty($stati_to_include)) {
727
+			foreach (array_keys($status_query_args) as $status) {
728
+				if (! in_array($status, $stati_to_include, true)) {
729
+					unset($status_query_args[ $status ]);
730
+				}
731
+			}
732
+		}
733
+		// loop through and query counts for each stati.
734
+		$status_query_results = array();
735
+		foreach ($status_query_args as $status => $status_where_conditions) {
736
+			$status_query_results[ $status ] = EEM_Datetime::count(
737
+				array($status_where_conditions),
738
+				'DTT_ID',
739
+				true
740
+			);
741
+		}
742
+		return $status_query_results;
743
+	}
744
+
745
+
746
+	/**
747
+	 * Returns the specific count for a given Datetime status matching any given query_params.
748
+	 *
749
+	 * @param string $status Valid string representation for Datetime status requested. (Defaults to Active).
750
+	 * @param array  $query_params
751
+	 * @return int
752
+	 * @throws EE_Error
753
+	 */
754
+	public function get_datetime_count_for_status($status = EE_Datetime::active, array $query_params = array())
755
+	{
756
+		$count = $this->get_datetime_counts_by_status(array($status), $query_params);
757
+		return ! empty($count[ $status ]) ? $count[ $status ] : 0;
758
+	}
759 759
 }
Please login to merge, or discard this patch.
Spacing   +21 added lines, -21 removed lines patch added patch discarded remove patch
@@ -121,7 +121,7 @@  discard block
 block discarded – undo
121 121
                 ),
122 122
             ),
123 123
         );
124
-        $this->_model_relations        = array(
124
+        $this->_model_relations = array(
125 125
             'Ticket'  => new EE_HABTM_Relation('Datetime_Ticket'),
126 126
             'Event'   => new EE_Belongs_To_Relation(),
127 127
             'Checkin' => new EE_Has_Many_Relation(),
@@ -131,16 +131,16 @@  discard block
 block discarded – undo
131 131
         $this->model_chain_to_password = $path_to_event_model;
132 132
         $this->_model_chain_to_wp_user = $path_to_event_model;
133 133
         // this model is generally available for reading
134
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ]       = new EE_Restriction_Generator_Event_Related_Public(
134
+        $this->_cap_restriction_generators[EEM_Base::caps_read]       = new EE_Restriction_Generator_Event_Related_Public(
135 135
             $path_to_event_model
136 136
         );
137
-        $this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = new EE_Restriction_Generator_Event_Related_Protected(
137
+        $this->_cap_restriction_generators[EEM_Base::caps_read_admin] = new EE_Restriction_Generator_Event_Related_Protected(
138 138
             $path_to_event_model
139 139
         );
140
-        $this->_cap_restriction_generators[ EEM_Base::caps_edit ]       = new EE_Restriction_Generator_Event_Related_Protected(
140
+        $this->_cap_restriction_generators[EEM_Base::caps_edit]       = new EE_Restriction_Generator_Event_Related_Protected(
141 141
             $path_to_event_model
142 142
         );
143
-        $this->_cap_restriction_generators[ EEM_Base::caps_delete ]     = new EE_Restriction_Generator_Event_Related_Protected(
143
+        $this->_cap_restriction_generators[EEM_Base::caps_delete]     = new EE_Restriction_Generator_Event_Related_Protected(
144 144
             $path_to_event_model,
145 145
             EEM_Base::caps_edit
146 146
         );
@@ -246,10 +246,10 @@  discard block
 block discarded – undo
246 246
      */
247 247
     private function validateStartAndEndTimeForBlankDate($start_time, $end_time)
248 248
     {
249
-        if (! is_array($start_time)) {
249
+        if ( ! is_array($start_time)) {
250 250
             throw new InvalidDataTypeException('start_time', $start_time, 'array');
251 251
         }
252
-        if (! is_array($end_time)) {
252
+        if ( ! is_array($end_time)) {
253 253
             throw new InvalidDataTypeException('end_time', $end_time, 'array');
254 254
         }
255 255
         if (count($start_time) !== 2) {
@@ -283,7 +283,7 @@  discard block
 block discarded – undo
283 283
      */
284 284
     public function get_all_event_dates($EVT_ID = 0)
285 285
     {
286
-        if (! $EVT_ID) { // on add_new_event event_id gets set to 0
286
+        if ( ! $EVT_ID) { // on add_new_event event_id gets set to 0
287 287
             return $this->create_new_blank_datetime();
288 288
         }
289 289
         $results = $this->get_datetimes_for_event_ordered_by_DTT_order($EVT_ID);
@@ -329,7 +329,7 @@  discard block
 block discarded – undo
329 329
                 'order_by'                 => array('DTT_order' => 'ASC'),
330 330
                 'default_where_conditions' => 'none',
331 331
             );
332
-        if (! $include_expired) {
332
+        if ( ! $include_expired) {
333 333
             $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
334 334
         }
335 335
         if ($include_deleted) {
@@ -440,7 +440,7 @@  discard block
 block discarded – undo
440 440
         $old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object();
441 441
         $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
442 442
         $query_params = array(array('Event.EVT_ID' => $EVT_ID), 'order_by' => array('DTT_EVT_start' => 'asc'));
443
-        if (! $include_expired) {
443
+        if ( ! $include_expired) {
444 444
             $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
445 445
         }
446 446
         if ($include_deleted) {
@@ -478,7 +478,7 @@  discard block
 block discarded – undo
478 478
         $old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object();
479 479
         $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
480 480
         $query_params = array(array('Ticket.TKT_ID' => $TKT_ID), 'order_by' => array('DTT_EVT_start' => 'asc'));
481
-        if (! $include_expired) {
481
+        if ( ! $include_expired) {
482 482
             $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
483 483
         }
484 484
         if ($include_deleted) {
@@ -518,7 +518,7 @@  discard block
 block discarded – undo
518 518
         $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
519 519
         $where_params = array('Ticket.TKT_ID' => $TKT_ID);
520 520
         $query_params = array($where_params, 'order_by' => array('DTT_order' => 'ASC'));
521
-        if (! $include_expired) {
521
+        if ( ! $include_expired) {
522 522
             $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
523 523
         }
524 524
         if ($include_deleted) {
@@ -641,10 +641,10 @@  discard block
 block discarded – undo
641 641
             $this->get_timezone(),
642 642
             'DTT_EVT_start'
643 643
         );
644
-        $columns_to_select        = array(
645
-            'dtt_year'      => array('YEAR(' . $query_interval . ')', '%s'),
646
-            'dtt_month'     => array('MONTHNAME(' . $query_interval . ')', '%s'),
647
-            'dtt_month_num' => array('MONTH(' . $query_interval . ')', '%s'),
644
+        $columns_to_select = array(
645
+            'dtt_year'      => array('YEAR('.$query_interval.')', '%s'),
646
+            'dtt_month'     => array('MONTHNAME('.$query_interval.')', '%s'),
647
+            'dtt_month_num' => array('MONTH('.$query_interval.')', '%s'),
648 648
         );
649 649
         return $this->_get_all_wpdb_results($query_params, OBJECT, $columns_to_select);
650 650
     }
@@ -723,17 +723,17 @@  discard block
 block discarded – undo
723 723
                 array('DTT_EVT_end' => array('<', time()))
724 724
             ),
725 725
         );
726
-        if (! empty($stati_to_include)) {
726
+        if ( ! empty($stati_to_include)) {
727 727
             foreach (array_keys($status_query_args) as $status) {
728
-                if (! in_array($status, $stati_to_include, true)) {
729
-                    unset($status_query_args[ $status ]);
728
+                if ( ! in_array($status, $stati_to_include, true)) {
729
+                    unset($status_query_args[$status]);
730 730
                 }
731 731
             }
732 732
         }
733 733
         // loop through and query counts for each stati.
734 734
         $status_query_results = array();
735 735
         foreach ($status_query_args as $status => $status_where_conditions) {
736
-            $status_query_results[ $status ] = EEM_Datetime::count(
736
+            $status_query_results[$status] = EEM_Datetime::count(
737 737
                 array($status_where_conditions),
738 738
                 'DTT_ID',
739 739
                 true
@@ -754,6 +754,6 @@  discard block
 block discarded – undo
754 754
     public function get_datetime_count_for_status($status = EE_Datetime::active, array $query_params = array())
755 755
     {
756 756
         $count = $this->get_datetime_counts_by_status(array($status), $query_params);
757
-        return ! empty($count[ $status ]) ? $count[ $status ] : 0;
757
+        return ! empty($count[$status]) ? $count[$status] : 0;
758 758
     }
759 759
 }
Please login to merge, or discard this patch.