Completed
Branch FET-10785-ee-system-loader (d67185)
by
unknown
106:46 queued 95:31
created

EEM_Registration::reg_statuses()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 0
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
1
<?php
2
use EventEspresso\core\exceptions\InvalidIdentifierException;
3
use EventEspresso\core\exceptions\InvalidStatusException;
4
use EventEspresso\core\services\database\TableAnalysis;
5
6
if (!defined('EVENT_ESPRESSO_VERSION')) {
7
    exit('No direct script access allowed');
8
}
9
10
11
/**
12
 * Registration Model
13
 *
14
 * @package    Event Espresso
15
 * @subpackage includes/models/
16
 * @author     Mike Nelson, Brent Christensen
17
 */
18
class EEM_Registration extends EEM_Soft_Delete_Base
19
{
20
21
    /**
22
     * @var EEM_Registration $_instance
23
     */
24
    protected static $_instance;
25
26
    /**
27
     * Keys are the status IDs for registrations (eg, RAP, RCN, etc), and the values
28
     * are status codes (eg, approved, cancelled, etc)
29
     *
30
     * @var array
31
     */
32
    private static $_reg_status;
33
34
    /**
35
     * The value of REG_count for a primary registrant
36
     */
37
    const PRIMARY_REGISTRANT_COUNT = 1;
38
39
    /**
40
     * Status ID (STS_ID on esp_status table) to indicate an INCOMPLETE registration.
41
     * Initial status for registrations when they are first created
42
     * Payments are NOT allowed.
43
     * Automatically toggled to whatever the default Event registration status is upon completion of the attendee
44
     * information reg step NO space reserved. Registration is NOT active
45
     */
46
    const status_id_incomplete = 'RIC';
47
48
    /**
49
     * Status ID (STS_ID on esp_status table) to indicate an UNAPPROVED registration.
50
     * Payments are NOT allowed.
51
     * Event Admin must manually toggle STS_ID for it to change
52
     * No space reserved.
53
     * Registration is active
54
     */
55
    const status_id_not_approved = 'RNA';
56
57
    /**
58
     * Status ID (STS_ID on esp_status table) to indicate registration is PENDING_PAYMENT .
59
     * Payments are allowed.
60
     * STS_ID will automatically be toggled to RAP if payment is made in full by the attendee
61
     * No space reserved.
62
     * Registration is active
63
     */
64
    const status_id_pending_payment = 'RPP';
65
66
    /**
67
     * Status ID (STS_ID on esp_status table) to indicate registration is on the WAIT_LIST .
68
     * Payments are allowed.
69
     * STS_ID will automatically be toggled to RAP if payment is made in full by the attendee
70
     * No space reserved.
71
     * Registration is active
72
     */
73
    const status_id_wait_list = 'RWL';
74
75
    /**
76
     * Status ID (STS_ID on esp_status table) to indicate an APPROVED registration.
77
     * the TXN may or may not be completed ( paid in full )
78
     * Payments are allowed.
79
     * A space IS reserved.
80
     * Registration is active
81
     */
82
    const status_id_approved = 'RAP';
83
84
    /**
85
     * Status ID (STS_ID on esp_status table) to indicate a registration was CANCELLED by the attendee.
86
     * Payments are NOT allowed.
87
     * NO space reserved.
88
     * Registration is NOT active
89
     */
90
    const status_id_cancelled = 'RCN';
91
92
    /**
93
     * Status ID (STS_ID on esp_status table) to indicate a registration was DECLINED by the Event Admin
94
     * Payments are NOT allowed.
95
     * No space reserved.
96
     * Registration is NOT active
97
     */
98
    const status_id_declined = 'RDC';
99
100
    /**
101
     * @var TableAnalysis $table_analysis
102
     */
103
    protected $_table_analysis;
104
105
106
    /**
107
     *    private constructor to prevent direct creation
108
     *
109
     * @Constructor
110
     * @access protected
111
     * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any
112
     *                         incoming timezone data that gets saved). Note this just sends the timezone info to the
113
     *                         date time model field objects.  Default is NULL (and will be assumed using the set
114
     *                         timezone in the 'timezone_string' wp option)
115
     * @throws EE_Error
116
     */
117
    protected function __construct($timezone = null)
118
    {
119
        $this->_table_analysis = EE_Registry::instance()->create('TableAnalysis', array(), true);
120
        $this->singular_item = esc_html__('Registration', 'event_espresso');
121
        $this->plural_item = esc_html__('Registrations', 'event_espresso');
122
        $this->_tables = array(
123
            'Registration' => new EE_Primary_Table('esp_registration', 'REG_ID'),
124
        );
125
        $this->_fields = array(
126
            'Registration' => array(
127
                'REG_ID' => new EE_Primary_Key_Int_Field(
128
                    'REG_ID',
129
                    esc_html__('Registration ID', 'event_espresso')
130
                ),
131
                'EVT_ID' => new EE_Foreign_Key_Int_Field(
132
                    'EVT_ID',
133
                    esc_html__('Event ID', 'event_espresso'),
134
                    false,
135
                    0,
136
                    'Event'
137
                ),
138
                'ATT_ID' => new EE_Foreign_Key_Int_Field(
139
                    'ATT_ID',
140
                    esc_html__('Attendee ID', 'event_espresso'),
141
                    false,
142
                    0,
143
                    'Attendee'
144
                ),
145
                'TXN_ID' => new EE_Foreign_Key_Int_Field(
146
                    'TXN_ID',
147
                    esc_html__('Transaction ID', 'event_espresso'),
148
                    false, 0, 'Transaction'
149
                ),
150
                'TKT_ID' => new EE_Foreign_Key_Int_Field(
151
                    'TKT_ID',
152
                    esc_html__('Ticket ID', 'event_espresso'),
153
                    false,
154
                    0, 'Ticket'
155
                ),
156
                'STS_ID' => new EE_Foreign_Key_String_Field(
157
                    'STS_ID',
158
                    esc_html__('Status ID', 'event_espresso'),
159
                    false,
160
                    EEM_Registration::status_id_incomplete,
161
                    'Status'
162
                ),
163
                'REG_date' => new EE_Datetime_Field(
164
                    'REG_date',
165
                    esc_html__('Time registration occurred', 'event_espresso'),
166
                    false,
167
                    EE_Datetime_Field::now,
168
                    $timezone
169
                ),
170
                'REG_final_price' => new EE_Money_Field(
171
                    'REG_final_price',
172
                    esc_html__('Registration\'s share of the transaction total', 'event_espresso'),
173
                    false,
174
                    0
175
                ),
176
                'REG_paid' => new EE_Money_Field(
177
                    'REG_paid',
178
                    esc_html__('Amount paid to date towards registration', 'event_espresso'),
179
                    false,
180
                    0
181
                ),
182
                'REG_session' => new EE_Plain_Text_Field(
183
                    'REG_session',
184
                    esc_html__('Session ID of registration', 'event_espresso'),
185
                    false,
186
                    ''
187
                ),
188
                'REG_code' => new EE_Plain_Text_Field(
189
                    'REG_code',
190
                    esc_html__('Unique Code for this registration', 'event_espresso'),
191
                    false,
192
                    ''
193
                ),
194
                'REG_url_link' => new EE_Plain_Text_Field(
195
                    'REG_url_link',
196
                    esc_html__('String to be used in URL for identifying registration', 'event_espresso'),
197
                    false,
198
                    ''
199
                ),
200
                'REG_count' => new EE_Integer_Field(
201
                    'REG_count',
202
                    esc_html__('Count of this registration in the group registration ', 'event_espresso'),
203
                    true,
204
                    1
205
                ),
206
                'REG_group_size' => new EE_Integer_Field(
207
                    'REG_group_size',
208
                    esc_html__('Number of registrations on this group', 'event_espresso'),
209
                    false,
210
                    1
211
                ),
212
                'REG_att_is_going' => new EE_Boolean_Field(
213
                    'REG_att_is_going',
214
                    esc_html__('Flag indicating the registrant plans on attending', 'event_espresso'),
215
                    false,
216
                    false
217
                ),
218
                'REG_deleted' => new EE_Trashed_Flag_Field(
219
                    'REG_deleted',
220
                    esc_html__('Flag indicating if registration has been archived or not.', 'event_espresso'),
221
                    false,
222
                    false
223
                ),
224
            ),
225
        );
226
        $this->_model_relations = array(
227
            'Event' => new EE_Belongs_To_Relation(),
228
            'Attendee' => new EE_Belongs_To_Relation(),
229
            'Transaction' => new EE_Belongs_To_Relation(),
230
            'Ticket' => new EE_Belongs_To_Relation(),
231
            'Status' => new EE_Belongs_To_Relation(),
232
            'Answer' => new EE_Has_Many_Relation(),
233
            'Checkin' => new EE_Has_Many_Relation(),
234
            'Registration_Payment' => new EE_Has_Many_Relation(),
235
            'Payment' => new EE_HABTM_Relation('Registration_Payment'),
236
            'Message' => new EE_Has_Many_Any_Relation(false)
237
            //allow deletes even if there are messages in the queue related
238
        );
239
        $this->_model_chain_to_wp_user = 'Event';
240
        parent::__construct($timezone);
241
    }
242
243
244
    /**
245
     * a list of ALL valid registration statuses currently in use within the system
246
     * generated by combining the filterable active and inactive reg status arrays
247
     *
248
     * @return array
249
     */
250
    public static function reg_statuses()
251
    {
252
        return array_unique(
253
            array_merge(
254
                EEM_Registration::active_reg_statuses(),
255
                EEM_Registration::inactive_reg_statuses()
256
            )
257
        );
258
    }
259
260
261
    /**
262
     * reg_statuses_that_allow_payment
263
     * a filterable list of registration statuses that allow a registrant to make a payment
264
     *
265
     * @access public
266
     * @return array
267
     */
268
    public static function reg_statuses_that_allow_payment()
269
    {
270
        return apply_filters(
271
            'FHEE__EEM_Registration__reg_statuses_that_allow_payment',
272
            array(
273
                EEM_Registration::status_id_approved,
274
                EEM_Registration::status_id_pending_payment,
275
            )
276
        );
277
    }
278
279
280
    /**
281
     * active_reg_statuses
282
     * a filterable list of registration statuses that are considered active
283
     *
284
     * @access public
285
     * @return array
286
     */
287
    public static function active_reg_statuses()
288
    {
289
        return apply_filters(
290
            'FHEE__EEM_Registration__active_reg_statuses',
291
            array(
292
                EEM_Registration::status_id_approved,
293
                EEM_Registration::status_id_pending_payment,
294
                EEM_Registration::status_id_wait_list,
295
                EEM_Registration::status_id_not_approved,
296
            )
297
        );
298
    }
299
300
301
    /**
302
     * inactive_reg_statuses
303
     * a filterable list of registration statuses that are not considered active
304
     *
305
     * @access public
306
     * @return array
307
     */
308
    public static function inactive_reg_statuses()
309
    {
310
        return apply_filters(
311
            'FHEE__EEM_Registration__inactive_reg_statuses',
312
            array(
313
                EEM_Registration::status_id_incomplete,
314
                EEM_Registration::status_id_cancelled,
315
                EEM_Registration::status_id_declined,
316
            )
317
        );
318
    }
319
320
321
    /**
322
     *    closed_reg_statuses
323
     *    a filterable list of registration statuses that are considered "closed"
324
     * meaning they should not be considered in any calculations involving monies owing
325
     *
326
     * @access public
327
     * @return array
328
     */
329
    public static function closed_reg_statuses()
330
    {
331
        return apply_filters(
332
            'FHEE__EEM_Registration__closed_reg_statuses',
333
            array(
334
                EEM_Registration::status_id_cancelled,
335
                EEM_Registration::status_id_declined,
336
                EEM_Registration::status_id_wait_list,
337
            )
338
        );
339
    }
340
341
342
    /**
343
     *        get list of registration statuses
344
     *
345
     * @access public
346
     * @param array $exclude The status ids to exclude from the returned results
347
     * @param bool $translated If true will return the values as singular localized strings
348
     * @return array
349
     * @throws EE_Error
350
     */
351
    public static function reg_status_array($exclude = array(), $translated = false)
352
    {
353
        EEM_Registration::instance()->_get_registration_status_array($exclude);
354
        return $translated
355
            ? EEM_Status::instance()->localized_status(self::$_reg_status, false, 'sentence')
356
            : self::$_reg_status;
357
    }
358
359
360
    /**
361
     *    get list of registration statuses
362
     *
363
     * @access private
364
     * @param array $exclude
365
     * @return void
366
     * @throws EE_Error
367
     */
368
    private function _get_registration_status_array($exclude = array())
369
    {
370
        //in the very rare circumstance that we are deleting a model's table's data
371
        //and the table hasn't actually been created, this could have an error
372
        /** @type WPDB $wpdb */
373
        global $wpdb;
374
        if ($this->_get_table_analysis()->tableExists($wpdb->prefix . 'esp_status')) {
375
            $results = $wpdb->get_results(
376
                "SELECT STS_ID, STS_code FROM {$wpdb->prefix}esp_status WHERE STS_type = 'registration'"
377
            );
378
            self::$_reg_status = array();
379
            foreach ($results as $status) {
380
                if (!in_array($status->STS_ID, $exclude, true)) {
381
                    self::$_reg_status[$status->STS_ID] = $status->STS_code;
382
                }
383
            }
384
        }
385
    }
386
387
388
    /**
389
     * Gets the injected table analyzer, or throws an exception
390
     *
391
     * @return TableAnalysis
392
     * @throws EE_Error
393
     */
394 View Code Duplication
    protected function _get_table_analysis()
395
    {
396
        if ($this->_table_analysis instanceof TableAnalysis) {
397
            return $this->_table_analysis;
398
        }
399
        throw new EE_Error(
400
            sprintf(
401
                esc_html__('Table analysis class on class %1$s is not set properly.', 'event_espresso'),
402
                get_class($this)
403
            )
404
        );
405
    }
406
407
408
    /**
409
     * This returns a wpdb->results array of all registration date month and years matching the incoming query params
410
     * and grouped by month and year.
411
     *
412
     * @param  array $where_params Array of query_params as described in the comments for EEM_Base::get_all()
413
     * @return array
414
     * @throws EE_Error
415
     */
416
    public function get_reg_months_and_years($where_params)
417
    {
418
        $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...
419
        $query_params['group_by'] = array('reg_year', 'reg_month');
420
        $query_params['order_by'] = array('REG_date' => 'DESC');
421
        $columns_to_select = array(
422
            'reg_year' => array('YEAR(REG_date)', '%s'),
423
            'reg_month' => array('MONTHNAME(REG_date)', '%s'),
424
        );
425
        return $this->_get_all_wpdb_results($query_params, OBJECT, $columns_to_select);
426
    }
427
428
429
    /**
430
     * retrieve ALL registrations for a particular Attendee from db
431
     *
432
     * @param int $ATT_ID
433
     * @return EE_Base_Class[]|EE_Registration[]|null
434
     * @throws EE_Error
435
     */
436
    public function get_all_registrations_for_attendee($ATT_ID = 0)
437
    {
438
        if (!$ATT_ID) {
439
            return null;
440
        }
441
        return $this->get_all(array(array('ATT_ID' => $ATT_ID)));
442
    }
443
444
445
    /**
446
     * Gets a registration given their REG_url_link. Yes, this should usually
447
     * be passed via a GET parameter.
448
     *
449
     * @param string $REG_url_link
450
     * @return EE_Base_Class|EE_Registration|null
451
     * @throws EE_Error
452
     */
453
    public function get_registration_for_reg_url_link($REG_url_link)
454
    {
455
        if (!$REG_url_link) {
456
            return null;
457
        }
458
        return $this->get_one(array(array('REG_url_link' => $REG_url_link)));
459
    }
460
461
462
    /**
463
     *        retrieve registration for a specific transaction attendee from db
464
     *
465
     * @access        public
466
     * @param    int $TXN_ID
467
     * @param    int $ATT_ID
468
     * @param    int $att_nmbr in case the ATT_ID is the same for multiple registrations (same details used) then the
469
     *                         attendee number is required
470
     * @return        mixed        array on success, FALSE on fail
471
     * @throws EE_Error
472
     */
473
    public function get_registration_for_transaction_attendee($TXN_ID = 0, $ATT_ID = 0, $att_nmbr = 0)
474
    {
475
        return $this->get_one(array(
476
            array(
477
                'TXN_ID' => $TXN_ID,
478
                'ATT_ID' => $ATT_ID,
479
            ),
480
            'limit' => array(min($att_nmbr - 1, 0), 1),
481
        ));
482
    }
483
484
485
    /**
486
     *        get the number of registrations per day  for the Registration Admin page Reports Tab.
487
     *        (doesn't utilize models because it's a fairly specialized query)
488
     *
489
     * @access        public
490
     * @param $period string which can be passed to php's strtotime function (eg "-1 month")
491
     * @return stdClass[] with properties regDate and total
492
     * @throws EE_Error
493
     */
494
    public function get_registrations_per_day_report($period = '-1 month')
495
    {
496
        $sql_date = $this->convert_datetime_for_query('REG_date', date('Y-m-d H:i:s', strtotime($period)),
497
            'Y-m-d H:i:s', 'UTC');
498
        $where = array(
499
            'REG_date' => array('>=', $sql_date),
500
            'STS_ID' => array('!=', EEM_Registration::status_id_incomplete),
501
        );
502
        if (!EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_day_report')) {
503
            $where['Event.EVT_wp_user'] = get_current_user_id();
504
        }
505
        $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'REG_date');
506
        $results = $this->_get_all_wpdb_results(
507
            array(
508
                $where,
509
                'group_by' => 'regDate',
510
                'order_by' => array('REG_date' => 'ASC'),
511
            ),
512
            OBJECT,
513
            array(
514
                'regDate' => array('DATE(' . $query_interval . ')', '%s'),
515
                'total' => array('count(REG_ID)', '%d'),
516
            ));
517
        return $results;
518
    }
