Completed
Branch BUG-10144-query-quotes (e5d611)
by
unknown
37:22 queued 18:36
created

EEM_Registration::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 75
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 53
nc 1
nop 1
dl 0
loc 75
rs 9
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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(
0 ignored issues
show
Documentation Bug introduced by
It seems like array('Registration' => ...gistration', 'REG_ID')) of type array<string,object<EE_P...ct<EE_Primary_Table>"}> is incompatible with the declared type array<integer,object<EE_Table_Base>> of property $_tables.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
120
            'Registration' => new EE_Primary_Table('esp_registration', 'REG_ID'),
121
        );
122
        $this->_fields = array(
0 ignored issues
show
Documentation Bug introduced by
It seems like array('Registration' => ...esso'), false, false))) of type array<string,array<strin...shed_Flag_Field>\"}>"}> is incompatible with the declared type array<integer,object<EE_Model_Field_Base>> of property $_fields.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
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(
0 ignored issues
show
Documentation Bug introduced by
It seems like array('Event' => new \EE...ny_Any_Relation(false)) of type array<string,object<EE_B...s_Many_Any_Relation>"}> is incompatible with the declared type array<integer,object<EE_Model_Relation_Base>> of property $_model_relations.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
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'),
0 ignored issues
show
Documentation introduced by
'Registration_Payment' is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
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);
0 ignored issues
show
Bug introduced by
It seems like $timezone defined by parameter $timezone on line 114 can also be of type string; however, EEM_Soft_Delete_Base::__construct() does only seem to accept null, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
188
    }
189
190
191
192
    /**
193
     * reg_statuses_that_allow_payment
194
     * a filterable list of registration statuses that allow a registrant to make a payment
195
     *
196
     * @access public
197
     * @return array
198
     */
199
    public static function reg_statuses_that_allow_payment()
200
    {
201
        return apply_filters('FHEE__EEM_Registration__reg_statuses_that_allow_payment', array(
202
            EEM_Registration::status_id_approved,
203
            EEM_Registration::status_id_pending_payment,
204
            EEM_Registration::status_id_wait_list,
205
        ));
206
    }
207
208
209
210
    /**
211
     * inactive_reg_statuses
212
     * a filterable list of registration statuses that are considered active
213
     *
214
     * @access public
215
     * @return array
216
     */
217
    public static function active_reg_statuses()
218
    {
219
        return apply_filters('FHEE__EEM_Registration__reg_statuses_that_allow_payment', array(
220
            EEM_Registration::status_id_approved,
221
            EEM_Registration::status_id_pending_payment,
222
            EEM_Registration::status_id_wait_list,
223
            EEM_Registration::status_id_not_approved,
224
        ));
225
    }
226
227
228
229
    /**
230
     * inactive_reg_statuses
231
     * a filterable list of registration statuses that are not considered active
232
     *
233
     * @access public
234
     * @return array
235
     */
236
    public static function inactive_reg_statuses()
237
    {
238
        return apply_filters('FHEE__EEM_Registration__reg_statuses_that_allow_payment', array(
239
            EEM_Registration::status_id_incomplete,
240
            EEM_Registration::status_id_cancelled,
241
            EEM_Registration::status_id_declined,
242
        ));
243
    }
244
245
246
247
    /**
248
     *    closed_reg_statuses
249
     *    a filterable list of registration statuses that are considered "closed"
250
     * meaning they should not be considered in any calculations involving monies owing
251
     *
252
     * @access public
253
     * @return array
254
     */
255
    public static function closed_reg_statuses()
256
    {
257
        return apply_filters('FHEE__EEM_Registration__closed_reg_statuses', array(
258
            EEM_Registration::status_id_cancelled,
259
            EEM_Registration::status_id_declined,
260
        ));
261
    }
262
263
264
265
    /**
266
     *        get list of registration statuses
267
     *
268
     * @access public
269
     * @param array $exclude    The status ids to exclude from the returned results
270
     * @param bool  $translated If true will return the values as singular localized strings
271
     * @return array
272
     */
273
    public static function reg_status_array($exclude = array(), $translated = false)
274
    {
275
        EEM_Registration::instance()->_get_registration_status_array($exclude);
276
        return $translated ? EEM_Status::instance()->localized_status(self::$_reg_status, false, 'sentence')
277
            : self::$_reg_status;
278
    }
279
280
281
282
    /**
283
     *    get list of registration statuses
284
     *
285
     * @access private
286
     * @param array $exclude
287
     * @return array
288
     */
289
    private function _get_registration_status_array($exclude = array())
290
    {
291
        //in the very rare circumstance that we are deleting a model's table's data
292
        //and the table hasn't actually been created, this could have an error
293
        /** @type WPDB $wpdb */
294
        global $wpdb;
295
        if ($this->_get_table_analysis()->tableExists($wpdb->prefix . 'esp_status')) {
296
            $results = $wpdb->get_results(
297
                "SELECT STS_ID, STS_code FROM {$wpdb->prefix}esp_status WHERE STS_type = 'registration'"
298
            );
299
            self::$_reg_status = array();
300
            foreach ($results as $status) {
301
                if ( ! in_array($status->STS_ID, $exclude)) {
302
                    self::$_reg_status[$status->STS_ID] = $status->STS_code;
303
                }
304
            }
305
        }
306
    }
307
308
309
310
    /**
311
     * Gets the injected table analyzer, or throws an exception
312
     *
313
     * @return TableAnalysis
314
     * @throws \EE_Error
315
     */
316 View Code Duplication
    protected function _get_table_analysis()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
317
    {
318
        if ($this->_table_analysis instanceof TableAnalysis) {
319
            return $this->_table_analysis;
320
        } else {
321
            throw new \EE_Error(sprintf(__('Table analysis class on class %1$s is not set properly.', 'event_espresso'),
322
                get_class($this)));
323
        }
324
    }
325
326
327
328
    /**
329
     * This returns a wpdb->results array of all registration date month and years matching the incoming query params
330
     * and grouped by month and year.
331
     *
332
     * @param  array $where_params Array of query_params as described in the comments for EEM_Base::get_all()
333
     * @return array
334
     * @throws \EE_Error
335
     */
336
    public function get_reg_months_and_years($where_params)
337
    {
338
        $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...
339
        $query_params['group_by'] = array('reg_year', 'reg_month');
340
        $query_params['order_by'] = array('REG_date' => 'DESC');
341
        $columns_to_select = array(
342
            'reg_year'  => array('YEAR(REG_date)', '%s'),
343
            'reg_month' => array('MONTHNAME(REG_date)', '%s'),
344
        );
345
        return $this->_get_all_wpdb_results($query_params, OBJECT, $columns_to_select);
346
    }
347
348
349
350
    /**
351
     *        retrieve ALL registrations for a particular Attendee from db
352
     *
353
     * @access        public
354
     * @param        int $ATT_ID
355
     * @return    EE_Registration[]
356
     */
357
    public function get_all_registrations_for_attendee($ATT_ID = 0)
358
    {
359
        if ( ! $ATT_ID) {
360
            return false;
361
        }
362
        return $this->get_all(array(array('ATT_ID' => $ATT_ID)));
363
    }
364
365
366
367
    /**
368
     * Gets a registration given their REG_url_link. Yes, this should usually
369
     * be passed via a GET parameter.
370
     *
371
     * @param string $REG_url_link
372
     * @return EE_Registration
373
     */
374
    public function get_registration_for_reg_url_link($REG_url_link)
375
    {
376
        if ( ! $REG_url_link) {
377
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by EEM_Registration::get_re...ration_for_reg_url_link of type EE_Registration|null.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
378
        }
379
        return $this->get_one(array(array('REG_url_link' => $REG_url_link)));
380
    }
381
382
383
384
    /**
385
     *        retrieve registration for a specific transaction attendee from db
386
     *
387
     * @access        public
388
     * @param    int $TXN_ID
389
     * @param    int $ATT_ID
390
     * @param    int $att_nmbr in case the ATT_ID is the same for multiple registrations (same details used) then the
391
     *                         attendee number is required
392
     * @return        mixed        array on success, FALSE on fail
393
     */
394
    public function get_registration_for_transaction_attendee($TXN_ID = 0, $ATT_ID = 0, $att_nmbr = 0)
395
    {
396
        return $this->get_one(array(
397
            array(
398
                'TXN_ID' => $TXN_ID,
399
                'ATT_ID' => $ATT_ID,
400
            ),
401
            'limit' => array(min(($att_nmbr - 1), 0), 1),
402
        ));
403
    }
404
405
406
407
    /**
408
     *        get the number of registrations per day  for the Registration Admin page Reports Tab.
409
     *        (doesn't utilize models because it's a fairly specialized query)
410
     *
411
     * @access        public
412
     * @param $period string which can be passed to php's strtotime function (eg "-1 month")
413
     * @return stdClass[] with properties regDate and total
414
     */
415
    public function get_registrations_per_day_report($period = '-1 month')
416
    {
417
        $sql_date = $this->convert_datetime_for_query('REG_date', date("Y-m-d H:i:s", strtotime($period)),
418
            'Y-m-d H:i:s', 'UTC');
419
        $where = array(
420
            'REG_date' => array('>=', $sql_date),
421
            'STS_ID'   => array('!=', EEM_Registration::status_id_incomplete),
422
        );
423
        if ( ! EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_day_report')) {
424
            $where['Event.EVT_wp_user'] = get_current_user_id();
425
        }
426
        $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'REG_date');
427
        $results = $this->_get_all_wpdb_results(array(
428
            $where,
429
            'group_by' => 'regDate',
430
            'order_by' => array('REG_date' => 'ASC'),
431
        ), OBJECT, array(
432
            'regDate' => array('DATE(' . $query_interval . ')', '%s'),
433
            'total'   => array('count(REG_ID)', '%d'),
434
        ));
435
        return $results;
436
    }
437
438
439
440
    /**
441
     * Get the number of registrations per day including the count of registrations for each Registration Status.
442
     * Note: EEM_Registration::status_id_incomplete registrations are excluded from the results.
443
     *
444
     * @param string $period
445
     * @return stdClass[] with properties Registration_REG_date and a column for each registration status as the STS_ID
446
     *                    (i.e. RAP)
447
     */
448 View Code Duplication
    public function get_registrations_per_day_and_per_status_report($period = '-1 month')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
449
    {
450
        global $wpdb;
451
        $registration_table = $wpdb->prefix . 'esp_registration';
452
        $event_table = $wpdb->posts;
453
        $sql_date = date("Y-m-d H:i:s", strtotime($period));
454
        //prepare the query interval for displaying offset
455
        $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'dates.REG_date');
456
        //inner date query
457
        $inner_date_query = "SELECT DISTINCT REG_date from $registration_table ";
458
        $inner_where = " WHERE";
459
        //exclude events not authored by user if permissions in effect
460
        if ( ! EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) {
461
            $inner_date_query .= "LEFT JOIN $event_table ON ID = EVT_ID";
462
            $inner_where .= " post_author = " . get_current_user_id() . " AND";
463
        }
464
        $inner_where .= " REG_date >= '$sql_date'";
465
        $inner_date_query .= $inner_where;
466
        //start main query
467
        $select = "SELECT DATE($query_interval) as Registration_REG_date, ";
468
        $join = '';
469
        $join_parts = array();
470
        $select_parts = array();
471
        //loop through registration stati to do parts for each status.
472
        foreach (EEM_Registration::reg_status_array() as $STS_ID => $STS_code) {
473
            if ($STS_ID === EEM_Registration::status_id_incomplete) {
474
                continue;
475
            }
476
            $select_parts[] = "COUNT($STS_code.REG_ID) as $STS_ID";
477
            $join_parts[] = "$registration_table AS $STS_code ON $STS_code.REG_date = dates.REG_date AND $STS_code.STS_ID = '$STS_ID'";
478
        }
479
        //setup the selects
480
        $select .= implode(', ', $select_parts);
481
        $select .= " FROM ($inner_date_query) AS dates LEFT JOIN ";
482
        //setup the joins
483
        $join .= implode(" LEFT JOIN ", $join_parts);
484
        //now let's put it all together
485
        $query = $select . $join . ' GROUP BY Registration_REG_date';
486
        //and execute it
487
        $results = $wpdb->get_results($query, ARRAY_A);
488
        return $results;
489
    }
