Completed
Branch trashed-datetimes-in-queries (9af1cf)
by
unknown
38:51 queued 29:30
created

EEM_Datetime::prepModelForQuery()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
use EventEspresso\core\exceptions\InvalidDataTypeException;
4
use EventEspresso\core\exceptions\InvalidInterfaceException;
5
6
/**
7
 * 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                 = [
39
            'Datetime' => new EE_Primary_Table('esp_datetime', 'DTT_ID'),
40
        ];
41
        $this->_fields                 = [
42
            'Datetime' => [
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        = [
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 ]       =
135
            new EE_Restriction_Generator_Event_Related_Public(
136
                $path_to_event_model
137
            );
138
        $this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] =
139
            new EE_Restriction_Generator_Event_Related_Protected(
140
                $path_to_event_model
141
            );
142
        $this->_cap_restriction_generators[ EEM_Base::caps_edit ]       =
143
            new EE_Restriction_Generator_Event_Related_Protected(
144
                $path_to_event_model
145
            );
146
        $this->_cap_restriction_generators[ EEM_Base::caps_delete ]     =
147
            new EE_Restriction_Generator_Event_Related_Protected(
148
                $path_to_event_model,
149
                EEM_Base::caps_edit
150
            );
151
        parent::__construct($timezone);
152
    }
153
154
155
    /**
156
     * create new blank datetime
157
     *
158
     * @access public
159
     * @return EE_Datetime[] array on success, FALSE on fail
160
     * @throws EE_Error
161
     * @throws InvalidArgumentException
162
     * @throws InvalidDataTypeException
163
     * @throws ReflectionException
164
     * @throws InvalidInterfaceException
165
     */
166
    public function create_new_blank_datetime()
167
    {
168
        // makes sure timezone is always set.
169
        $timezone_string = $this->get_timezone();
170
        /**
171
         * Filters the initial start date for the new datetime.
172
         * Any time included in this value will be overridden later so use additional filters to modify the time.
173
         *
174
         * @param int $start_date Unix timestamp representing now + 30 days in seconds.
175
         * @return int Unix timestamp
176
         */
177
        $start_date = apply_filters(
178
            'FHEE__EEM_Datetime__create_new_blank_datetime__start_date',
179
            $this->current_time_for_query('DTT_EVT_start', true) + MONTH_IN_SECONDS
180
        );
181
        /**
182
         * Filters the initial end date for the new datetime.
183
         * Any time included in this value will be overridden later so use additional filters to modify the time.
184
         *
185
         * @param int $end_data Unix timestamp representing now + 30 days in seconds.
186
         * @return int Unix timestamp
187
         */
188
        $end_date       = apply_filters(
189
            'FHEE__EEM_Datetime__create_new_blank_datetime__end_date',
190
            $this->current_time_for_query('DTT_EVT_end', true) + MONTH_IN_SECONDS
191
        );
192
        $blank_datetime = EE_Datetime::new_instance(
193
            [
194
                'DTT_EVT_start' => $start_date,
195
                'DTT_EVT_end'   => $end_date,
196
                'DTT_order'     => 1,
197
                'DTT_reg_limit' => EE_INF,
198
            ],
199
            $timezone_string
200
        );
201
        /**
202
         * Filters the initial start time and format for the new EE_Datetime instance.
203
         *
204
         * @param array $start_time An array having size 2.  First element is the time, second element is the time
205
         *                          format.
206
         * @return array
207
         */
208
        $start_time = apply_filters(
209
            'FHEE__EEM_Datetime__create_new_blank_datetime__start_time',
210
            ['8am', 'ga']
211
        );
212
        /**
213
         * Filters the initial end time and format for the new EE_Datetime instance.
214
         *
215
         * @param array $end_time An array having size 2.  First element is the time, second element is the time
216
         *                        format
217
         * @return array
218
         */
219
        $end_time = apply_filters(
220
            'FHEE__EEM_Datetime__create_new_blank_datetime__end_time',
221
            ['5pm', 'ga']
222
        );
223
        $this->validateStartAndEndTimeForBlankDate($start_time, $end_time);
224
        $blank_datetime->set_start_time(
225
            $this->convert_datetime_for_query(
226
                'DTT_EVT_start',
227
                $start_time[0],
228
                $start_time[1],
229
                $timezone_string
230
            )
231
        );
232
        $blank_datetime->set_end_time(
233
            $this->convert_datetime_for_query(
234
                'DTT_EVT_end',
235
                $end_time[0],
236
                $end_time[1],
237
                $timezone_string
238
            )
239
        );
240
        return [$blank_datetime];
241
    }