519
520
521
    /**
522
     * Get the number of registrations per day including the count of registrations for each Registration Status.
523
     * Note: EEM_Registration::status_id_incomplete registrations are excluded from the results.
524
     *
525
     * @param string $period
526
     * @return stdClass[] with properties Registration_REG_date and a column for each registration status as the STS_ID
527
     * @throws EE_Error
528
     *                    (i.e. RAP)
529
     */
530 View Code Duplication
    public function get_registrations_per_day_and_per_status_report($period = '-1 month')
531
    {
532
        global $wpdb;
533
        $registration_table = $wpdb->prefix . 'esp_registration';
534
        $event_table = $wpdb->posts;
535
        $sql_date = date('Y-m-d H:i:s', strtotime($period));
536
        //prepare the query interval for displaying offset
537
        $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'dates.REG_date');
538
        //inner date query
539
        $inner_date_query = "SELECT DISTINCT REG_date from {$registration_table} ";
540
        $inner_where = ' WHERE';
541
        //exclude events not authored by user if permissions in effect
542
        if (!EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) {
543
            $inner_date_query .= "LEFT JOIN {$event_table} ON ID = EVT_ID";
544
            $inner_where .= ' post_author = ' . get_current_user_id() . ' AND';
545
        }
546
        $inner_where .= " REG_date >= '{$sql_date}'";