490
491
492
493
    /**
494
     *        get the number of registrations per event  for the Registration Admin page Reports Tab
495
     *
496
     * @access        public
497
     * @param $period string which can be passed to php's strtotime function (eg "-1 month")
498
     * @return stdClass[] each with properties event_name, reg_limit, and total
499
     */
500
    public function get_registrations_per_event_report($period = '-1 month')
501
    {
502
        $date_sql = $this->convert_datetime_for_query('REG_date', date("Y-m-d H:i:s", strtotime($period)),
503
            'Y-m-d H:i:s', 'UTC');
504
        $where = array(
505
            'REG_date' => array('>=', $date_sql),
506
            'STS_ID'   => array('!=', EEM_Registration::status_id_incomplete),
507
        );
508
        if ( ! EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) {
509
            $where['Event.EVT_wp_user'] = get_current_user_id();
510
        }
511
        $results = $this->_get_all_wpdb_results(array(
512
            $where,
513
            'group_by' => 'Event.EVT_name',
514
            'order_by' => 'Event.EVT_name',
515
            'limit'    => array(0, 24),
516
        ), OBJECT, array(
517
            'event_name' => array('Event_CPT.post_title', '%s'),
518
            'total'      => array('COUNT(REG_ID)', '%s'),
519
        ));
520
        return $results;
521
    }
