Completed
Branch BUG-9962-improper-sprintf-usag... (604098)
by
unknown
51:51 queued 34:21
created

EEM_Registration::active_reg_statuses()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 8
nc 1
nop 0
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
1
<?php if ( ! defined('EVENT_ESPRESSO_VERSION')) exit('No direct script access allowed');
2
require_once ( EE_MODELS . 'EEM_Soft_Delete_Base.model.php' );
3
require_once ( EE_CLASSES . 'EE_Registration.class.php' );
4
/**
5
 *
6
 * Registration Model
7
 *
8
 * @package			Event Espresso
9
 * @subpackage		includes/models/
10
 * @author				Mike Nelson, Brent Christensen
11
 *
12
 * ------------------------------------------------------------------------
13
 */
14
class EEM_Registration extends EEM_Soft_Delete_Base {
15
16
  	// private instance of the Registration object
17
	protected static $_instance = NULL;
18
19
	/**
20
	 * Keys are the status IDs for registrations (eg, RAP, RCN, etc), and the values
21
	 * are status codes (eg, approved, cancelled, etc)
22
	 * @var array
23
	 */
24
	private static $_reg_status;
25
26
	/**
27
	 * The value of REG_count for a primary registrant
28
	 */
29
	const PRIMARY_REGISTRANT_COUNT = 1;
30
31
	/**
32
	 * Status ID (STS_ID on esp_status table) to indicate an INCOMPLETE registration.
33
	 * Initial status for registrations when they are first created
34
	 * Payments are NOT allowed.
35
	 * Automatically toggled to whatever the default Event registration status is upon completion of the attendee information reg step
36
	 * NO space reserved.
37
	 * Registration is NOT active
38
	 */
39
	const status_id_incomplete = 'RIC';
40
41
	/**
42
	 * Status ID (STS_ID on esp_status table) to indicate an UNAPPROVED registration.
43
	 * Payments are NOT allowed.
44
	 * Event Admin must manually toggle STS_ID for it to change
45
	 * No space reserved.
46
	 * Registration is active
47
	 */
48
	const status_id_not_approved = 'RNA';
49
50
	/**
51
	 * Status ID (STS_ID on esp_status table) to indicate registration is PENDING_PAYMENT .
52
	 * Payments are allowed.
53
	 * STS_ID will automatically be toggled to RAP if payment is made in full by the attendee
54
	 * No space reserved.
55
	 * Registration is active
56
	 */
57
	const status_id_pending_payment = 'RPP';
58
59
	/**
60
	 * Status ID (STS_ID on esp_status table) to indicate registration is on the WAIT_LIST .
61
	 * Payments are allowed.
62
	 * STS_ID will automatically be toggled to RAP if payment is made in full by the attendee
63
	 * No space reserved.
64
	 * Registration is active
65
	 */
66
	const status_id_wait_list = 'RWL';
67
68
	/**
69
	 * Status ID (STS_ID on esp_status table) to indicate an APPROVED registration.
70
	 * the TXN may or may not be completed ( paid in full )
71
	 * Payments are allowed.
72
	 * A space IS reserved.
73
	 * Registration is active
74
	 */
75
	const status_id_approved = 'RAP';
76
77
	/**
78
	 * Status ID (STS_ID on esp_status table) to indicate a registration was CANCELLED by the attendee.
79
	 * Payments are NOT allowed.
80
	 * NO space reserved.
81
	 * Registration is NOT active
82
	 */
83
	const status_id_cancelled = 'RCN';
84
85
	/**
86
	 * Status ID (STS_ID on esp_status table) to indicate a registration was DECLINED by the Event Admin
87
	 * Payments are NOT allowed.
88
	 * No space reserved.
89
	 * Registration is NOT active
90
	 */
91
	const status_id_declined = 'RDC';
92
93
94
95
	/**
96
	 *    private constructor to prevent direct creation
97
	 *
98
	 * @Constructor
99
	 * @access protected
100
	 * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any incoming timezone data that gets saved).
101
	 *    Note this just sends the timezone info to the date time model field objects.  Default is NULL (and will be assumed using the set timezone in the 'timezone_string' wp option)
102
	 * @return \EEM_Registration
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
103
	 */
104
	protected function __construct( $timezone = null ) {
105
		$this->singular_item = __('Registration','event_espresso');
106
		$this->plural_item = __('Registrations','event_espresso');
107
108
		$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...
109
			'Registration'=>new EE_Primary_Table('esp_registration','REG_ID')
110
		);
111
		$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...
112
			'Registration'=>array(
113
				'REG_ID'=>new EE_Primary_Key_Int_Field('REG_ID', __('Registration ID','event_espresso')),
114
				'EVT_ID'=>new EE_Foreign_Key_Int_Field('EVT_ID', __('Event ID','event_espresso'), false, 0, 'Event'),
115
				'ATT_ID'=>new EE_Foreign_Key_Int_Field('ATT_ID', __('Attendee ID','event_espresso'), false, 0, 'Attendee'),
116
				'TXN_ID'=>new EE_Foreign_Key_Int_Field('TXN_ID', __('Transaction ID','event_espresso'), false, 0, 'Transaction'),
117
				'TKT_ID'=>new EE_Foreign_Key_Int_Field('TKT_ID', __('Ticket ID','event_espresso'), false, 0, 'Ticket'),
118
				'STS_ID'=>new EE_Foreign_Key_String_Field('STS_ID', __('Status ID','event_espresso'), false, EEM_Registration::status_id_incomplete, 'Status'),
119
				'REG_date'=>new EE_Datetime_Field('REG_date', __('Time registration occurred','event_espresso'), false, time(), $timezone ),
120
				'REG_final_price'=>new EE_Money_Field('REG_final_price', __('Registration\'s share of the transaction total','event_espresso'), false, 0),
121
				'REG_paid'=>new EE_Money_Field('REG_paid', __('Amount paid to date towards registration','event_espresso'), false, 0),
122
				'REG_session'=>new EE_Plain_Text_Field('REG_session', __('Session ID of registration','event_espresso'), false, ''),
123
				'REG_code'=>new EE_Plain_Text_Field('REG_code', __('Unique Code for this registration','event_espresso'), false, ''),
124
				'REG_url_link'=>new EE_Plain_Text_Field('REG_url_link', __('String to be used in URL for identifying registration','event_espresso'), false, ''),
125
				'REG_count'=>new EE_Integer_Field('REG_count', __('Count of this registration in the group registration ','event_espresso'), true, 1),
126
				'REG_group_size'=>new EE_Integer_Field('REG_group_size', __('Number of registrations on this group','event_espresso'), false, 1),
127
				'REG_att_is_going'=>new EE_Boolean_Field('REG_att_is_going', __('Flag indicating the registrant plans on attending','event_espresso'), false, false),
128
				'REG_deleted' => new EE_Trashed_Flag_Field('REG_deleted', __('Flag indicating if registration has been archived or not.', 'event_espresso'), false, false )
129
			)
130
		);