242
243
244
    /**
245
     * Validates whether the start_time and end_time are in the expected format.
246
     *
247
     * @param array $start_time
248
     * @param array $end_time
249
     * @throws InvalidArgumentException
250
     * @throws InvalidDataTypeException
251
     */
252
    private function validateStartAndEndTimeForBlankDate(array $start_time, array $end_time)
253
    {
254
        if (! is_array($start_time)) {
255
            throw new InvalidDataTypeException('start_time', $start_time, 'array');
256
        }
257
        if (! is_array($end_time)) {
258
            throw new InvalidDataTypeException('end_time', $end_time, 'array');
259
        }
260
        if (count($start_time) !== 2) {
261
            throw new InvalidArgumentException(
262
                sprintf(
263
                    'The variable %1$s is expected to be an array with two elements.  The first item in the '
264
                    . 'array should be a valid time string, the second item in the array should be a valid time format',
265
                    '$start_time'
266
                )
267
            );
268
        }
269
        if (count($end_time) !== 2) {
270
            throw new InvalidArgumentException(
271
                sprintf(
272
                    'The variable %1$s is expected to be an array with two elements.  The first item in the '
273
                    . 'array should be a valid time string, the second item in the array should be a valid time format',
274
                    '$end_time'
275
                )
276
            );
277
        }
278
    }
279
280
281
    /**
282
     * get event start date from db
283
     *
284
     * @access public
285
     * @param int $EVT_ID
286
     * @return EE_Datetime[] array on success, FALSE on fail
287
     * @throws EE_Error
288
     * @throws ReflectionException
289
     */
290
    public function get_all_event_dates($EVT_ID = 0)
291
    {
292
        if (! $EVT_ID) { // on add_new_event event_id gets set to 0
293
            return $this->create_new_blank_datetime();
294
        }
295
        $results = $this->get_datetimes_for_event_ordered_by_DTT_order($EVT_ID);
296
        if (empty($results)) {
297
            return $this->create_new_blank_datetime();
298
        }
299
        return $results;
300
    }
301
302
303
    /**
304
     * get all datetimes attached to an event ordered by the DTT_order field
305
     *
306
     * @public
307
     * @param int     $EVT_ID     event id
308
     * @param boolean $include_expired
309
     * @param boolean $include_deleted
310
     * @param int     $limit      If included then limit the count of results by
311
     *                            the given number
312
     * @return EE_Datetime[]
313
     * @throws EE_Error
314
     */
315 View Code Duplication
    public function get_datetimes_for_event_ordered_by_DTT_order(
316
        int $EVT_ID,
317
        bool $include_expired = true,
318
        bool $include_deleted = true,
319
        $limit = 0
320
    ) {
321
        $prev_data_prep_value = $this->prepModelForQuery();
322
        $where_params         = ['Event.EVT_ID' => absint($EVT_ID)];
323
        $query_params[0]      = $this->addDefaultWhereParams($where_params, $include_deleted, $include_expired);
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...
324
        $query_params         = $this->addDefaultWhereConditions($query_params);
325
        $query_params         = $this->addDefaultQueryParams($query_params, $limit, 'DTT_order');
326
        return $this->getDatetimesAndRestoreModel($query_params, $prev_data_prep_value);
327
    }
328
329
330
    /**
331
     * Gets the datetimes for the event (with the given limit), and orders them by "importance".
332
     * By importance, we mean that the primary datetimes are most important (DEPRECATED FOR NOW),
333
     * and then the earlier datetimes are the most important.
334
     * Maybe we'll want this to take into account datetimes that haven't already passed, but we don't yet.
335
     *
336
     * @param int $EVT_ID
337
     * @param int $limit
338
     * @return EE_Datetime[]|EE_Base_Class[]
339
     * @throws EE_Error
340
     */