522
523
524
525
    /**
526
     * Get the number of registrations per event grouped by registration status.
527
     * Note: EEM_Registration::status_id_incomplete registrations are excluded from the results.
528
     *
529
     * @param string $period
530
     * @return stdClass[] with properties `Registration_Event` and a column for each registration status as the STS_ID
531
     *                    (i.e. RAP)
532
     */
533 View Code Duplication
    public function get_registrations_per_event_and_per_status_report($period = '-1 month')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
534
    {
535
        global $wpdb;
536
        $registration_table = $wpdb->prefix . 'esp_registration';
537
        $event_table = $wpdb->posts;
538
        $sql_date = date("Y-m-d H:i:s", strtotime($period));
539
        //inner date query
540
        $inner_date_query = "SELECT DISTINCT EVT_ID, REG_date from $registration_table ";
541
        $inner_where = " WHERE";
542
        //exclude events not authored by user if permissions in effect
543
        if ( ! EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) {
544
            $inner_date_query .= "LEFT JOIN $event_table ON ID = EVT_ID";
545
            $inner_where .= " post_author = " . get_current_user_id() . " AND";
546
        }
547
        $inner_where .= " REG_date >= '$sql_date'";
548
        $inner_date_query .= $inner_where;
549
        //build main query
550
        $select = "SELECT Event.post_title as Registration_Event, ";
551
        $join = '';
552
        $join_parts = array();
553
        $select_parts = array();
554
        //loop through registration stati to do parts for each status.
555
        foreach (EEM_Registration::reg_status_array() as $STS_ID => $STS_code) {
556
            if ($STS_ID === EEM_Registration::status_id_incomplete) {
557
                continue;
558
            }
559
            $select_parts[] = "COUNT($STS_code.REG_ID) as $STS_ID";
560
            $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";
561
        }
562
        //setup the selects
563
        $select .= implode(', ', $select_parts);
564
        $select .= " FROM ($inner_date_query) AS dates LEFT JOIN $event_table as Event ON Event.ID = dates.EVT_ID LEFT JOIN ";
565
        //setup remaining joins
566
        $join .= implode(" LEFT JOIN ", $join_parts);
567
        //now put it all together
568
        $query = $select . $join . ' GROUP BY Registration_Event';
569
        //and execute
570
        $results = $wpdb->get_results($query, ARRAY_A);
571
        return $results;
572
    }