131
		$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...
132
			'Event'=>new EE_Belongs_To_Relation(),
133
			'Attendee'=>new EE_Belongs_To_Relation(),
134
			'Transaction'=>new EE_Belongs_To_Relation(),
135
			'Ticket'=>new EE_Belongs_To_Relation(),
136
			'Status'=>new EE_Belongs_To_Relation(),
137
			'Answer'=>new EE_Has_Many_Relation(),
138
			'Checkin'=>new EE_Has_Many_Relation(),
139
			'Registration_Payment' => new EE_Has_Many_Relation(),
140
			'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...
141
			'Message' => new EE_Has_Many_Any_Relation( false ) //allow deletes even if there are messages in the queue related
142
		);
143
		$this->_model_chain_to_wp_user = 'Event';
144
145
		parent::__construct( $timezone );
0 ignored issues
show
Bug introduced by
It seems like $timezone defined by parameter $timezone on line 104 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...
146
	}
147
148
149
150
	/**
151
	 * reg_statuses_that_allow_payment
152
	 * a filterable list of registration statuses that allow a registrant to make a payment
153
	 *
154
	 * @access public
155
	 * @return array
156
	 */
157
	public static function reg_statuses_that_allow_payment() {
158
		return apply_filters(
159
			'FHEE__EEM_Registration__reg_statuses_that_allow_payment',
160
			array(
161
				EEM_Registration::status_id_approved,
162
				EEM_Registration::status_id_pending_payment,
163
				EEM_Registration::status_id_wait_list,
164
			)
165
		);
166
	}