547
        $inner_date_query .= $inner_where;
548
        //start main query
549
        $select = "SELECT DATE({$query_interval}) as Registration_REG_date, ";
550
        $join = '';
551
        $join_parts = array();
552
        $select_parts = array();
553
        //loop through registration stati to do parts for each status.
554
        foreach (EEM_Registration::reg_status_array() as $STS_ID => $STS_code) {
555
            if ($STS_ID === EEM_Registration::status_id_incomplete) {
556
                continue;
557
            }
558
            $select_parts[] = "COUNT({$STS_code}.REG_ID) as {$STS_ID}";
559
            $join_parts[] = "{$registration_table} AS {$STS_code} ON {$STS_code}.REG_date = dates.REG_date AND {$STS_code}.STS_ID = '{$STS_ID}'";
560
        }
561
        //setup the selects
562
        $select .= implode(', ', $select_parts);
563
        $select .= " FROM ($inner_date_query) AS dates LEFT JOIN ";
564
        //setup the joins
565
        $join .= implode(' LEFT JOIN ', $join_parts);
566
        //now let's put it all together
567
        $query = $select . $join . ' GROUP BY Registration_REG_date';
568
        //and execute it
569
        return $wpdb->get_results($query, ARRAY_A);
570
    }
571
572
573
    /**
574
     *        get the number of registrations per event  for the Registration Admin page Reports Tab
575
     *
576
     * @access        public
577
     * @param $period string which can be passed to php's strtotime function (eg "-1 month")
578
     * @return stdClass[] each with properties event_name, reg_limit, and total
579
     * @throws EE_Error
580
     */