341
    public function get_datetimes_for_event_ordered_by_importance(int $EVT_ID, $limit = 0)
342
    {
343
        $query_params[0] = ['Event.EVT_ID' => absint($EVT_ID)];
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...
344
        $query_params    = $this->addDefaultWhereConditions($query_params);
345
        $query_params    = $this->addDefaultQueryParams($query_params, $limit);
346
        return $this->get_all($query_params);
347
    }
348
349
350
    /**
351
     * @param int     $EVT_ID
352
     * @param boolean $include_expired
353
     * @param boolean $include_deleted
354
     * @return EE_Datetime
355
     * @throws EE_Error
356
     */
357
    public function get_oldest_datetime_for_event(
358
        int $EVT_ID,
359
        bool $include_expired = false,
360
        bool $include_deleted = false
361
    ) {
362
        $results = $this->get_datetimes_for_event_ordered_by_start_time(
363
            $EVT_ID,
364
            $include_expired,
365
            $include_deleted,
366
            1
367
        );
368
        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...
369
            return array_shift($results);
370
        }
371
        return null;
372
    }
373
374
375
    /**
376
     * Gets the 'primary' datetime for an event.
377
     *
378
     * @param int  $EVT_ID
379
     * @param bool $try_to_exclude_expired
380
     * @param bool $try_to_exclude_deleted
381
     * @return EE_Datetime
382
     * @throws EE_Error
383
     */
384
    public function get_primary_datetime_for_event(
385
        int $EVT_ID,
386
        bool $try_to_exclude_expired = true,
387
        bool $try_to_exclude_deleted = true
388
    ) {
389
        if ($try_to_exclude_expired) {
390
            $non_expired = $this->get_oldest_datetime_for_event($EVT_ID, false, false);
391
            if ($non_expired) {
392
                return $non_expired;
393
            }
394
        }
395
        if ($try_to_exclude_deleted) {
396
            $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...
397
            if ($expired_even) {
398
                return $expired_even;
399
            }
400
        }
401
        return $this->get_oldest_datetime_for_event($EVT_ID, true, true);
402
    }
403
404
405
    /**
406
     * Gets ALL the datetimes for an event (including trashed ones, for now), ordered
407
     * only by start date
408
     *
409
     * @param int     $EVT_ID
410
     * @param boolean $include_expired
411
     * @param boolean $include_deleted
412
     * @param int     $limit
413
     * @return EE_Datetime[]
414
     * @throws EE_Error
415
     */
416 View Code Duplication
    public function get_datetimes_for_event_ordered_by_start_time(
417
        int $EVT_ID,
418
        bool $include_expired = true,
419
        bool $include_deleted = true,
420
        $limit = 0
421
    ) {
422
        $prev_data_prep_value = $this->prepModelForQuery();
423
        $where_params         = ['Event.EVT_ID' => absint($EVT_ID)];
424
        $query_params[0]      = $this->addDefaultWhereParams($where_params, $include_deleted, $include_expired);
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...
425
        $query_params         = $this->addDefaultWhereConditions(
426
            $query_params,
427
            EEM_Base::default_where_conditions_this_only
428
        );
429
        $query_params         = $this->addDefaultQueryParams($query_params, $limit, 'DTT_order');
430
        return $this->getDatetimesAndRestoreModel($query_params, $prev_data_prep_value);
431
    }
432
433
434
    /**
435
     * Gets ALL the datetimes for an ticket (including trashed ones, for now), ordered
436
     * only by start date
437
     *
438
     * @param int     $TKT_ID
439
     * @param boolean $include_expired
440
     * @param boolean $include_deleted
441
     * @param int     $limit
442
     * @return EE_Datetime[]
443
     * @throws EE_Error
444
     */