167
168
169
170
	/**
171
	 * inactive_reg_statuses
172
	 * a filterable list of registration statuses that are not considered active
173
	 *
174
	 * @access public
175
	 * @return array
176
	 */
177
	public static function active_reg_statuses() {
178
		return apply_filters(
179
			'FHEE__EEM_Registration__reg_statuses_that_allow_payment',
180
			array(
181
				EEM_Registration::status_id_approved,
182
				EEM_Registration::status_id_pending_payment,
183
				EEM_Registration::status_id_wait_list,
184
				EEM_Registration::status_id_not_approved,
185
			)
186
		);
187
	}
188
189
190
191
	/**
192
	 * inactive_reg_statuses
193
	 * a filterable list of registration statuses that are not considered active
194
	 *
195
	 * @access public
196
	 * @return array
197
	 */
198
	public static function inactive_reg_statuses() {
199
		return apply_filters(
200
			'FHEE__EEM_Registration__reg_statuses_that_allow_payment',
201
			array(
202
				EEM_Registration::status_id_incomplete,
203
				EEM_Registration::status_id_cancelled,
204
				EEM_Registration::status_id_declined,
205
			)
206
		);
207
	}
208
209
210
211
	/**
212
	 * 		get list of registration statuses
213
	 *
214
	 *
215
	 *		@access public
216
	 *		@param array $exclude The status ids to exclude from the returned results
217
	 *		@param bool  $translated If true will return the values as singular localized strings
218
	 *		@return array
219
	 */
220
	public static function reg_status_array( $exclude = array(), $translated = FALSE ) {
221
		EEM_Registration::instance()->_get_registration_status_array( $exclude );
222
		return $translated ? EEM_Status::instance()->localized_status( self::$_reg_status, FALSE, 'sentence') : self::$_reg_status;
223
	}
224
225
226
227
	/**
228
	 * 	get list of registration statuses
229
	 * @access private
230
	 * @param array $exclude
231
	 * @return array
232
	 */
233
	private function _get_registration_status_array( $exclude = array() ) {
234
		//in the very rare circumstance that we are deleting a model's table's data
235
		//and the table hasn't actually been created, this could have an error
236
		/** @type WPDB $wpdb */
237
		global $wpdb;
238
		if( EEH_Activation::table_exists( $wpdb->prefix . 'esp_status' ) ){
239
			$SQL = 'SELECT STS_ID, STS_code FROM '. $wpdb->prefix . 'esp_status WHERE STS_type = "registration"';
240
			$results = $wpdb->get_results( $SQL );
241
			self::$_reg_status = array();
242
			foreach ( $results as $status ) {
243
				if ( ! in_array( $status->STS_ID, $exclude )) {
244
					self::$_reg_status[ $status->STS_ID ] = $status->STS_code;
245
				}
246
			}
247
		}
248
249
	}
250
251
252
253
254
	/**
255
	 * This returns a wpdb->results array of all registration date month and years matching the incoming query params and grouped by month and year.
256
	 * @param  array  $where_params Array of query_params as described in the comments for EEM_Base::get_all()
257
	 * @return wpdb results array
258
	 */
259
	public function get_reg_months_and_years( $where_params ) {
260
		$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...
261
		$query_params['group_by'] = array('reg_year', 'reg_month');
262
		$query_params['order_by'] = array( 'REG_date' => 'DESC' );
263
		$columns_to_select = array(
264
			'reg_year' => array('YEAR(REG_date)', '%s'),
265
			'reg_month' => array('MONTHNAME(REG_date)', '%s')
266
			);
267
		return $this->_get_all_wpdb_results( $query_params, OBJECT, $columns_to_select );
268
	}
269
270
271
272
273
	/**
274
	*		retrieve ALL registrations for a particular Attendee from db
275
	* 		@access		public
276
	* 		@param		int		$ATT_ID
277
	*		@return 	EE_Registration[]
278
	*/
279
	public function get_all_registrations_for_attendee( $ATT_ID = 0 ) {
280
		if ( ! $ATT_ID ) {
281
			return FALSE;
282
		}
283
		return $this->get_all( array( array( 'ATT_ID' => $ATT_ID )));
284
	}