581
    public function get_registrations_per_event_report($period = '-1 month')
582
    {
583
        $date_sql = $this->convert_datetime_for_query('REG_date', date('Y-m-d H:i:s', strtotime($period)),
584
            'Y-m-d H:i:s', 'UTC');
585
        $where = array(
586
            'REG_date' => array('>=', $date_sql),
587
            'STS_ID' => array('!=', EEM_Registration::status_id_incomplete),
588
        );
589
        if (
590
        !EE_Registry::instance()->CAP->current_user_can(
591
            'ee_read_others_registrations',
592
            'reg_per_event_report'
593
        )
594
        ) {
595
            $where['Event.EVT_wp_user'] = get_current_user_id();
596
        }
597
        $results = $this->_get_all_wpdb_results(array(
598
            $where,
599
            'group_by' => 'Event.EVT_name',
600
            'order_by' => 'Event.EVT_name',
601
            'limit' => array(0, 24),
602
        ),
603
            OBJECT,
604
            array(
605
                'event_name' => array('Event_CPT.post_title', '%s'),
606
                'total' => array('COUNT(REG_ID)', '%s'),
607
            )
608
        );
609
        return $results;
610
    }
611
612
613
    /**
614
     * Get the number of registrations per event grouped by registration status.
615
     * Note: EEM_Registration::status_id_incomplete registrations are excluded from the results.
616
     *
617
     * @param string $period
618
     * @return stdClass[] with properties `Registration_Event` and a column for each registration status as the STS_ID
619
     * @throws EE_Error
620
     *                    (i.e. RAP)
621
     */
