Completed
Branch BETA-4.9-message-activity (793322)
by
unknown
18:25 queued 10s
created

EEM_Registration   D

Complexity

Total Complexity 38

Size/Duplication

Total Lines 626
Duplicated Lines 16.13 %

Coupling/Cohesion

Components 2
Dependencies 23

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 38
c 3
b 0
f 0
lcom 2
cbo 23
dl 101
loc 626
rs 4.62

18 Methods

Rating   Name   Duplication   Size   Complexity  
A reg_status_array() 0 4 2
B __construct() 0 43 1
A reg_statuses_that_allow_payment() 0 9 1
A get_reg_months_and_years() 0 10 1
A get_all_registrations_for_attendee() 0 6 2
A get_registration_for_reg_url_link() 0 6 2
A get_registration_for_transaction_attendee() 0 9 1
A _get_registration_status_array() 0 17 4
B get_registrations_per_day_report() 0 24 2
B get_registrations_per_day_and_per_status_report() 52 52 4
A get_registrations_per_event_report() 0 23 2
B get_registrations_per_event_and_per_status_report() 49 49 4
A get_primary_registration_for_transaction_ID() 0 6 2
A get_event_registration_count() 0 9 2
A delete_registrations_with_no_transaction() 0 6 1
A count_registrations_checked_into_datetime() 0 23 1
B count_registrations_checked_into_event() 0 25 1
B get_latest_registration_for_each_of_given_contacts() 0 52 5

How to fix   Duplicated Code   

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:

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