445 View Code Duplication
    public function get_datetimes_for_ticket_ordered_by_start_time(
446
        int $TKT_ID,
447
        bool $include_expired = true,
448
        bool $include_deleted = true,
449
        $limit = 0
450
    ) {
451
        $prev_data_prep_value = $this->prepModelForQuery();
452
        $where_params         = ['Ticket.TKT_ID' => absint($TKT_ID)];
453
        $query_params[0]      = $this->addDefaultWhereParams($where_params, $include_deleted, $include_expired);
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...
454
        $query_params         = $this->addDefaultQueryParams($query_params, $limit);
455
        return $this->getDatetimesAndRestoreModel($query_params, $prev_data_prep_value);
456
    }
457
458
459
    /**
460
     * Gets all the datetimes for a ticket (including trashed ones, for now), ordered by the DTT_order for the
461
     * datetimes.
462
     *
463
     * @param int      $TKT_ID           ID of ticket to retrieve the datetimes for
464
     * @param boolean  $include_expired  whether to include expired datetimes or not
465
     * @param boolean  $include_deleted  whether to include trashed datetimes or not.
466
     * @param int|null $limit            if null, no limit, if int then limit results by
467
     *                                   that number
468
     * @return EE_Datetime[]
469
     * @throws EE_Error
470
     */
471 View Code Duplication
    public function get_datetimes_for_ticket_ordered_by_DTT_order(
472
        int $TKT_ID,
473
        bool $include_expired = true,
474
        bool $include_deleted = true,
475
        $limit = 0
476
    ) {
477
        $prev_data_prep_value = $this->prepModelForQuery();
478
        $where_params         = ['Ticket.TKT_ID' => absint($TKT_ID)];
479
        $query_params[0]      = $this->addDefaultWhereParams($where_params, $include_deleted, $include_expired);
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...
480
        $query_params         = $this->addDefaultQueryParams($query_params, $limit, 'DTT_order');
481
        return $this->getDatetimesAndRestoreModel($query_params, $prev_data_prep_value);
482
    }
483
484
485
    /**
486
     * Gets the most important datetime for a particular event (ie, the primary event usually. But if for some WACK
487
     * reason it doesn't exist, we consider the earliest event the most important)
488
     *
489
     * @param int $EVT_ID
490
     * @return EE_Datetime
491
     * @throws EE_Error
492
     */
493
    public function get_most_important_datetime_for_event(int $EVT_ID)
494
    {
495
        $results = $this->get_datetimes_for_event_ordered_by_importance($EVT_ID, 1);
496
        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...
497
            return array_shift($results);
498
        }
499
        return null;
500
    }
501
502
503
    /**
504
     * This returns a wpdb->results        Array of all DTT month and years matching the incoming query params and
505
     * grouped by month and year.
506
     *
507
     * @param array  $where_params       @see
508
     *                                   https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions
509
     * @param string $evt_active_status  A string representing the evt active status to filter the months by.
510
     *                                   Can be:
511
     *                                   - '' = no filter
512
     *                                   - upcoming = Published events with at least one upcoming datetime.
513
     *                                   - expired = Events with all datetimes expired.
514
     *                                   - active = Events that are published and have at least one datetime that
515
     *                                   starts before now and ends after now.
516
     *                                   - inactive = Events that are either not published.
517
     * @return EE_Base_Class[]
518
     * @throws EE_Error
519
     * @throws InvalidArgumentException
520
     * @throws InvalidArgumentException
521
     */
522
    public function get_dtt_months_and_years(array $where_params, $evt_active_status = '')