622 View Code Duplication
    public function get_registrations_per_event_and_per_status_report($period = '-1 month')
623
    {
624
        global $wpdb;
625
        $registration_table = $wpdb->prefix . 'esp_registration';
626
        $event_table = $wpdb->posts;
627
        $sql_date = date('Y-m-d H:i:s', strtotime($period));
628
        //inner date query
629
        $inner_date_query = "SELECT DISTINCT EVT_ID, REG_date from $registration_table ";
630
        $inner_where = ' WHERE';
631
        //exclude events not authored by user if permissions in effect
632
        if (!EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) {
633
            $inner_date_query .= "LEFT JOIN {$event_table} ON ID = EVT_ID";
634
            $inner_where .= ' post_author = ' . get_current_user_id() . ' AND';
635
        }
636
        $inner_where .= " REG_date >= '{$sql_date}'";
637
        $inner_date_query .= $inner_where;
638
        //build main query
639
        $select = 'SELECT Event.post_title as Registration_Event, ';
640
        $join = '';
641
        $join_parts = array();
642
        $select_parts = array();
643
        //loop through registration stati to do parts for each status.
644
        foreach (EEM_Registration::reg_status_array() as $STS_ID => $STS_code) {
645
            if ($STS_ID === EEM_Registration::status_id_incomplete) {
646
                continue;
647
            }
648
            $select_parts[] = "COUNT({$STS_code}.REG_ID) as {$STS_ID}";
649
            $join_parts[] = "{$registration_table} AS {$STS_code} ON {$STS_code}.EVT_ID = dates.EVT_ID AND {$STS_code}.STS_ID = '{$STS_ID}' AND {$STS_code}.REG_date = dates.REG_date";
650
        }
651
        //setup the selects
652
        $select .= implode(', ', $select_parts);
653
        $select .= " FROM ($inner_date_query) AS dates LEFT JOIN $event_table as Event ON Event.ID = dates.EVT_ID LEFT JOIN ";
654
        //setup remaining joins
655
        $join .= implode(' LEFT JOIN ', $join_parts);
656
        //now put it all together
657
        $query = $select . $join . ' GROUP BY Registration_Event';
658
        //and execute
659
        return $wpdb->get_results($query, ARRAY_A);
660
    }