573
574
575
576
    /**
577
     * Returns the EE_Registration of the primary attendee on the transaction id provided
578
     *
579
     * @param int $TXN_ID
580
     * @return EE_Registration
581
     */
582
    public function get_primary_registration_for_transaction_ID($TXN_ID = 0)
583
    {
584
        if ( ! $TXN_ID) {
585
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by EEM_Registration::get_pr...tion_for_transaction_ID of type EE_Registration|null.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
586
        }
587
        return $this->get_one(array(
588
            array(
589
                'TXN_ID'    => $TXN_ID,
590
                'REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT,
591
            ),
592
        ));
593
    }
594
595
596
597
    /**
598
     *        get_event_registration_count
599
     *
600
     * @access public
601
     * @param int     $EVT_ID
602
     * @param boolean $for_incomplete_payments
603
     * @return int
604
     */
605
    public function get_event_registration_count($EVT_ID, $for_incomplete_payments = false)
606
    {
607
        // we only count approved registrations towards registration limits
608
        $query_params = array(array('EVT_ID' => $EVT_ID, 'STS_ID' => self::status_id_approved));
609
        if ($for_incomplete_payments) {
610
            $query_params[0]['Transaction.STS_ID'] = array('!=', EEM_Transaction::complete_status_code);
611
        }
612
        return $this->count($query_params);
613
    }
