Completed
Branch FET/event-question-group-refac... (8c9768)
by
unknown
27:04 queued 17:53
created

validateStartAndEndTimeForBlankDate()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
nc 5
nop 2
dl 0
loc 27
rs 9.1768
c 0
b 0
f 0
1
<?php
2
3
use EventEspresso\core\exceptions\InvalidDataTypeException;
4
use EventEspresso\core\exceptions\InvalidInterfaceException;
5
6
/**
7
 * Class Datetime Model
8
 *
9
 * @package               Event Espresso
10
 * @subpackage            includes/models/
11
 * @author                Michael Nelson, Brent Christensen
12
 */
13
class EEM_Datetime extends EEM_Soft_Delete_Base
14
{
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) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $results of type EE_Datetime[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
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);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $expired_even is correct as $this->get_oldest_dateti...or_event($EVT_ID, true) (which targets EEM_Datetime::get_oldest_datetime_for_event()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
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 View Code Duplication
    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) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $limit of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
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 View Code Duplication
    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) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $limit of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
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 View Code Duplication
    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) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $limit of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
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) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $results of type EE_Base_Class[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
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(
0 ignored issues
show
Coding Style Comprehensibility introduced by
$exclude_query was never initialized. Although not strictly required by PHP, it is generally a good practice to add $exclude_query = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
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;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$query_params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $query_params = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
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
}
760