661
662
663
    /**
664
     * Returns the EE_Registration of the primary attendee on the transaction id provided
665
     *
666
     * @param int $TXN_ID
667
     * @return EE_Base_Class|EE_Registration|null
668
     * @throws EE_Error
669
     */
670
    public function get_primary_registration_for_transaction_ID($TXN_ID = 0)
671
    {
672
        if (!$TXN_ID) {
673
            return null;
674
        }
675
        return $this->get_one(array(
676
            array(
677
                'TXN_ID' => $TXN_ID,
678
                'REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT,
679
            ),
680
        ));
681
    }
682
683
684
    /**
685
     *        get_event_registration_count
686
     *
687
     * @access public
688
     * @param int $EVT_ID
689
     * @param boolean $for_incomplete_payments
690
     * @return int
691
     * @throws EE_Error
692
     */
693
    public function get_event_registration_count($EVT_ID, $for_incomplete_payments = false)
694
    {
695
        // we only count approved registrations towards registration limits
696
        $query_params = array(array('EVT_ID' => $EVT_ID, 'STS_ID' => self::status_id_approved));
697
        if ($for_incomplete_payments) {
698
            $query_params[0]['Transaction.STS_ID'] = array('!=', EEM_Transaction::complete_status_code);
699
        }
700
        return $this->count($query_params);
701
    }