523
    {
524
        $current_time_for_DTT_EVT_start = $this->current_time_for_query('DTT_EVT_start');
525
        $current_time_for_DTT_EVT_end   = $this->current_time_for_query('DTT_EVT_end');
526
        switch ($evt_active_status) {
527
            case 'upcoming':
528
                $where_params['Event.status'] = 'publish';
529
                // if there are already query_params matching DTT_EVT_start then we need to modify that to add them.
530
                if (isset($where_params['DTT_EVT_start'])) {
531
                    $where_params['DTT_EVT_start*****'] = $where_params['DTT_EVT_start'];
532
                }
533
                $where_params['DTT_EVT_start'] = ['>', $current_time_for_DTT_EVT_start];
534
                break;
535
            case 'expired':
536
                if (isset($where_params['Event.status'])) {
537
                    unset($where_params['Event.status']);
538
                }
539
                // get events to exclude
540
                $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...
541
                    $where_params,
542
                    ['DTT_EVT_end' => ['>', $current_time_for_DTT_EVT_end]]
543
                );
544
                // first get all events that have datetimes where its not expired.
545
                $event_ids = $this->_get_all_wpdb_results(
546
                    $exclude_query,
547
                    OBJECT_K,
548
                    'Datetime.EVT_ID'
549
                );
550
                $event_ids = array_keys($event_ids);
551
                if (isset($where_params['DTT_EVT_end'])) {
552
                    $where_params['DTT_EVT_end****'] = $where_params['DTT_EVT_end'];
553
                }
554
                $where_params['DTT_EVT_end']  = ['<', $current_time_for_DTT_EVT_end];
555
                $where_params['Event.EVT_ID'] = ['NOT IN', $event_ids];
556
                break;
557
            case 'active':
558
                $where_params['Event.status'] = 'publish';
559
                if (isset($where_params['DTT_EVT_start'])) {
560
                    $where_params['Datetime.DTT_EVT_start******'] = $where_params['DTT_EVT_start'];
561
                }
562
                if (isset($where_params['Datetime.DTT_EVT_end'])) {
563
                    $where_params['Datetime.DTT_EVT_end*****'] = $where_params['DTT_EVT_end'];
564
                }
565
                $where_params['DTT_EVT_start'] = ['<', $current_time_for_DTT_EVT_start];
566
                $where_params['DTT_EVT_end']   = ['>', $current_time_for_DTT_EVT_end];
567
                break;
568
            case 'inactive':
569
                if (isset($where_params['Event.status'])) {
570
                    unset($where_params['Event.status']);
571
                }
572
                if (isset($where_params['OR'])) {
573
                    $where_params['AND']['OR'] = $where_params['OR'];
574
                }
575
                if (isset($where_params['DTT_EVT_end'])) {
576
                    $where_params['AND']['DTT_EVT_end****'] = $where_params['DTT_EVT_end'];
577
                    unset($where_params['DTT_EVT_end']);
578
                }
579
                if (isset($where_params['DTT_EVT_start'])) {
580
                    $where_params['AND']['DTT_EVT_start'] = $where_params['DTT_EVT_start'];
581
                    unset($where_params['DTT_EVT_start']);
582
                }
583
                $where_params['AND']['Event.status'] = ['!=', 'publish'];
584
                break;
585
        }
586
        $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...
587
        $query_params['group_by'] = ['dtt_year', 'dtt_month'];
588
        $query_params             = $this->addOrderByQueryParams($query_params, 'DTT_EVT_start', 'DESC');
589
590
        $query_interval    = EEH_DTT_Helper::get_sql_query_interval_for_offset(
591
            $this->get_timezone(),
592
            'DTT_EVT_start'
593
        );
594
        $columns_to_select = [
595
            'dtt_year'      => ['YEAR(' . $query_interval . ')', '%s'],
596
            'dtt_month'     => ['MONTHNAME(' . $query_interval . ')', '%s'],
597
            'dtt_month_num' => ['MONTH(' . $query_interval . ')', '%s'],
598
        ];
599
        return $this->_get_all_wpdb_results($query_params, OBJECT, $columns_to_select);
600
    }
601
602
603
    /**
604
     * Updates the DTT_sold attribute on each datetime (based on the registrations
605
     * for the tickets for each datetime)
606
     *
607
     * @param EE_Base_Class[]|EE_Datetime[] $datetimes
608
     * @throws EE_Error
609
     * @throws ReflectionException
610
     */
611
    public function update_sold(array $datetimes)
612
    {
613
        EE_Error::doing_it_wrong(
614
            __FUNCTION__,
615
            esc_html__(
616
                'Please use \EEM_Ticket::update_tickets_sold() instead which will in turn correctly update both the Ticket AND Datetime counts.',
617
                'event_espresso'
618
            ),
619
            '4.9.32.rc.005'
620
        );
621
        foreach ($datetimes as $datetime) {
622
            $datetime->update_sold();
623
        }
624
    }