614
615
616
617
    /**
618
     * Deletes all registrations with no transactions. Note that this needs to be very efficient
619
     * and so it uses wpdb directly
620
     *
621
     * @global WPDB $wpdb
622
     * @return int number deleted
623
     */
624
    public function delete_registrations_with_no_transaction()
625
    {
626
        /** @type WPDB $wpdb */
627
        global $wpdb;
628
        return $wpdb->query('DELETE r FROM '
629
                            . $this->table()
630
                            . ' r LEFT JOIN '
631
                            . EEM_Transaction::instance()->table()
632
                            . ' t ON r.TXN_ID = t.TXN_ID WHERE t.TXN_ID IS NULL');
633
    }
634
635
636
637
    /**
638
     *  Count registrations checked into (or out of) a datetime
639
     *
640
     * @param int     $DTT_ID     datetime ID
641
     * @param boolean $checked_in whether to count registrations checked IN or OUT
642
     * @return int
643
     */
644
    public function count_registrations_checked_into_datetime($DTT_ID, $checked_in = true)
645
    {
646
        global $wpdb;
647
        //subquery to get latest checkin
648
        $query = $wpdb->prepare('SELECT '
649
                                . 'COUNT( DISTINCT checkins.REG_ID ) '
650
                                . 'FROM '
651
                                . EEM_Checkin::instance()
652
                                             ->table()
653
                                . ' AS checkins INNER JOIN'
654
                                . '( SELECT '
655
                                . 'max( CHK_timestamp ) AS latest_checkin, '
656
                                . 'REG_ID AS REG_ID '
657
                                . 'FROM '
658
                                . EEM_Checkin::instance()->table()
659
                                . ' '
660
                                . 'WHERE DTT_ID=%d '
661
                                . 'GROUP BY REG_ID'
662
                                . ') AS most_recent_checkin_per_reg '
663
                                . 'ON checkins.REG_ID=most_recent_checkin_per_reg.REG_ID '
664
                                . 'AND checkins.CHK_timestamp = most_recent_checkin_per_reg.latest_checkin '
665
                                . 'WHERE '
666
                                . 'checkins.CHK_in=%d', $DTT_ID, $checked_in);
667
        return (int)$wpdb->get_var($query);
668
    }
