Test Failed
Push — issues/1944 ( f13954...e5d7bc )
by Ravinder
05:26
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
82
	 * the query is run to convert them to the proper syntax.
83
	 *
84
	 * @since  1.8.14
85
	 * @access public
86
	 *
87
	 * @param  $args array The array of arguments that can be passed in and used for setting up this payment query.
88
	 */
89
	public function __construct( $args = array() ) {
90
		$defaults = array(
91
			'number'     => 20,
92
			'offset'     => 0,
93
			'paged'      => 1,
94
			'orderby'    => 'id',
95
			'order'      => 'DESC',
96
			'user'       => null,
97
			'email'      => null,
98
			'donor'      => null,
99
			'meta_query' => array(),
0 ignored issues
show
introduced by
Detected usage of meta_query, possible slow query.
Loading history...
100
			'date_query' => array(),
101
			's'          => null,
102
			'fields'     => 'all', // Support donors (all fields) or valid column  as string or array list
103
			'count'      => false,
104
			// 'form'       => array(),
105
		);
106
107
		$this->args = wp_parse_args( $args, $defaults );
108
		$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...
109
		$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...
110
		$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...
111
	}
112
113
	/**
114
	 * Modify the query/query arguments before we retrieve donors.
115
	 *
116
	 * @since  1.8.14
117
	 * @access public
118
	 *
119
	 * @return void
120
	 */
121
	public function init() {
122
	}
123
124
125
	/**
126
	 * Retrieve donors.
127
	 *
128
	 * The query can be modified in two ways; either the action before the
129
	 * query is run, or the filter on the arguments (existing mainly for backwards
130
	 * compatibility).
131
	 *
132
	 * @since  1.8.14
133
	 * @access public
134
	 *
135
	 * @global wpdb $wpdb
136
	 *
137
	 * @return array
138
	 */
139
	public function get_donors() {
140
		global $wpdb;
141
142
		/**
143
		 * Fires before retrieving donors.
144
		 *
145
		 * @since 1.8.14
146
		 *
147
		 * @param Give_Donors_Query $this Donors query object.
148
		 */
149
		do_action( 'give_pre_get_donors', $this );
150
151
		$cache_key        = Give_Cache::get_key( 'give_donor', $this->get_sql(), false );
0 ignored issues
show
Documentation introduced by
$this->get_sql() is of type string, but the function expects a array|null.

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...
152
153
		// Get donors from cache.
154
		$this->donors = Give_Cache::get_db_query( $cache_key );
0 ignored issues
show
Documentation Bug introduced by
It seems like \Give_Cache::get_db_query($cache_key) of type * is incompatible with the declared type array of property $donors.

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