625
626
627
    /**
628
     *    Gets the total number of tickets available at a particular datetime
629
     *    (does NOT take into account the datetime's spaces available)
630
     *
631
     * @param int   $DTT_ID
632
     * @param array $query_params
633
     * @return int of tickets available. If sold out, return less than 1. If infinite, returns EE_INF,  IF there are NO
634
     *             tickets attached to datetime then FALSE is returned.
635
     * @throws EE_Error
636
     * @throws ReflectionException
637
     */
638
    public function sum_tickets_currently_available_at_datetime(int $DTT_ID, array $query_params = [])
639
    {
640
        $datetime = $this->get_one_by_ID($DTT_ID);
641
        if ($datetime instanceof EE_Datetime) {
642
            return $datetime->tickets_remaining($query_params);
643
        }
644
        return 0;
645
    }
646
647
648
    /**
649
     * This returns an array of counts of datetimes in the database for each Datetime status that can be queried.
650
     *
651
     * @param array $stati_to_include  If included you can restrict the statuses we return counts for by including the
652
     *                                 stati you want counts for as values in the array.  An empty array returns counts
653
     *                                 for all valid stati.
654
     * @param array $query_params      If included can be used to refine the conditions for returning the count (i.e.
655
     *                                 only for Datetimes connected to a specific event, or specific ticket.
656
     * @return array  The value returned is an array indexed by Datetime Status and the values are the counts.  The
657
     * @throws EE_Error
658
     *                                 stati used as index keys are: EE_Datetime::active EE_Datetime::upcoming
659
     *                                 EE_Datetime::expired
660
     */
661
    public function get_datetime_counts_by_status(array $stati_to_include = [], array $query_params = [])
662
    {
663
        // only accept where conditions for this query.
664
        $_where            = isset($query_params[0]) ? $query_params[0] : [];
665
        $status_query_args = [
666
            EE_Datetime::active   => array_merge(
667
                $_where,
668
                ['DTT_EVT_start' => ['<', time()], 'DTT_EVT_end' => ['>', time()]]
669
            ),
670
            EE_Datetime::upcoming => array_merge(
671
                $_where,
672
                ['DTT_EVT_start' => ['>', time()]]
673
            ),
674
            EE_Datetime::expired  => array_merge(
675
                $_where,
676
                ['DTT_EVT_end' => ['<', time()]]
677
            ),
678
        ];
679
        if (! empty($stati_to_include)) {
680
            foreach (array_keys($status_query_args) as $status) {
681
                if (! in_array($status, $stati_to_include, true)) {
682
                    unset($status_query_args[ $status ]);
683
                }
684
            }
685
        }
686
        // loop through and query counts for each stati.
687
        $status_query_results = [];
688
        foreach ($status_query_args as $status => $status_where_conditions) {
689
            $status_query_results[ $status ] = EEM_Datetime::count(
690
                [$status_where_conditions],
691
                'DTT_ID',
692
                true
693
            );
694
        }
695
        return $status_query_results;
696
    }
697
698
699
    /**
700
     * Returns the specific count for a given Datetime status matching any given query_params.
701
     *
702
     * @param string $status Valid string representation for Datetime status requested. (Defaults to Active).
703
     * @param array  $query_params
704
     * @return int
705
     * @throws EE_Error
706
     */
707
    public function get_datetime_count_for_status($status = EE_Datetime::active, array $query_params = [])
708
    {
709
        $count = $this->get_datetime_counts_by_status([$status], $query_params);
710
        return ! empty($count[ $status ]) ? $count[ $status ] : 0;
711
    }
712
713
714
    /**
715
     * @return bool|int
716
     * @since   $VID:$
717
     */
718
    private function prepModelForQuery()
719
    {
720
        $prev_data_prep_value = $this->get_assumption_concerning_values_already_prepared_by_model_object();
721
        $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
722
        return $prev_data_prep_value;
723
    }