669
670
671
672
    /**
673
     *  Count registrations checked into (or out of) an event.
674
     *
675
     * @param int     $EVT_ID     event ID
676
     * @param boolean $checked_in whether to count registrations checked IN or OUT
677
     * @return int
678
     */
679
    public function count_registrations_checked_into_event($EVT_ID, $checked_in = true)
680
    {
681
        global $wpdb;
682
        //subquery to get latest checkin
683
        $query = $wpdb->prepare('SELECT '
684
                                . 'COUNT( DISTINCT checkins.REG_ID ) '
685
                                . 'FROM '
686
                                . EEM_Checkin::instance()
687
                                             ->table()
688
                                . ' AS checkins INNER JOIN'
689
                                . '( SELECT '
690
                                . 'max( CHK_timestamp ) AS latest_checkin, '
691
                                . 'REG_ID AS REG_ID '
692
                                . 'FROM '
693
                                . EEM_Checkin::instance()->table()
694
                                . ' AS c '
695
                                . 'INNER JOIN '
696
                                . EEM_Datetime::instance()->table()
697
                                . ' AS d '
698
                                . 'ON c.DTT_ID=d.DTT_ID '
699
                                . 'WHERE d.EVT_ID=%d '
700
                                . 'GROUP BY REG_ID'
701
                                . ') AS most_recent_checkin_per_reg '
702
                                . 'ON checkins.REG_ID=most_recent_checkin_per_reg.REG_ID '
703
                                . 'AND checkins.CHK_timestamp = most_recent_checkin_per_reg.latest_checkin '
704
                                . 'WHERE '
705
                                . 'checkins.CHK_in=%d', $EVT_ID, $checked_in);
706
        return (int)$wpdb->get_var($query);
707
    }
708
709
710
711
    /**
712
     * The purpose of this method is to retrieve an array of
713
     * EE_Registration objects that represent the latest registration
714
     * for each ATT_ID given in the function argument.
715
     *
716
     * @param array $attendee_ids
717
     * @return EE_Registration[]
718
     */
719
    public function get_latest_registration_for_each_of_given_contacts($attendee_ids = array())
720
    {
721
        //first do a native wp_query to get the latest REG_ID's matching these attendees.
722
        global $wpdb;
723
        $registration_table = $wpdb->prefix . 'esp_registration';
724
        $attendee_table = $wpdb->posts;
725
        $attendee_ids = is_array($attendee_ids) ? array_map('absint', $attendee_ids) : array((int)$attendee_ids);
726
        $attendee_ids = implode(',', $attendee_ids);
727
        //first we do a query to get the registration ids
728
        // (because a group by before order by causes the order by to be ignored.)
729
        $registration_id_query = "
730
			SELECT registrations.registration_ids as registration_id
731
			FROM (
732
				SELECT
733
					Attendee.ID as attendee_ids,
734
					Registration.REG_ID as registration_ids
735
				FROM $registration_table AS Registration
736
				JOIN $attendee_table AS Attendee
737
					ON Registration.ATT_ID = Attendee.ID
738
					AND Attendee.ID IN ( $attendee_ids )
739
				ORDER BY Registration.REG_ID DESC
740
			  ) AS registrations
741
			  GROUP BY registrations.attendee_ids
742
		";
743
        $registration_ids = $wpdb->get_results($registration_id_query, ARRAY_A);
744
        if (empty($registration_ids)) {
745
            return array();
746
        }
747
        $ids_for_model_query = array();
748
        //let's flatten the ids so they can be used in the model query.
749
        foreach ($registration_ids as $registration_id) {
750
            if (isset($registration_id['registration_id'])) {
751
                $ids_for_model_query[] = $registration_id['registration_id'];
752
            }
753
        }
754
        //construct query
755
        $_where = array(
756
            'REG_ID' => array('IN', $ids_for_model_query),
757
        );
758
        return $this->get_all(array($_where));
759
    }
760
761
762
763
}
764
// End of file EEM_Registration.model.php
765
// Location: /includes/models/EEM_Registration.model.php
766