285
286
287
288
	/**
289
	 * Gets a registration given their REG_url_link. Yes, this should usually
290
	 * be passed via a GET parameter.
291
	 * @param string $REG_url_link
292
	 * @return EE_Registration
293
	 */
294
	public function get_registration_for_reg_url_link($REG_url_link){
295
		if(!$REG_url_link){
296
			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...
297
		}
298
		return $this->get_one(array(array('REG_url_link'=>$REG_url_link)));
299
	}
300
301
302
303
304
	/**
305
	*		retrieve registration for a specific transaction attendee from db
306
	*
307
	* 		@access		public
308
	* 		@param	int	$TXN_ID
309
	* 		@param    int		$ATT_ID
310
	* 		@param    int		$att_nmbr 	in case the ATT_ID is the same for multiple registrations (same details used) then the attendee number is required
311
	*		@return 		mixed		array on success, FALSE on fail
312
	*/
313
	public function get_registration_for_transaction_attendee( $TXN_ID = 0, $ATT_ID = 0, $att_nmbr = 0 ) {
314
		return $this->get_one(array(
315
			array(
316
				'TXN_ID'=>$TXN_ID,
317
				'ATT_ID'=>$ATT_ID
318
			),
319
			'limit'=>array( min( ( $att_nmbr-1 ), 0 ), 1 )
320
		));
321
	}
322
323
324
	/**
325
	*		get the number of registrations per day  for the Registration Admin page Reports Tab.
326
	 *		(doesn't utilize models because it's a fairly specialized query)
327
	* 		@access		public
328
	 *		@param $period string which can be passed to php's strtotime function (eg "-1 month")
329
	 *		@return stdClass[] with properties regDate and total
330
	*/
331
	public function get_registrations_per_day_report( $period = '-1 month' ) {
332
333
		$sql_date = $this->convert_datetime_for_query( 'REG_date', date("Y-m-d H:i:s", strtotime($period) ), 'Y-m-d H:i:s', 'UTC' );
334
		$where = array( 'REG_date' => array( '>=', $sql_date ), 'STS_ID' => array( '!=', EEM_Registration::status_id_incomplete ) );
335
336
		if ( ! EE_Registry::instance()->CAP->current_user_can( 'ee_read_others_registrations', 'reg_per_day_report' ) ) {
337
			$where['Event.EVT_wp_user'] = get_current_user_id();
338
		}
339
340
		$query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset( $this->get_timezone(), 'REG_date' );
341
342
		$results = $this->_get_all_wpdb_results(
343
				array(
344
					$where,
345
					'group_by'=>'regDate',
346
					'order_by'=>array('REG_date'=>'ASC')
347
				),
348
				OBJECT,
349
				array(
350
					'regDate'=>array( 'DATE(' . $query_interval . ')','%s'),
351
					'total'=>array('count(REG_ID)','%d')
352
				));
353
		return $results;
354
	}
355
356
357
	/**
358
	 * Get the number of registrations per day including the count of registrations for each Registration Status.
359
	 * Note: EEM_Registration::status_id_incomplete registrations are excluded from the results.
360
	 *
361
	 * @param string $period
362
	 *
363
	 * @return stdClass[] with properties Registration_REG_date and a column for each registration status as the STS_ID
364
	 *                    (i.e. RAP)
365
	 */
366 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...
367
		global $wpdb;
368
		$registration_table = $wpdb->prefix . 'esp_registration';
369
		$event_table = $wpdb->posts;
370
		$sql_date = date("Y-m-d H:i:s", strtotime($period) );
371
372
		//prepare the query interval for displaying offset
373
		$query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset( $this->get_timezone(), 'dates.REG_date' );
374
375
		//inner date query
376
		$inner_date_query = "SELECT DISTINCT REG_date from $registration_table ";
377
		$inner_where = " WHERE";
378
		//exclude events not authored by user if permissions in effect
379
		if ( ! EE_Registry::instance()->CAP->current_user_can( 'ee_read_others_registrations', 'reg_per_event_report' ) ) {
380
			$inner_date_query .= "LEFT JOIN $event_table ON ID = EVT_ID";
381
			$inner_where .= " post_author = " . get_current_user_id() . " AND";
382
		}
383
		$inner_where .= " REG_date >= '$sql_date'";
384
		$inner_date_query .= $inner_where;