702
703
704
    /**
705
     * Deletes all registrations with no transactions. Note that this needs to be very efficient
706
     * and so it uses wpdb directly
707
     *
708
     * @global WPDB $wpdb
709
     * @return int number deleted
710
     * @throws EE_Error
711
     */
712
    public function delete_registrations_with_no_transaction()
713
    {
714
        /** @type WPDB $wpdb */
715
        global $wpdb;
716
        return $wpdb->query(
717
            'DELETE r FROM '
718
            . $this->table()
719
            . ' r LEFT JOIN '
720
            . EEM_Transaction::instance()->table()
721
            . ' t ON r.TXN_ID = t.TXN_ID WHERE t.TXN_ID IS NULL');
722
    }
723
724
725
    /**
726
     *  Count registrations checked into (or out of) a datetime
727
     *
728
     * @param int $DTT_ID datetime ID
729
     * @param boolean $checked_in whether to count registrations checked IN or OUT
730
     * @return int
731
     * @throws EE_Error
732
     */
733
    public function count_registrations_checked_into_datetime($DTT_ID, $checked_in = true)
734
    {
735
        global $wpdb;
736
        //subquery to get latest checkin
737
        $query = $wpdb->prepare(
738
            'SELECT '
739
            . 'COUNT( DISTINCT checkins.REG_ID ) '
740
            . 'FROM ' . EEM_Checkin::instance()->table() . ' AS checkins INNER JOIN'
741
            . '( SELECT '
742
            . 'max( CHK_timestamp ) AS latest_checkin, '
743
            . 'REG_ID AS REG_ID '
744
            . 'FROM ' . EEM_Checkin::instance()->table() . ' '
745
            . 'WHERE DTT_ID=%d '
746
            . 'GROUP BY REG_ID'
747
            . ') AS most_recent_checkin_per_reg '
748
            . 'ON checkins.REG_ID=most_recent_checkin_per_reg.REG_ID '
749
            . 'AND checkins.CHK_timestamp = most_recent_checkin_per_reg.latest_checkin '
750
            . 'WHERE '
751
            . 'checkins.CHK_in=%d',
752
            $DTT_ID,
753
            $checked_in
754
        );
755
        return (int)$wpdb->get_var($query);
756
    }
757
758
759
    /**
760
     *  Count registrations checked into (or out of) an event.
761
     *
762
     * @param int $EVT_ID event ID
763
     * @param boolean $checked_in whether to count registrations checked IN or OUT
764
     * @return int
765
     * @throws EE_Error
766
     */
767
    public function count_registrations_checked_into_event($EVT_ID, $checked_in = true)
768
    {
769
        global $wpdb;
770
        //subquery to get latest checkin
771
        $query = $wpdb->prepare(
772
            'SELECT '
773
            . 'COUNT( DISTINCT checkins.REG_ID ) '
774
            . 'FROM ' . EEM_Checkin::instance()->table() . ' AS checkins INNER JOIN'
775
            . '( SELECT '
776
            . 'max( CHK_timestamp ) AS latest_checkin, '
777
            . 'REG_ID AS REG_ID '
778
            . 'FROM ' . EEM_Checkin::instance()->table() . ' AS c '
779
            . 'INNER JOIN ' . EEM_Datetime::instance()->table() . ' AS d '
780
            . 'ON c.DTT_ID=d.DTT_ID '
781
            . 'WHERE d.EVT_ID=%d '
782
            . 'GROUP BY REG_ID'
783
            . ') AS most_recent_checkin_per_reg '
784
            . 'ON checkins.REG_ID=most_recent_checkin_per_reg.REG_ID '
785
            . 'AND checkins.CHK_timestamp = most_recent_checkin_per_reg.latest_checkin '
786
            . 'WHERE '
787
            . 'checkins.CHK_in=%d',
788
            $EVT_ID,
789
            $checked_in
790
        );
791
        return (int)$wpdb->get_var($query);
792
    }
