Test Failed
Pull Request — master (#2551)
by Devin
04:51
created

Give_Donors_Query::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 23
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 19
nc 1
nop 1
dl 0
loc 23
rs 9.0856
c 0
b 0
f 0
1
<?php
2
/**
3
 * Donors Query
4
 *
5
 * @package     Give
6
 * @subpackage  Classes/Stats
7
 * @copyright   Copyright (c) 2017, WordImpress
8
 * @license     https://opensource.org/licenses/gpl-license GNU Public License
9
 * @since       1.8.14
10
 */
11
12
// Exit if accessed directly.
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit;
15
}
16
17
/**
18
 * Give_Donors_Query Class
19
 *
20
 * This class is for retrieving donors data.
21
 *
22
 * Donors can be retrieved for date ranges and pre-defined periods.
23
 *
24
 * @since 1.8.14
25
 */
26
class Give_Donors_Query {
27
28
	/**
29
	 * The args to pass to the give_get_donors() query
30
	 *
31
	 * @since  1.8.14
32
	 * @access public
33
	 *
34
	 * @var    array
35
	 */
36
	public $args = array();
37
38
	/**
39
	 * The donors found based on the criteria set
40
	 *
41
	 * @since  1.8.14
42
	 * @access public
43
	 *
44
	 * @var    array
45
	 */
46
	public $donors = array();
47
48
	/**
49
	 * The donors found based on the criteria set
50
	 *
51
	 * @since  1.8.14
52
	 * @access public
53
	 *
54
	 * @var    array
55
	 */
56
	public $table_name = '';
57
58
	/**
59
	 * The donors found based on the criteria set
60
	 *
61
	 * @since  1.8.14
62
	 * @access public
63
	 *
64
	 * @var    array
65
	 */
66
	public $meta_table_name = '';
67
68
	/**
69
	 * The donors found based on the criteria set
70
	 *
71
	 * @since  1.8.14
72
	 * @access public
73
	 *
74
	 * @var    array
75
	 */
76
	public $meta_type = '';
77
78
	/**
79
	 * Default query arguments.
80
	 *
81
	 * Not all of these are valid arguments that can be passed to WP_Query. The ones that are not, are modified before the query is run to convert them to the proper syntax.
82
	 *
83
	 * @since  1.8.14
84
	 * @access public
85
	 *
86
	 * @param  $args array The array of arguments that can be passed in and used for setting up this payment query.
87
	 */
88
	public function __construct( $args = array() ) {
89
		$defaults = array(
90
			'number'     => 20,
91
			'offset'     => 0,
92
			'paged'      => 1,
93
			'orderby'    => 'id',
94
			'order'      => 'DESC',
95
			'user'       => null,
96
			'email'      => null,
97
			'donor'      => null,
98
			'meta_query' => array(),
0 ignored issues
show
introduced by
Detected usage of meta_query, possible slow query.
Loading history...
99
			'date_query' => array(),
100
			's'          => null,
101
			'fields'     => 'all', // Support donors (all fields) or valid column  as string or array list
102
			'count'      => false,
103
			// 'form'       => array(),
104
		);
105
106
		$this->args = wp_parse_args( $args, $defaults );
107
		$this->table_name      = Give()->donors->table_name;
0 ignored issues
show
Documentation Bug introduced by
It seems like Give()->donors->table_name of type string is incompatible with the declared type array of property $table_name.

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...
108
		$this->meta_table_name = Give()->donor_meta->table_name;
0 ignored issues
show
Documentation Bug introduced by
It seems like Give()->donor_meta->table_name of type string is incompatible with the declared type array of property $meta_table_name.

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
		$this->meta_type       = Give()->donor_meta->meta_type;
0 ignored issues
show
Documentation Bug introduced by
It seems like Give()->donor_meta->meta_type of type string is incompatible with the declared type array of property $meta_type.

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...
110
	}
111
112
	/**
113
	 * Modify the query/query arguments before we retrieve donors.
114
	 *
115
	 * @since  1.8.14
116
	 * @access public
117
	 *
118
	 * @return void
119
	 */
120
	public function init() {
121
	}
122
123
124
	/**
125
	 * Retrieve donors.
126
	 *
127
	 * The query can be modified in two ways; either the action before the
128
	 * query is run, or the filter on the arguments (existing mainly for backwards
129
	 * compatibility).
130
	 *
131
	 * @since  1.8.14
132
	 * @access public
133
	 *
134
	 * @global wpdb $wpdb
135
	 *
136
	 * @return array
137
	 */
138
	public function get_donors() {
139
		global $wpdb;
140
141
		/**
142
		 * Fires before retrieving donors.
143
		 *
144
		 * @since 1.8.14
145
		 *
146
		 * @param Give_Donors_Query $this Donors query object.
147
		 */
148
		do_action( 'give_pre_get_donors', $this );
149
150
		if ( empty( $this->args['count'] ) ) {
151
			$this->donors = $wpdb->get_results( $this->get_sql() );
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
introduced by
Usage of a direct database call without caching is prohibited. Use wp_cache_get / wp_cache_set.
Loading history...
152
		} else {
153
			$this->donors = $wpdb->get_var( $this->get_sql() );
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
introduced by
Usage of a direct database call without caching is prohibited. Use wp_cache_get / wp_cache_set.
Loading history...
154
		}
155
156
		/**
157
		 * Fires after retrieving donors.
158
		 *
159
		 * @since 1.8.14
160
		 *
161
		 * @param Give_Donors_Query $this Donors query object.
162
		 */
163
		do_action( 'give_post_get_donors', $this );
164
165
		return $this->donors;
166
	}
167
168
	/**
169
	 * Get sql query from queried array.
170
	 *
171
	 * @since  2.0
172
	 * @access public
173
	 *
174
	 * @global wpdb $wpdb
175
	 * @return string
176
	 */
177
	public function get_sql() {
178
		global $wpdb;
179
180
		if ( $this->args['number'] < 1 ) {
181
			$this->args['number'] = 999999999999;
182
		}
183
184
		$where = $this->get_where_query();
185
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
186
187
		// Set offset.
188
		if ( empty( $this->args['offset'] ) && ( 0 < $this->args['paged'] ) ) {
189
			$this->args['offset'] = $this->args['number'] * ( $this->args['paged'] - 1 );
190
		}
191
192
		// Set fields.
193
		$fields = "{$this->table_name}.*";
194
		if ( ! empty( $this->args['fields'] ) && 'all' !== $this->args['fields'] ) {
195
			if ( is_string( $this->args['fields'] ) ) {
196
				$fields = "{$this->table_name}.{$this->args['fields']}";
197
			} else if ( is_array( $this->args['fields'] ) ) {
198
				$fields = "{$this->table_name}." . implode( " , {$this->table_name}.", $this->args['fields'] );
199
			}
200
		}
201
202
		// Set count.
203
		if ( ! empty( $this->args['count'] ) ) {
204
			$fields = "COUNT({$this->table_name}.id)";
205
		}
206
207
		$orderby = $this->get_order_query();
208
209
		$sql = $wpdb->prepare(
210
			"SELECT {$fields} FROM {$this->table_name} LIMIT %d,%d;",
211
			absint( $this->args['offset'] ),
212
			absint( $this->args['number'] )
213
		);
214
215
		// $where, $orderby and order already prepared query they can generate notice if you re prepare them in above.
216
		// WordPress consider LIKE condition as placeholder if start with s,f, or d.
217
		$sql = str_replace( 'LIMIT', "{$where} {$orderby} {$this->args['order']} LIMIT", $sql );
218
219
		return $sql;
220
	}
221
222
	/**
223
	 * Set query where clause.
224
	 *
225
	 * @since  1.8.14
226
	 * @access private
227
	 *
228
	 * @global wpdb $wpdb
229
	 * @return string
230
	 */
231
	private function get_where_query() {
232
		$where = '';
233
234
		// Get sql query for meta.
235
		if ( ! empty( $this->args['meta_query'] ) ) {
236
			$meta_query_object = new WP_Meta_Query( $this->args['meta_query'] );
237
			$meta_query        = $meta_query_object->get_sql(
238
				$this->meta_type,
239
				$this->table_name,
240
				'id'
241
			);
242
243
			$where = implode( '', $meta_query );
244
		}
245
246
		$where .= 'WHERE 1=1 ';
247
		$where .= $this->get_where_search();
248
		$where .= $this->get_where_email();
249
		$where .= $this->get_where_donor();
250
		$where .= $this->get_where_user();
251
		$where .= $this->get_where_date();
252
253
		return trim( $where );
254
		
255
	}
256
257
	/**
258
	 * Set email where clause.
259
	 *
260
	 * @since  1.8.14
261
	 * @access private
262
	 *
263
	 * @global wpdb $wpdb
264
	 * @return string
265
	 */
266
	private function get_where_email() {
267
		global $wpdb;
268
269
		$where = '';
270
271
		if ( ! empty( $this->args['email'] ) ) {
272
273
			if ( is_array( $this->args['email'] ) ) {
274
275
				$emails_count       = count( $this->args['email'] );
276
				$emails_placeholder = array_fill( 0, $emails_count, '%s' );
277
				$emails             = implode( ', ', $emails_placeholder );
278
279
				$where .= $wpdb->prepare( "AND {$this->table_name}.email IN( $emails )", $this->args['email'] );
280
			} else {
281
				$where .= $wpdb->prepare( "AND {$this->table_name}.email = %s", $this->args['email'] );
282
			}
283
		}
284
285
		return $where;
286
	}
287
288
	/**
289
	 * Set donor where clause.
290
	 *
291
	 * @since  1.8.14
292
	 * @access private
293
	 *
294
	 * @global wpdb $wpdb
295
	 * @return string
296
	 */
297 View Code Duplication
	private function get_where_donor() {
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...
298
		$where = '';
299
300
		// Specific donors.
301
		if ( ! empty( $this->args['donor'] ) ) {
302
			if ( ! is_array( $this->args['donor'] ) ) {
303
				$this->args['donor'] = explode( ',', $this->args['donor'] );
304
			}
305
			$donor_ids = implode( ',', array_map( 'intval', $this->args['donor'] ) );
306
307
			$where .= "AND {$this->table_name}.id IN( {$donor_ids} )";
308
		}
309
310
		return $where;
311
	}
312
313
	/**
314
	 * Set date where clause.
315
	 *
316
	 * @since  1.8.14
317
	 * @access private
318
	 *
319
	 * @global wpdb $wpdb
320
	 * @return string
321
	 */
322
	private function get_where_date() {
323
		$where = '';
324
325
		// Donors created for a specific date or in a date range
326
		if ( ! empty( $this->args['date_query'] ) ) {
327
			$date_query_object = new WP_Date_Query(
328
				is_array( $this->args['date_query'] ) ? $this->args['date_query'] : wp_parse_args( $this->args['date_query'] ),
329
				"{$this->table_name}.date_created"
330
			);
331
332
			$where .= str_replace(
333
				array(
334
					"\n",
335
					'(   (',
336
					'))',
337
				),
338
				array(
339
					'',
340
					'( (',
341
					') )',
342
				),
343
				$date_query_object->get_sql()
344
			);
345
		}
346
347
		return $where;
348
	}
349
350
	/**
351
	 * Set search where clause.
352
	 *
353
	 * @since  1.8.14
354
	 * @access private
355
	 *
356
	 * @global wpdb $wpdb
357
	 * @return string
358
	 */
359
	private function get_where_search() {
360
		$where = '';
361
362
		// Donors created for a specific date or in a date range
363
		if ( ! empty( $this->args['s'] ) && false !== strpos( $this->args['s'], ':' ) ) {
364
			$search_parts = explode( ':', $this->args['s'] );
365
366
			if ( ! empty( $search_parts[0] ) ) {
367
				switch ( $search_parts[0] ) {
368
					case 'name':
369
						$where = "AND {$this->table_name}.name LIKE '%{$search_parts[1]}%'";
370
						break;
371
372
					case 'note':
373
						$where = "AND {$this->table_name}.notes LIKE '%{$search_parts[1]}%'";
374
						break;
375
				}
376
			}
377
		}
378
379
		return $where;
380
	}
381
382
	/**
383
	 * Set user where clause.
384
	 *
385
	 * @since  1.8.14
386
	 * @access private
387
	 *
388
	 * @global wpdb $wpdb
389
	 * @return string
390
	 */
391 View Code Duplication
	private function get_where_user() {
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...
392
		$where = '';
393
394
		// Donors create for specific wp user.
395
		if ( ! empty( $this->args['user'] ) ) {
396
			if ( ! is_array( $this->args['user'] ) ) {
397
				$this->args['user'] = explode( ',', $this->args['user'] );
398
			}
399
			$user_ids = implode( ',', array_map( 'intval', $this->args['user'] ) );
400
401
			$where .= "AND {$this->table_name}.user_id IN( {$user_ids} )";
402
		}
403
404
		return $where;
405
	}
406
407
	/**
408
	 * Set orderby query
409
	 *
410
	 * @since  1.8.14
411
	 * @access private
412
	 *
413
	 * @return string
414
	 */
415
	private function get_order_query() {
416
		$table_columns = Give()->donors->get_columns();
417
418
		$this->args['orderby'] = ! array_key_exists( $this->args['orderby'], $table_columns ) ?
419
			'id' :
420
			$this->args['orderby'];
421
422
		$this->args['orderby'] = esc_sql( $this->args['orderby'] );
423
		$this->args['order']   = esc_sql( $this->args['order'] );
424
425
		switch ( $table_columns[ $this->args['orderby'] ] ) {
426
			case '%d':
427
			case '%f':
428
				$query = "ORDER BY {$this->table_name}.{$this->args['orderby']}+0";
429
				break;
430
431
			default:
432
				$query = "ORDER BY {$this->table_name}.{$this->args['orderby']}";
433
		}
434
435
		return $query;
436
	}
437
}
438