385
386
		//start main query
387
		$select = "SELECT DATE($query_interval) as Registration_REG_date, ";
388
		$join = '';
389
		$join_parts = array();
390
		$select_parts = array();
391
392
		//loop through registration stati to do parts for each status.
393
		foreach ( EEM_Registration::reg_status_array() as $STS_ID => $STS_code ) {
394
			if ( $STS_ID === EEM_Registration::status_id_incomplete ) {
395
				continue;
396
			}
397
			$select_parts[] = "COUNT($STS_code.REG_ID) as $STS_ID";
398
			$join_parts[] = "$registration_table AS $STS_code ON $STS_code.REG_date = dates.REG_date AND $STS_code.STS_ID = '$STS_ID'";
399
		}
400
401
		//setup the selects
402
		$select .= implode(', ', $select_parts );
403
		$select .= " FROM ($inner_date_query) AS dates LEFT JOIN ";
404
405
		//setup the joins
406
		$join .= implode( " LEFT JOIN ", $join_parts );
407
408
		//now let's put it all together
409
		$query = $select . $join . ' GROUP BY Registration_REG_date';
410
411
		//and execute it
412
		$results = $wpdb->get_results(
413
			$query,
414
			ARRAY_A
415
		);
416
		return $results;
417
	}
418
419
420
421
422
423
424
	/**
425
	*		get the number of registrations per event  for the Registration Admin page Reports Tab
426
	* 		@access		public
427
	 * @param $period string which can be passed to php's strtotime function (eg "-1 month")
428
	 *		@return stdClass[] each with properties event_name, reg_limit, and total
429
	*/
430
	public function get_registrations_per_event_report( $period = '-1 month' ) {
431
432
		$date_sql = $this->convert_datetime_for_query( 'REG_date', date( "Y-m-d H:i:s", strtotime( $period )), 'Y-m-d H:i:s', 'UTC' );
433
		$where = array( 'REG_date' => array( '>=', $date_sql ), 'STS_ID' => array( '!=', EEM_Registration::status_id_incomplete ) );
434
435
		if ( ! EE_Registry::instance()->CAP->current_user_can( 'ee_read_others_registrations', 'reg_per_event_report' ) ) {
436
			$where['Event.EVT_wp_user'] = get_current_user_id();
437
		}
438
		$results = $this->_get_all_wpdb_results(array(
439
			$where,
440
			'group_by'=>'Event.EVT_name',
441
			'order_by'=>'Event.EVT_name',
442
			'limit'=>array(0,24)),
443
			OBJECT,
444
			array(
445
				'event_name'=>array('Event_CPT.post_title','%s'),
446
				'total'=>array('COUNT(REG_ID)','%s')
447
			)
448
		);
449
450
		return $results;
451
452
	}
453
454
455
	/**
456
	 * Get the number of registrations per event grouped by registration status.
457
	 * Note: EEM_Registration::status_id_incomplete registrations are excluded from the results.
458
	 *
459
	 * @param string $period
460
	 *
461
	 * @return stdClass[] with properties `Registration_Event` and a column for each registration status as the STS_ID
462
	 *                    (i.e. RAP)
463
	 */
464 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...
465
		global $wpdb;
466
		$registration_table = $wpdb->prefix . 'esp_registration';
467
		$event_table = $wpdb->posts;
468
		$sql_date = date("Y-m-d H:i:s", strtotime($period) );
469
470
		//inner date query
471
		$inner_date_query = "SELECT DISTINCT EVT_ID, REG_date from $registration_table ";
472
		$inner_where = " WHERE";
473
		//exclude events not authored by user if permissions in effect
474
		if ( ! EE_Registry::instance()->CAP->current_user_can( 'ee_read_others_registrations', 'reg_per_event_report' ) ) {
475
			$inner_date_query .= "LEFT JOIN $event_table ON ID = EVT_ID";
476
			$inner_where .= " post_author = " . get_current_user_id() . " AND";
477
		}
478
		$inner_where .= " REG_date >= '$sql_date'";
479
		$inner_date_query .= $inner_where;
480
481
		//build main query
482
		$select = "SELECT Event.post_title as Registration_Event, ";
483
		$join = '';
484
		$join_parts = array();
485
		$select_parts = array();