793
794
795
    /**
796
     * The purpose of this method is to retrieve an array of
797
     * EE_Registration objects that represent the latest registration
798
     * for each ATT_ID given in the function argument.
799
     *
800
     * @param array $attendee_ids
801
     * @return EE_Base_Class[]|EE_Registration[]
802
     * @throws EE_Error
803
     */
804
    public function get_latest_registration_for_each_of_given_contacts($attendee_ids = array())
805
    {
806
        //first do a native wp_query to get the latest REG_ID's matching these attendees.
807
        global $wpdb;
808
        $registration_table = $wpdb->prefix . 'esp_registration';
809
        $attendee_table = $wpdb->posts;
810
        $attendee_ids = is_array($attendee_ids)
811
            ? array_map('absint', $attendee_ids)
812
            : array((int)$attendee_ids);
813
        $ATT_IDs = implode(',', $attendee_ids);
814
        // first we do a query to get the registration ids
815
        // (because a group by before order by causes the order by to be ignored.)
816
        $registration_id_query = "
817
			SELECT registrations.registration_ids as registration_id
818
			FROM (
819
				SELECT
820
					Attendee.ID as attendee_ids,
821
					Registration.REG_ID as registration_ids
822
				FROM {$registration_table} AS Registration
823
				JOIN {$attendee_table} AS Attendee
824
					ON Registration.ATT_ID = Attendee.ID
825
					AND Attendee.ID IN ( {$ATT_IDs} )
826
				ORDER BY Registration.REG_ID DESC
827
			  ) AS registrations
828
			  GROUP BY registrations.attendee_ids
829
		";
830
        $registration_ids = $wpdb->get_results($registration_id_query, ARRAY_A);
831
        if (empty($registration_ids)) {
832
            return array();
833
        }
834
        $ids_for_model_query = array();
835
        //let's flatten the ids so they can be used in the model query.
836
        foreach ($registration_ids as $registration_id) {
837
            if (isset($registration_id['registration_id'])) {
838
                $ids_for_model_query[] = $registration_id['registration_id'];
839
            }
840
        }
841
        //construct query
842
        $_where = array(
843
            'REG_ID' => array('IN', $ids_for_model_query),
844
        );
845
        return $this->get_all(array($_where));
846
    }
847
848
849
850
    /**
851
     * returns a count of registrations for the supplied event having the status as specified
852
     *
853
     * @param int $EVT_ID
854
     * @param array $statuses
855
     * @return int
856
     * @throws InvalidArgumentException
857
     * @throws InvalidStatusException
858
     * @throws EE_Error
859
     */
860
    public function event_reg_count_for_statuses($EVT_ID, $statuses = array() )
861
    {
862
        $EVT_ID = absint($EVT_ID);
863
        if (! $EVT_ID) {
864
            throw new InvalidArgumentException(
865
                esc_html__('An invalid Event ID was supplied.', 'event_espresso')
866
            );
867
        }
868
        $statuses = is_array($statuses) ? $statuses : array($statuses);
869
        $statuses = ! empty($statuses) ? $statuses : array(EEM_Registration::status_id_approved);
870
        $valid_reg_statuses = EEM_Registration::reg_statuses();
871
        foreach ($statuses as $status) {
872
            if(! in_array($status, $valid_reg_statuses, true)) {
873
                throw new InvalidStatusException($status, esc_html__('Registration', 'event_espresso'));
874
            }
875
        }
876
        return $this->count(
877
            array(
878
                array(
879
                    'EVT_ID' => $EVT_ID,
880
                    'STS_ID' => array('IN', $statuses),
881
                ),
882
            ),
883
            'REG_ID',
884
            true
885
        );
886
    }
887
888
}
889
// End of file EEM_Registration.model.php
890
// Location: /includes/models/EEM_Registration.model.php
891