Test Failed
Push — feature/background-processing ( ddf6d7 )
by Ravinder
06:04
created

Give_DB_Donors::get_donors()   F

Complexity

Conditions 16
Paths 5184

Size

Total Lines 119
Code Lines 58

Duplication

Lines 44
Ratio 36.97 %

Importance

Changes 0
Metric Value
cc 16
eloc 58
nc 5184
nop 1
dl 44
loc 119
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Donors DB
4
 *
5
 * @package     Give
6
 * @subpackage  Classes/Give_DB_Donors
7
 * @copyright   Copyright (c) 2016, WordImpress
8
 * @license     https://opensource.org/licenses/gpl-license GNU Public License
9
 * @since       1.0
10
 */
11
12
// Exit if accessed directly.
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit;
15
}
16
17
/**
18
 * Give_DB_Donors Class
19
 *
20
 * This class is for interacting with the donor database table.
21
 *
22
 * @since 1.0
23
 */
24
class Give_DB_Donors extends Give_DB {
25
26
	/**
27
	 * Give_DB_Donors constructor.
28
	 *
29
	 * Set up the Give DB Donor class.
30
	 *
31
	 * @since  1.0
32
	 * @access public
33
	 */
34
	public function __construct() {
35
		/* @var WPDB $wpdb */
36
		global $wpdb;
37
38
		$this->table_name  = $wpdb->prefix . 'give_customers';
39
		$this->primary_key = 'id';
40
		$this->version     = '1.0';
41
42
		// Set hooks and register table only if instance loading first time.
43
		if( ! ( Give()->donors instanceof Give_DB_Donors ) ) {
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
44
			// Setup hook.
45
			add_action( 'profile_update', array( $this, 'update_donor_email_on_user_update' ), 10, 2 );
46
47
			// Install table.
48
			$this->register_table();
49
		}
50
51
	}
52
53
	/**
54
	 * Get columns and formats
55
	 *
56
	 * @since  1.0
57
	 * @access public
58
	 *
59
	 * @return array  Columns and formats.
60
	 */
61 View Code Duplication
	public function get_columns() {
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...
62
		return array(
63
			'id'             => '%d',
64
			'user_id'        => '%d',
65
			'name'           => '%s',
66
			'email'          => '%s',
67
			'payment_ids'    => '%s',
68
			'purchase_value' => '%f',
69
			'purchase_count' => '%d',
70
			'notes'          => '%s',
71
			'date_created'   => '%s',
72
		);
73
	}
74
75
	/**
76
	 * Get default column values
77
	 *
78
	 * @since  1.0
79
	 * @access public
80
	 *
81
	 * @return array  Default column values.
82
	 */
83 View Code Duplication
	public function get_column_defaults() {
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...
84
		return array(
85
			'user_id'        => 0,
86
			'email'          => '',
87
			'name'           => '',
88
			'payment_ids'    => '',
89
			'purchase_value' => 0.00,
90
			'purchase_count' => 0,
91
			'notes'          => '',
92
			'date_created'   => date( 'Y-m-d H:i:s' ),
93
		);
94
	}
95
96
	/**
97
	 * Add a donor
98
	 *
99
	 * @since  1.0
100
	 * @access public
101
	 *
102
	 * @param  array $data
103
	 *
104
	 * @return int|bool
105
	 */
106
	public function add( $data = array() ) {
107
108
		$defaults = array(
109
			'payment_ids' => ''
0 ignored issues
show
introduced by
Each line in an array declaration must end in a comma
Loading history...
110
		);
111
112
		$args = wp_parse_args( $data, $defaults );
113
114
		if ( empty( $args['email'] ) ) {
115
			return false;
116
		}
117
118 View Code Duplication
		if ( ! empty( $args['payment_ids'] ) && is_array( $args['payment_ids'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
119
			$args['payment_ids'] = implode( ',', array_unique( array_values( $args['payment_ids'] ) ) );
120
		}
121
122
		$donor = $this->get_donor_by( 'email', $args['email'] );
123
124
		// update an existing donor.
125
		if ( $donor ) {
126
127
			// Update the payment IDs attached to the donor
128
			if ( ! empty( $args['payment_ids'] ) ) {
129
130
				if ( empty( $donor->payment_ids ) ) {
131
132
					$donor->payment_ids = $args['payment_ids'];
133
134
				} else {
135
136
					$existing_ids          = array_map( 'absint', explode( ',', $donor->payment_ids ) );
137
					$payment_ids           = array_map( 'absint', explode( ',', $args['payment_ids'] ) );
138
					$payment_ids           = array_merge( $payment_ids, $existing_ids );
139
					$donor->payment_ids = implode( ',', array_unique( array_values( $payment_ids ) ) );
140
141
				}
142
143
				$args['payment_ids'] = $donor->payment_ids;
144
145
			}
146
147
			$this->update( $donor->id, $args );
148
149
			return $donor->id;
150
151
		} else {
152
153
			return $this->insert( $args, 'donor' );
154
155
		}
156
157
	}
158
159
	/**
160
	 * Delete a donor.
161
	 *
162
	 * NOTE: This should not be called directly as it does not make necessary changes to
163
	 * the payment meta and logs. Use give_donor_delete() instead.
164
	 *
165
	 * @since  1.0
166
	 * @access public
167
	 *
168
	 * @param  bool|string|int $_id_or_email
169
	 *
170
	 * @return bool|int
171
	 */
172
	public function delete( $_id_or_email = false ) {
173
174
		if ( empty( $_id_or_email ) ) {
175
			return false;
176
		}
177
178
		$column   = is_email( $_id_or_email ) ? 'email' : 'id';
179
		$donor = $this->get_donor_by( $column, $_id_or_email );
180
181
		if ( $donor->id > 0 ) {
182
183
			global $wpdb;
184
185
			return $wpdb->delete( $this->table_name, array( 'id' => $donor->id ), array( '%d' ) );
186
187
		} else {
188
			return false;
189
		}
190
191
	}
192
193
	/**
194
	 * Delete a donor.
195
	 *
196
	 * NOTE: This should not be called directly as it does not make necessary changes to
197
	 * the payment meta and logs. Use give_donor_delete() instead.
198
	 *
199
	 * @since  1.0
200
	 * @access public
201
	 *
202
	 * @param  int $user_id
203
	 *
204
	 * @return bool|int
205
	 */
206
	public function delete_by_user_id( $user_id = false ) {
207
208
		if ( empty( $user_id ) ) {
209
			return false;
210
		}
211
		global $wpdb;
212
213
		return $wpdb->delete( $this->table_name, array( 'user_id' => $user_id ), array( '%d' ) );
214
	}
215
216
	/**
217
	 * Checks if a donor exists
218
	 *
219
	 * @since  1.0
220
	 * @access public
221
	 *
222
	 * @param  string $value The value to search for. Default is empty.
223
	 * @param  string $field The Donor ID or email to search in. Default is 'email'.
224
	 *
225
	 * @return bool          True is exists, false otherwise.
226
	 */
227
	public function exists( $value = '', $field = 'email' ) {
228
		
229
		$columns = $this->get_columns();
230
		if ( ! array_key_exists( $field, $columns ) ) {
231
			return false;
232
		}
233
234
		return (bool) $this->get_column_by( 'id', $field, $value );
235
236
	}
237
238
	/**
239
	 * Attaches a payment ID to a donor
240
	 *
241
	 * @since  1.0
242
	 * @access public
243
	 *
244
	 * @param  int $donor_id Donor ID.
245
	 * @param  int $payment_id  Payment ID.
246
	 *
247
	 * @return bool
248
	 */
249
	public function attach_payment( $donor_id = 0, $payment_id = 0 ) {
250
251
		$donor = new Give_Donor( $donor_id );
0 ignored issues
show
Documentation introduced by
$donor_id is of type integer, 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...
252
253
		if ( empty( $donor->id ) ) {
254
			return false;
255
		}
256
257
		// Attach the payment, but don't increment stats, as this function previously did not
258
		return $donor->attach_payment( $payment_id, false );
259
260
	}
261
262
	/**
263
	 * Removes a payment ID from a donor.
264
	 *
265
	 * @since  1.0
266
	 * @access public
267
	 *
268
	 * @param  int $donor_id Donor ID.
269
	 * @param  int $payment_id  Payment ID.
270
	 *
271
	 * @return bool
272
	 */
273
	public function remove_payment( $donor_id = 0, $payment_id = 0 ) {
274
275
		$donor = new Give_Donor( $donor_id );
0 ignored issues
show
Documentation introduced by
$donor_id is of type integer, 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...
276
277
		if ( ! $donor ) {
278
			return false;
279
		}
280
281
		// Remove the payment, but don't decrease stats, as this function previously did not
282
		return $donor->remove_payment( $payment_id, false );
283
284
	}
285
286
	/**
287
	 * Increments donor's donation stats.
288
	 *
289
	 * @access public
290
	 *
291
	 * @param int   $donor_id Donor ID.
292
	 * @param float $amount      Amoumt.
293
	 *
294
	 * @return bool
295
	 */
296 View Code Duplication
	public function increment_stats( $donor_id = 0, $amount = 0.00 ) {
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...
297
298
		$donor = new Give_Donor( $donor_id );
0 ignored issues
show
Documentation introduced by
$donor_id is of type integer, 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...
299
300
		if ( empty( $donor->id ) ) {
301
			return false;
302
		}
303
304
		$increased_count = $donor->increase_purchase_count();
305
		$increased_value = $donor->increase_value( $amount );
306
307
		return ( $increased_count && $increased_value ) ? true : false;
0 ignored issues
show
Bug Best Practice introduced by
The expression $increased_count of type false|integer is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
308
309
	}
310
311
	/**
312
	 * Decrements donor's donation stats.
313
	 *
314
	 * @since  1.0
315
	 * @access public
316
	 *
317
	 * @param  int   $donor_id Donor ID.
318
	 * @param  float $amount      Amount.
319
	 *
320
	 * @return bool
321
	 */
322 View Code Duplication
	public function decrement_stats( $donor_id = 0, $amount = 0.00 ) {
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...
323
324
		$donor = new Give_Donor( $donor_id );
0 ignored issues
show
Documentation introduced by
$donor_id is of type integer, 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...
325
326
		if ( ! $donor ) {
327
			return false;
328
		}
329
330
		$decreased_count = $donor->decrease_donation_count();
331
		$decreased_value = $donor->decrease_value( $amount );
332
333
		return ( $decreased_count && $decreased_value ) ? true : false;
0 ignored issues
show
Bug Best Practice introduced by
The expression $decreased_count of type false|integer is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
334
335
	}
336
337
	/**
338
	 * Updates the email address of a donor record when the email on a user is updated
339
	 *
340
	 * @since  1.4.3
341
	 * @access public
342
	 *
343
	 * @param  int          $user_id       User ID.
344
	 * @param  WP_User|bool $old_user_data User data.
345
	 *
346
	 * @return bool
347
	 */
348
	public function update_donor_email_on_user_update( $user_id = 0, $old_user_data = false ) {
0 ignored issues
show
Unused Code introduced by
The parameter $old_user_data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
349
350
		$donor = new Give_Donor( $user_id, true );
0 ignored issues
show
Documentation introduced by
$user_id is of type integer, 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...
351
352
		if( ! $donor ) {
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
353
			return false;
354
		}
355
356
		$user = get_userdata( $user_id );
357
358
		if( ! empty( $user ) && $user->user_email !== $donor->email ) {
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
359
360
			if( ! $this->get_donor_by( 'email', $user->user_email ) ) {
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
361
362
				$success = $this->update( $donor->id, array( 'email' => $user->user_email ) );
363
364
				if( $success ) {
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
365
					// Update some payment meta if we need to
366
					$payments_array = explode( ',', $donor->payment_ids );
367
368
					if( ! empty( $payments_array ) ) {
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
369
370
						foreach ( $payments_array as $payment_id ) {
371
372
							give_update_payment_meta( $payment_id, 'email', $user->user_email );
373
374
						}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
375
376
					}
377
378
					/**
379
					 * Fires after updating donor email on user update.
380
					 *
381
					 * @since 1.4.3
382
					 * 
383
					 * @param  WP_User       $user     WordPress User object.
384
					 * @param  Give_Donor $donor Give donor object.
385
					 */
386
					do_action( 'give_update_donor_email_on_user_update', $user, $donor );
387
388
				}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
389
390
			}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
391
392
		}
393
394
	}
395
	
396
	/**
397
	 * Retrieves a single donor from the database
398
	 *
399
	 * @since  1.0
400
	 * @access public
401
	 *
402
	 * @param  string $field ID or email. Default is 'id'.
403
	 * @param  mixed  $value The Customer ID or email to search. Default is 0.
404
	 *
405
	 * @return mixed         Upon success, an object of the donor. Upon failure, NULL
406
	 */
407
	public function get_donor_by( $field = 'id', $value = 0 ) {
408
		/* @var WPDB $wpdb */
409
		global $wpdb;
410
411
		if ( empty( $field ) || empty( $value ) ) {
412
			return null;
413
		}
414
415
		if ( 'id' == $field || 'user_id' == $field ) {
416
			// Make sure the value is numeric to avoid casting objects, for example,
417
			// to int 1.
418
			if ( ! is_numeric( $value ) ) {
419
				return false;
420
			}
421
422
			$value = intval( $value );
423
424
			if ( $value < 1 ) {
425
				return false;
426
			}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
427
428
		} elseif ( 'email' === $field ) {
429
430
			if ( ! is_email( $value ) ) {
431
				return false;
432
			}
433
434
			$value = trim( $value );
435
		}
436
437
		if ( ! $value ) {
438
			return false;
439
		}
440
441
		switch ( $field ) {
442
			case 'id':
443
				$db_field = 'id';
444
				break;
445
			case 'email':
446
				$value    = sanitize_text_field( $value );
447
				$db_field = 'email';
448
				break;
449
			case 'user_id':
450
				$db_field = 'user_id';
451
				break;
452
			default:
453
				return false;
454
		}
455
456
		if ( ! $donor = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $this->table_name WHERE $db_field = %s LIMIT 1", $value ) ) ) {
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...
457
458
			// Look for donor from an additional email.
459
			if( 'email' === $field ) {
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
460
				$meta_table  = Give()->donor_meta->table_name;
461
				$donor_id = $wpdb->get_var( $wpdb->prepare( "SELECT customer_id FROM {$meta_table} WHERE meta_key = 'additional_email' AND meta_value = %s LIMIT 1", $value ) );
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...
462
463
				if( ! empty( $donor_id ) ) {
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
464
					return $this->get( $donor_id );
465
 				}
466
 			}
467
468
			return false;
469
		}
470
471
		return $donor;
472
	}
473
474
	/**
475
	 * Retrieve donors from the database.
476
	 *
477
	 * @since  1.0
478
	 * @access public
479
     *
480
     * @param  array $args
481
     *
482
     * @return array|object|null Customers array or object. Null if not found.
483
	 */
484
	public function get_donors( $args = array() ) {
485
        /* @var WPDB $wpdb */
486
		global $wpdb;
487
488
		$defaults = array(
489
			'number'  => 20,
490
			'offset'  => 0,
491
			'user_id' => 0,
492
			'orderby' => 'id',
493
			'order'   => 'DESC'
0 ignored issues
show
introduced by
Each line in an array declaration must end in a comma
Loading history...
494
		);
495
496
		$args = wp_parse_args( $args, $defaults );
497
498
		if ( $args['number'] < 1 ) {
499
			$args['number'] = 999999999999;
500
		}
501
502
		$where = ' WHERE 1=1 ';
503
504
		// specific donors.
505 View Code Duplication
		if ( ! empty( $args['id'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
506
507
			if ( is_array( $args['id'] ) ) {
508
				$ids = implode( ',', array_map( 'intval', $args['id'] ) );
509
			} else {
510
				$ids = intval( $args['id'] );
511
			}
512
513
			$where .= " AND `id` IN( {$ids} ) ";
514
515
		}
516
517
		// donors for specific user accounts
518 View Code Duplication
		if ( ! empty( $args['user_id'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
519
520
			if ( is_array( $args['user_id'] ) ) {
521
				$user_ids = implode( ',', array_map( 'intval', $args['user_id'] ) );
522
			} else {
523
				$user_ids = intval( $args['user_id'] );
524
			}
525
526
			$where .= " AND `user_id` IN( {$user_ids} ) ";
527
528
		}
529
530
		//specific donors by email
531
		if( ! empty( $args['email'] ) ) {
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
532
533
			if( is_array( $args['email'] ) ) {
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
534
535
				$emails_count       = count( $args['email'] );
536
				$emails_placeholder = array_fill( 0, $emails_count, '%s' );
537
				$emails             = implode( ', ', $emails_placeholder );
538
539
				$where .= $wpdb->prepare( " AND `email` IN( $emails ) ", $args['email'] );
540
			} else {
541
				$where .= $wpdb->prepare( " AND `email` = %s ", $args['email'] );
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal AND `email` = %s does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
542
			}
543
		}
544
545
		// specific donors by name
546
		if( ! empty( $args['name'] ) ) {
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
547
			$where .= $wpdb->prepare( " AND `name` LIKE '%%%%" . '%s' . "%%%%' ", $args['name'] );
548
		}
549
550
		// Donors created for a specific date or in a date range
551
		if ( ! empty( $args['date'] ) ) {
552
553
			if ( is_array( $args['date'] ) ) {
554
555 View Code Duplication
				if ( ! empty( $args['date']['start'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
556
557
					$start = date( 'Y-m-d H:i:s', strtotime( $args['date']['start'] ) );
558
559
					$where .= " AND `date_created` >= '{$start}'";
560
561
				}
562
563 View Code Duplication
				if ( ! empty( $args['date']['end'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
564
565
					$end = date( 'Y-m-d H:i:s', strtotime( $args['date']['end'] ) );
566
567
					$where .= " AND `date_created` <= '{$end}'";
568
569
				}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
570
571 View Code Duplication
			} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
572
573
				$year  = date( 'Y', strtotime( $args['date'] ) );
574
				$month = date( 'm', strtotime( $args['date'] ) );
575
				$day   = date( 'd', strtotime( $args['date'] ) );
576
577
				$where .= " AND $year = YEAR ( date_created ) AND $month = MONTH ( date_created ) AND $day = DAY ( date_created )";
578
			}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
579
580
		}
581
582
		$args['orderby'] = ! array_key_exists( $args['orderby'], $this->get_columns() ) ? 'id' : $args['orderby'];
583
584
		if ( 'purchase_value' == $args['orderby'] ) {
585
			$args['orderby'] = 'purchase_value+0';
586
		}
587
588
		$cache_key = md5( 'give_donors_' . serialize( $args ) );
589
590
		$donors = wp_cache_get( $cache_key, 'donors' );
591
592
		$args['orderby'] = esc_sql( $args['orderby'] );
593
		$args['order']   = esc_sql( $args['order'] );
594
595
		if ( $donors === false ) {
0 ignored issues
show
introduced by
Found "=== false". Use Yoda Condition checks, you must
Loading history...
596
			$donors = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM  $this->table_name $where ORDER BY {$args['orderby']} {$args['order']} LIMIT %d,%d;", absint( $args['offset'] ), absint( $args['number'] ) ) );
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
597
			wp_cache_set( $cache_key, $donors, 'donors', 3600 );
598
		}
599
600
		return $donors;
601
602
	}
603
604
605
	/**
606
	 * Count the total number of donors in the database
607
	 *
608
	 * @since  1.0
609
	 * @access public
610
     *
611
     * @param  array $args
612
     *
613
     * @return int         Total number of donors.
614
	 */
615
	public function count( $args = array() ) {
616
        /* @var WPDB $wpdb */
617
		global $wpdb;
618
619
		$where = ' WHERE 1=1 ';
620
621
		if ( ! empty( $args['date'] ) ) {
622
623
			if ( is_array( $args['date'] ) ) {
624
625
				$start = date( 'Y-m-d H:i:s', strtotime( $args['date']['start'] ) );
626
				$end   = date( 'Y-m-d H:i:s', strtotime( $args['date']['end'] ) );
627
628
				$where .= " AND `date_created` >= '{$start}' AND `date_created` <= '{$end}'";
629
630 View Code Duplication
			} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
631
632
				$year  = date( 'Y', strtotime( $args['date'] ) );
633
				$month = date( 'm', strtotime( $args['date'] ) );
634
				$day   = date( 'd', strtotime( $args['date'] ) );
635
636
				$where .= " AND $year = YEAR ( date_created ) AND $month = MONTH ( date_created ) AND $day = DAY ( date_created )";
637
			}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
638
639
		}
640
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
641
642
		$cache_key = md5( 'give_donors_count' . serialize( $args ) );
643
644
		$count = wp_cache_get( $cache_key, 'donors' );
645
646
		if ( $count === false ) {
0 ignored issues
show
introduced by
Found "=== false". Use Yoda Condition checks, you must
Loading history...
647
			$count = $wpdb->get_var( "SELECT COUNT($this->primary_key) FROM " . $this->table_name . "{$where};" );
0 ignored issues
show
introduced by
Usage of a direct database call is discouraged.
Loading history...
648
			wp_cache_set( $cache_key, $count, 'donors', 3600 );
649
		}
650
651
		return absint( $count );
652
653
	}
654
655
	/**
656
	 * Create the table
657
	 *
658
	 * @since  1.0
659
	 * @access public
660
	 *
661
	 * @return void
662
	 */
663 View Code Duplication
	public function create_table() {
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...
664
665
		require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
666
667
		$sql = "CREATE TABLE " . $this->table_name . " (
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal CREATE TABLE does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
Coding Style Comprehensibility introduced by
The string literal (\n id bigint(20...OLLATE utf8_general_ci; does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
668
		id bigint(20) NOT NULL AUTO_INCREMENT,
669
		user_id bigint(20) NOT NULL,
670
		email varchar(50) NOT NULL,
671
		name mediumtext NOT NULL,
672
		purchase_value mediumtext NOT NULL,
673
		purchase_count bigint(20) NOT NULL,
674
		payment_ids longtext NOT NULL,
675
		notes longtext NOT NULL,
676
		date_created datetime NOT NULL,
677
		PRIMARY KEY  (id),
678
		UNIQUE KEY email (email),
679
		KEY user (user_id)
680
		) CHARACTER SET utf8 COLLATE utf8_general_ci;";
681
682
		dbDelta( $sql );
683
684
		update_option( $this->table_name . '_db_version', $this->version );
685
	}
686
	
687
	/**
688
	 * Check if the Customers table was ever installed
689
	 *
690
	 * @since  1.4.3
691
	 * @access public
692
	 *
693
	 * @return bool Returns if the donors table was installed and upgrade routine run.
694
	 */
695
	public function installed() {
696
		return $this->table_exists( $this->table_name );
697
	}
698
699
}
700