Completed
Branch FET-3467-waitlists (f9ed0c)
by
unknown
90:26 queued 78:09
created

EEM_Registration   F

Complexity

Total Complexity 46

Size/Duplication

Total Lines 820
Duplicated Lines 13.78 %

Coupling/Cohesion

Components 3
Dependencies 25

Importance

Changes 0
Metric Value
dl 113
loc 820
rs 3
c 0
b 0
f 0
wmc 46
lcom 3
cbo 25

24 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 75 1
A reg_statuses() 0 15 1
A reg_statuses_that_allow_payment() 0 10 1
A active_reg_statuses() 0 12 1
A inactive_reg_statuses() 0 11 1
A closed_reg_statuses() 0 11 1
A reg_status_array() 0 6 2
A _get_registration_status_array() 0 18 4
A _get_table_analysis() 12 13 2
A get_reg_months_and_years() 0 11 1
A get_all_registrations_for_attendee() 0 7 2
A get_registration_for_reg_url_link() 0 7 2
A get_registration_for_transaction_attendee() 0 10 1
B get_registrations_per_day_report() 0 25 2
B get_registrations_per_day_and_per_status_report() 42 42 4
B get_registrations_per_event_report() 0 25 2
B get_registrations_per_event_and_per_status_report() 40 40 4
A get_primary_registration_for_transaction_ID() 0 12 2
A get_event_registration_count() 0 9 2
A delete_registrations_with_no_transaction() 0 11 1
B count_registrations_checked_into_datetime() 0 24 1
B count_registrations_checked_into_event() 0 26 1
B get_latest_registration_for_each_of_given_contacts() 0 43 5
A event_reg_count_for_status() 0 20 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like EEM_Registration often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EEM_Registration, and based on these observations, apply Extract Interface, too.

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