724
725
726
    /**
727
     * @param array    $query_params
728
     * @param bool|int $prev_data_prep_value
729
     * @return EE_Base_Class[]|EE_Datetime[]
730
     * @throws EE_Error
731
     * @since   $VID:$
732
     */
733
    private function getDatetimesAndRestoreModel(array $query_params, $prev_data_prep_value)
734
    {
735
        $result = $this->get_all($query_params);
736
        $this->assume_values_already_prepared_by_model_object($prev_data_prep_value);
737
        return $result;
738
    }
739
740
741
    /**
742
     * @param array  $query_params
743
     * @param int    $limit
744
     * @param string $order_by
745
     * @param string $order
746
     * @return array
747
     * @since   $VID:$
748
     */
749
    private function addDefaultQueryParams(array $query_params, $limit = 0, $order_by = 'DTT_EVT_start', $order = 'ASC')
750
    {
751
        $query_params = $this->addOrderByQueryParams($query_params, $order_by, $order);
752
        $query_params = $this->addLimitQueryParams($query_params, $limit);
753
        return $query_params;
754
    }
755
756
757
    /**
758
     * @param array  $query_params
759
     * @param string $default_where_conditions
760
     * @return array
761
     * @since   $VID:$
762
     */
763
    private function addDefaultWhereConditions(
764
        array $query_params,
765
        $default_where_conditions = EEM_Base::default_where_conditions_none
766
    ) {
767
        $query_params['default_where_conditions'] = $default_where_conditions;
768
        return $query_params;
769
    }
770
771
772
    /**
773
     * @param array $where_params
774
     * @param bool  $include_deleted
775
     * @param bool  $include_expired
776
     * @return array
777
     * @since   $VID:$
778
     */
779
    private function addDefaultWhereParams(array $where_params, bool $include_deleted = true, bool $include_expired = true)
780
    {
781
        $where_params = $this->addExpiredWhereParams($where_params, $include_expired);
782
        $where_params = $this->addDeletedWhereParams($where_params, $include_deleted);
783
        return $where_params;
784
    }
785
786
787
    /**
788
     * @param array $where_params
789
     * @param bool  $include_deleted
790
     * @return array
791
     * @since   $VID:$
792
     */
793
    private function addDeletedWhereParams(array $where_params, bool $include_deleted = true)
794
    {
795
        $deleted                     = $include_deleted ? [true, false] : [false];
796
        $where_params['DTT_deleted'] = ['IN', $deleted];
797
        return $where_params;
798
    }
799
800
801
    /**
802
     * @param array $where_params
803
     * @param bool  $include_expired
804
     * @return array
805
     * @since   $VID:$
806
     */
807
    private function addExpiredWhereParams(array $where_params, bool $include_expired = true)
808
    {
809
        if (! $include_expired) {
810
            $where_params['DTT_EVT_end'] = ['>=', current_time('mysql', true)];
811
        }
812
        return $where_params;
813
    }
814
815
816
    /**
817
     * @param array $query_params
818
     * @param int   $limit
819
     * @return array
820
     * @since   $VID:$
821
     */
822
    private function addLimitQueryParams(array $query_params, $limit = 0)
823
    {
824
        if ($limit) {
825
            $query_params['limit'] = $limit;
826
        }
827
        return $query_params;
828
    }
829
830
831
    /**
832
     * @param array  $query_params
833
     * @param string $order_by
834
     * @param string $order
835
     * @return array
836
     * @since   $VID:$
837
     */
838
    private function addOrderByQueryParams(array $query_params, $order_by = 'DTT_EVT_start', $order = 'ASC')
839
    {
840
        $order                    = $order === 'ASC' ? 'ASC' : 'DESC';
841
        $valid_order_columns      = ['DTT_ID', 'DTT_EVT_start', 'DTT_EVT_end', 'DTT_order'];
842
        $order_by                 = in_array($order_by, $valid_order_columns, true) ? $order_by : 'DTT_EVT_start';
843
        $query_params['order_by'] = [$order_by => $order];
844
        return $query_params;
845
    }
846
}
847