486
487
		//loop through registration stati to do parts for each status.
488
		foreach ( EEM_Registration::reg_status_array() as $STS_ID => $STS_code ) {
489
			if ( $STS_ID === EEM_Registration::status_id_incomplete ) {
490
				continue;
491
			}
492
			$select_parts[] = "COUNT($STS_code.REG_ID) as $STS_ID";
493
			$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";
494
		}
495
496
		//setup the selects
497
		$select .= implode( ', ', $select_parts );
498
		$select .= " FROM ($inner_date_query) AS dates LEFT JOIN $event_table as Event ON Event.ID = dates.EVT_ID LEFT JOIN ";
499
500
		//setup remaining joins
501
		$join .= implode( " LEFT JOIN ", $join_parts );
502
503
		//now put it all together
504
		$query = $select . $join . ' GROUP BY Registration_Event';
505
506
		//and execute
507
		$results = $wpdb->get_results(
508
			$query,
509
			ARRAY_A
510
		);
511
		return $results;
512
	}
513
514
515
	/**
516
	 * Returns the EE_Registration of the primary attendee on the transaction id provided
517
	 * @param int $TXN_ID
518
	 * @return EE_Registration
519
	 */
520
	public function get_primary_registration_for_transaction_ID( $TXN_ID = 0){
521
		if( ! $TXN_ID ){
522
			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...
523
		}
524
		return $this->get_one(array(array('TXN_ID'=>$TXN_ID,'REG_count'=>  EEM_Registration::PRIMARY_REGISTRANT_COUNT)));
525
	}
526
527
528
	/**
529
	 *		get_event_registration_count
530
	 *
531
	 *		@access public
532
	 *		@param int $EVT_ID
533
	 *		@param boolean $for_incomplete_payments
534
	 *		@return int
535
	 */
536
	public function get_event_registration_count ( $EVT_ID, $for_incomplete_payments = FALSE ) {
537
		// we only count approved registrations towards registration limits
538
		$query_params = array( array( 'EVT_ID' => $EVT_ID, 'STS_ID' => self::status_id_approved ) );
539
		if( $for_incomplete_payments ){
540
			$query_params[0]['Transaction.STS_ID']=array('!=',  EEM_Transaction::complete_status_code);
541
		}
542
543
		return $this->count($query_params);
544
	}
545
546
	/**
547
	 * Deletes all registrations with no transactions. Note that this needs to be very efficient
548
	 * and so it uses wpdb directly
549
	 * @global WPDB $wpdb
550
	 * @return int number deleted
551
	 */
552
	public function delete_registrations_with_no_transaction() {
553
		/** @type WPDB $wpdb */
554
		global $wpdb;
555
		return $wpdb->query(
556
				'DELETE r FROM ' . $this->table() . ' r LEFT JOIN ' . EEM_Transaction::instance()->table() . ' t ON r.TXN_ID = t.TXN_ID WHERE t.TXN_ID IS NULL' );
557
	}
558
559
	/**
560
	 *  Count registrations checked into (or out of) a datetime
561
	 *
562
	 * @param int $DTT_ID datetime ID
563
	 * @param boolean $checked_in whether to count registrations checked IN or OUT
564
	 * @return int
565
	 */
566
	public function count_registrations_checked_into_datetime( $DTT_ID, $checked_in = true) {
567
		global $wpdb;
568
		//subquery to get latest checkin
569
		$query = $wpdb->prepare(
570
			'SELECT '
571
				. 'COUNT( DISTINCT checkins.REG_ID ) '
572
			. 'FROM ' . EEM_Checkin::instance()->table() . ' AS checkins INNER JOIN'
573
				. '( SELECT '
574
					. 'max( CHK_timestamp ) AS latest_checkin, '
575
					. 'REG_ID AS REG_ID '
576
				. 'FROM ' . EEM_Checkin::instance()->table() . ' '
577
				. 'WHERE DTT_ID=%d '
578
				. 'GROUP BY REG_ID'
579
			. ') AS most_recent_checkin_per_reg '
580
			. 'ON checkins.REG_ID=most_recent_checkin_per_reg.REG_ID '
581
				. 'AND checkins.CHK_timestamp = most_recent_checkin_per_reg.latest_checkin '
582
			. 'WHERE '
583
				. 'checkins.CHK_in=%d',
584
			$DTT_ID,
585
			$checked_in
586
		);
587
		return (int)$wpdb->get_var( $query );
588
	}
589
590
	/**
591
	 *  Count registrations checked into (or out of) an event.
592
	 *
593
	 * @param int $EVT_ID event ID
594
	 * @param boolean $checked_in whether to count registrations checked IN or OUT
595
	 * @return int
596
	 */
597
	public function count_registrations_checked_into_event( $EVT_ID, $checked_in = true ) {
598
		global $wpdb;
599
		//subquery to get latest checkin
600
		$query = $wpdb->prepare(
601
			'SELECT '
602
				. 'COUNT( DISTINCT checkins.REG_ID ) '
603
			. 'FROM ' . EEM_Checkin::instance()->table() . ' AS checkins INNER JOIN'
604
				. '( SELECT '
605
					. 'max( CHK_timestamp ) AS latest_checkin, '
606
					. 'REG_ID AS REG_ID '
607
				. 'FROM ' . EEM_Checkin::instance()->table() . ' AS c '
608
				. 'INNER JOIN ' . EEM_Datetime::instance()->table() . ' AS d '
609
				. 'ON c.DTT_ID=d.DTT_ID '
610
				. 'WHERE d.EVT_ID=%d '
611
				. 'GROUP BY REG_ID'
612
			. ') AS most_recent_checkin_per_reg '
613
			. 'ON checkins.REG_ID=most_recent_checkin_per_reg.REG_ID '
614
				. 'AND checkins.CHK_timestamp = most_recent_checkin_per_reg.latest_checkin '
615
			. 'WHERE '
616
				. 'checkins.CHK_in=%d',
617
			$EVT_ID,
618
			$checked_in
619
		);
620
		return (int)$wpdb->get_var( $query );
621
	}
622
623
624
625
626
627
	/**
628
	 * The purpose of this method is to retrieve an array of
629
	 * EE_Registration objects that represent the latest registration
630
	 * for each ATT_ID given in the function argument.
631
	 *
632
	 * @param array $attendee_ids
633
	 * @return EE_Registration[]
634
	 */
635
	public function get_latest_registration_for_each_of_given_contacts( $attendee_ids = array() ) {
636
		//first do a native wp_query to get the latest REG_ID's matching these attendees.
637
		global $wpdb;
638
		$registration_table = $wpdb->prefix . 'esp_registration';
639
		$attendee_table = $wpdb->posts;
640
		$attendee_ids = is_array( $attendee_ids )
641
			? array_map( 'absint', $attendee_ids )
642
			: array( (int) $attendee_ids );
643
		$attendee_ids = implode( ',', $attendee_ids );
644
645
646
		//first we do a query to get the registration ids
647
		// (because a group by before order by causes the order by to be ignored.)
648
		$registration_id_query = "
649
			SELECT registrations.registration_ids as registration_id
650
			FROM (
651
				SELECT
652
					Attendee.ID as attendee_ids,
653
					Registration.REG_ID as registration_ids
654
				FROM $registration_table AS Registration
655
				JOIN $attendee_table AS Attendee
656
					ON Registration.ATT_ID = Attendee.ID
657
					AND Attendee.ID IN ( $attendee_ids )
658
				ORDER BY Registration.REG_ID DESC
659
			  ) AS registrations
660
			  GROUP BY registrations.attendee_ids
661
		";
662
663
		$registration_ids = $wpdb->get_results(
664
			$registration_id_query,
665
			ARRAY_A
666
		);
667
668
		if ( empty( $registration_ids ) ) {
669
			return array();
670
		}
671
672
		$ids_for_model_query = array();
673
		//let's flatten the ids so they can be used in the model query.
674
		foreach ( $registration_ids as $registration_id ) {
675
			if ( isset( $registration_id['registration_id'] ) ) {
676
				$ids_for_model_query[] = $registration_id['registration_id'];
677
			}
678
		}
679
680
		//construct query
681
		$_where = array(
682
			'REG_ID' => array( 'IN', $ids_for_model_query )
683
		);
684
685
		return $this->get_all( array( $_where ) );
686
	}
687
688
689
690
}
691
// End of file EEM_Registration.model.php
692
// Location: /includes/models/EEM_Registration.model.php
693