Test Failed
Pull Request — master (#2054)
by Devin
05:04
created

Give_DB_Donors::delete()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 27
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 11
nc 5
nop 1
dl 0
loc 27
rs 8.5806
c 0
b 0
f 0
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
	 * Give_DB_Donors constructor.
27
	 *
28
	 * Set up the Give DB Donor class.
29
	 *
30
	 * @since  1.0
31
	 * @access public
32
	 */
33
	public function __construct() {
34
		/* @var WPDB $wpdb */
35
		global $wpdb;
36
37
		$this->table_name  = $wpdb->prefix . 'give_customers';
38
		$this->primary_key = 'id';
39
		$this->version     = '1.0';
40
41
		// Set hooks and register table only if instance loading first time.
42
		if ( ! ( Give()->donors instanceof Give_DB_Donors ) ) {
43
			// Setup hook.
44
			add_action( 'profile_update', array( $this, 'update_donor_email_on_user_update' ), 10, 2 );
45
46
			// Install table.
47
			$this->register_table();
48
		}
49
50
	}
51
52
	/**
53
	 * Get columns and formats
54
	 *
55
	 * @since  1.0
56
	 * @access public
57
	 *
58
	 * @return array  Columns and formats.
59
	 */
60 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...
61
		return array(
62
			'id'             => '%d',
63
			'user_id'        => '%d',
64
			'name'           => '%s',
65
			'email'          => '%s',
66
			'payment_ids'    => '%s',
67
			'purchase_value' => '%f',
68
			'purchase_count' => '%d',
69
			'notes'          => '%s',
70
			'date_created'   => '%s',
71
		);
72
	}
73
74
	/**
75
	 * Get default column values
76
	 *
77
	 * @since  1.0
78
	 * @access public
79
	 *
80
	 * @return array  Default column values.
81
	 */
82 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...
83
		return array(
84
			'user_id'        => 0,
85
			'email'          => '',
86
			'name'           => '',
87
			'payment_ids'    => '',
88
			'purchase_value' => 0.00,
89
			'purchase_count' => 0,
90
			'notes'          => '',
91
			'date_created'   => date( 'Y-m-d H:i:s' ),
92
		);
93
	}
94
95
	/**
96
	 * Add a donor
97
	 *
98
	 * @since  1.0
99
	 * @access public
100
	 *
101
	 * @param  array $data
102
	 *
103
	 * @return int|bool
104
	 */
105
	public function add( $data = array() ) {
106
107
		$defaults = array(
108
			'payment_ids' => ''
0 ignored issues
show
introduced by
Each line in an array declaration must end in a comma
Loading history...
109
		);
110
111
		$args = wp_parse_args( $data, $defaults );
112
113
		if ( empty( $args['email'] ) ) {
114
			return false;
115
		}
116
117 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...
118
			$args['payment_ids'] = implode( ',', array_unique( array_values( $args['payment_ids'] ) ) );
119
		}
120
121
		$donor = $this->get_donor_by( 'email', $args['email'] );
122
123
		// update an existing donor.
124
		if ( $donor ) {
125
126
			// Update the payment IDs attached to the donor
127
			if ( ! empty( $args['payment_ids'] ) ) {
128
129
				if ( empty( $donor->payment_ids ) ) {
130
131
					$donor->payment_ids = $args['payment_ids'];
132
133
				} else {
134
135
					$existing_ids       = array_map( 'absint', explode( ',', $donor->payment_ids ) );
136
					$payment_ids        = array_map( 'absint', explode( ',', $args['payment_ids'] ) );
137
					$payment_ids        = array_merge( $payment_ids, $existing_ids );
138
					$donor->payment_ids = implode( ',', array_unique( array_values( $payment_ids ) ) );
139
140
				}
141
142
				$args['payment_ids'] = $donor->payment_ids;
143
144
			}
145
146
			$this->update( $donor->id, $args );
147
148
			return $donor->id;
149
150
		} else {
151
152
			return $this->insert( $args, 'donor' );
153
154
		}
155
156
	}
157
158
	/**
159
	 * Delete a donor.
160
	 *
161
	 * NOTE: This should not be called directly as it does not make necessary changes to
162
	 * the payment meta and logs. Use give_donor_delete() instead.
163
	 *
164
	 * @since  1.0
165
	 * @access public
166
	 *
167
	 * @param  bool|string|int $_id_or_email
168
	 *
169
	 * @return bool|int
170
	 */
171
	public function delete( $_id_or_email = false ) {
172
173
		if ( empty( $_id_or_email ) ) {
174
			return false;
175
		}
176
177
		$column = is_email( $_id_or_email ) ? 'email' : 'id';
178
		$donor  = $this->get_donor_by( $column, $_id_or_email );
179
180
		if ( $donor->id > 0 ) {
181
182
			global $wpdb;
183
184
			/**
185
			 * Deleting the donor meta.
186
			 *
187
			 * @since 1.8.14
188
			 */
189
			Give()->donor_meta->delete_all_meta( $donor->id );
190
191
			return $wpdb->delete( $this->table_name, array( 'id' => $donor->id ), array( '%d' ) );
192
193
		} else {
194
			return false;
195
		}
196
197
	}
198
199
	/**
200
	 * Delete a donor.
201
	 *
202
	 * NOTE: This should not be called directly as it does not make necessary changes to
203
	 * the payment meta and logs. Use give_donor_delete() instead.
204
	 *
205
	 * @since  1.0
206
	 * @access public
207
	 *
208
	 * @param  int $user_id
209
	 *
210
	 * @return bool|int
211
	 */
212
	public function delete_by_user_id( $user_id = false ) {
213
214
		if ( empty( $user_id ) ) {
215
			return false;
216
		}
217
218
		/**
219
		 * Deleting the donor meta.
220
		 *
221
		 * @since 1.8.14
222
		 */
223
		$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...
224
		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...
225
			Give()->donor_meta->delete_all_meta( $donor->id );
226
		}
227
228
		global $wpdb;
229
		return $wpdb->delete( $this->table_name, array( 'user_id' => $user_id ), array( '%d' ) );
230
	}
231
232
	/**
233
	 * Checks if a donor exists
234
	 *
235
	 * @since  1.0
236
	 * @access public
237
	 *
238
	 * @param  string $value The value to search for. Default is empty.
239
	 * @param  string $field The Donor ID or email to search in. Default is 'email'.
240
	 *
241
	 * @return bool          True is exists, false otherwise.
242
	 */
243
	public function exists( $value = '', $field = 'email' ) {
244
245
		$columns = $this->get_columns();
246
		if ( ! array_key_exists( $field, $columns ) ) {
247
			return false;
248
		}
249
250
		return (bool) $this->get_column_by( 'id', $field, $value );
251
252
	}
253
254
	/**
255
	 * Attaches a payment ID to a donor
256
	 *
257
	 * @since  1.0
258
	 * @access public
259
	 *
260
	 * @param  int $donor_id Donor ID.
261
	 * @param  int $payment_id Payment ID.
262
	 *
263
	 * @return bool
264
	 */
265
	public function attach_payment( $donor_id = 0, $payment_id = 0 ) {
266
267
		$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...
268
269
		if ( empty( $donor->id ) ) {
270
			return false;
271
		}
272
273
		// Attach the payment, but don't increment stats, as this function previously did not
274
		return $donor->attach_payment( $payment_id, false );
275
276
	}
277
278
	/**
279
	 * Removes a payment ID from a donor.
280
	 *
281
	 * @since  1.0
282
	 * @access public
283
	 *
284
	 * @param  int $donor_id Donor ID.
285
	 * @param  int $payment_id Payment ID.
286
	 *
287
	 * @return bool
288
	 */
289
	public function remove_payment( $donor_id = 0, $payment_id = 0 ) {
290
291
		$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...
292
293
		if ( ! $donor ) {
294
			return false;
295
		}
296
297
		// Remove the payment, but don't decrease stats, as this function previously did not
298
		return $donor->remove_payment( $payment_id, false );
299
300
	}
301
302
	/**
303
	 * Increments donor's donation stats.
304
	 *
305
	 * @access public
306
	 *
307
	 * @param int $donor_id Donor ID.
308
	 * @param float $amount Amoumt.
309
	 *
310
	 * @return bool
311
	 */
312 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...
313
314
		$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...
315
316
		if ( empty( $donor->id ) ) {
317
			return false;
318
		}
319
320
		$increased_count = $donor->increase_purchase_count();
321
		$increased_value = $donor->increase_value( $amount );
322
323
		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...
324
325
	}
326
327
	/**
328
	 * Decrements donor's donation stats.
329
	 *
330
	 * @since  1.0
331
	 * @access public
332
	 *
333
	 * @param  int $donor_id Donor ID.
334
	 * @param  float $amount Amount.
335
	 *
336
	 * @return bool
337
	 */
338 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...
339
340
		$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...
341
342
		if ( ! $donor ) {
343
			return false;
344
		}
345
346
		$decreased_count = $donor->decrease_donation_count();
347
		$decreased_value = $donor->decrease_value( $amount );
348
349
		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...
350
351
	}
352
353
	/**
354
	 * Updates the email address of a donor record when the email on a user is updated
355
	 *
356
	 * @since  1.4.3
357
	 * @access public
358
	 *
359
	 * @param  int $user_id User ID.
360
	 * @param  WP_User|bool $old_user_data User data.
361
	 *
362
	 * @return bool
363
	 */
364
	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...
365
366
		$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...
367
368
		if ( ! $donor ) {
369
			return false;
370
		}
371
372
		$user = get_userdata( $user_id );
373
374
		if ( ! empty( $user ) && $user->user_email !== $donor->email ) {
375
376
			if ( ! $this->get_donor_by( 'email', $user->user_email ) ) {
377
378
				$success = $this->update( $donor->id, array( 'email' => $user->user_email ) );
379
380
				if ( $success ) {
381
					// Update some payment meta if we need to
382
					$payments_array = explode( ',', $donor->payment_ids );
383
384
					if ( ! empty( $payments_array ) ) {
385
386
						foreach ( $payments_array as $payment_id ) {
387
388
							give_update_payment_meta( $payment_id, 'email', $user->user_email );
389
390
						}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
391
392
					}
393
394
					/**
395
					 * Fires after updating donor email on user update.
396
					 *
397
					 * @since 1.4.3
398
					 *
399
					 * @param  WP_User $user WordPress User object.
400
					 * @param  Give_Donor $donor Give donor object.
401
					 */
402
					do_action( 'give_update_donor_email_on_user_update', $user, $donor );
403
404
				}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
405
406
			}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
407
408
		}
409
410
	}
411
412
	/**
413
	 * Retrieves a single donor from the database
414
	 *
415
	 * @since  1.0
416
	 * @access public
417
	 *
418
	 * @param  string $field ID or email. Default is 'id'.
419
	 * @param  mixed $value The Customer ID or email to search. Default is 0.
420
	 *
421
	 * @return mixed         Upon success, an object of the donor. Upon failure, NULL
422
	 */
423
	public function get_donor_by( $field = 'id', $value = 0 ) {
424
		/* @var WPDB $wpdb */
425
		global $wpdb;
426
427
		if ( empty( $field ) || empty( $value ) ) {
428
			return null;
429
		}
430
431
		if ( 'id' == $field || 'user_id' == $field ) {
432
			// Make sure the value is numeric to avoid casting objects, for example,
433
			// to int 1.
434
			if ( ! is_numeric( $value ) ) {
435
				return false;
436
			}
437
438
			$value = intval( $value );
439
440
			if ( $value < 1 ) {
441
				return false;
442
			}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
443
444
		} elseif ( 'email' === $field ) {
445
446
			if ( ! is_email( $value ) ) {
447
				return false;
448
			}
449
450
			$value = trim( $value );
451
		}
452
453
		if ( ! $value ) {
454
			return false;
455
		}
456
457
		switch ( $field ) {
458
			case 'id':
459
				$db_field = 'id';
460
				break;
461
			case 'email':
462
				$value    = sanitize_text_field( $value );
463
				$db_field = 'email';
464
				break;
465
			case 'user_id':
466
				$db_field = 'user_id';
467
				break;
468
			default:
469
				return false;
470
		}
471
472
		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...
473
474
			// Look for donor from an additional email.
475
			if ( 'email' === $field ) {
476
				$meta_table = Give()->donor_meta->table_name;
477
				$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...
478
479
				if ( ! empty( $donor_id ) ) {
480
					return $this->get( $donor_id );
481
				}
482
			}
483
484
			return false;
485
		}
486
487
		return $donor;
488
	}
489
490
	/**
491
	 * Retrieve donors from the database.
492
	 *
493
	 * @since  1.0
494
	 * @access public
495
	 *
496
	 * @param  array $args
497
	 *
498
	 * @return array|object|null Customers array or object. Null if not found.
499
	 */
500
	public function get_donors( $args = array() ) {
501
		/* @var WPDB $wpdb */
502
		global $wpdb;
503
504
		$defaults = array(
505
			'number'  => 20,
506
			'offset'  => 0,
507
			'user_id' => 0,
508
			'orderby' => 'id',
509
			'order'   => 'DESC'
0 ignored issues
show
introduced by
Each line in an array declaration must end in a comma
Loading history...
510
		);
511
512
		$args = wp_parse_args( $args, $defaults );
513
514
		if ( $args['number'] < 1 ) {
515
			$args['number'] = 999999999999;
516
		}
517
518
		$where = ' WHERE 1=1 ';
519
520
		// specific donors.
521 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...
522
523
			if ( is_array( $args['id'] ) ) {
524
				$ids = implode( ',', array_map( 'intval', $args['id'] ) );
525
			} else {
526
				$ids = intval( $args['id'] );
527
			}
528
529
			$where .= " AND `id` IN( {$ids} ) ";
530
531
		}
532
533
		// donors for specific user accounts
534 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...
535
536
			if ( is_array( $args['user_id'] ) ) {
537
				$user_ids = implode( ',', array_map( 'intval', $args['user_id'] ) );
538
			} else {
539
				$user_ids = intval( $args['user_id'] );
540
			}
541
542
			$where .= " AND `user_id` IN( {$user_ids} ) ";
543
544
		}
545
546
		//specific donors by email
547
		if ( ! empty( $args['email'] ) ) {
548
549
			if ( is_array( $args['email'] ) ) {
550
551
				$emails_count       = count( $args['email'] );
552
				$emails_placeholder = array_fill( 0, $emails_count, '%s' );
553
				$emails             = implode( ', ', $emails_placeholder );
554
555
				$where .= $wpdb->prepare( " AND `email` IN( $emails ) ", $args['email'] );
556
			} else {
557
				$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...
558
			}
559
		}
560
561
		// specific donors by name
562
		if ( ! empty( $args['name'] ) ) {
563
			$where .= $wpdb->prepare( " AND `name` LIKE '%%%%" . '%s' . "%%%%' ", $args['name'] );
564
		}
565
566
		// Donors created for a specific date or in a date range
567
		if ( ! empty( $args['date'] ) ) {
568
569
			if ( is_array( $args['date'] ) ) {
570
571 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...
572
573
					$start = date( 'Y-m-d H:i:s', strtotime( $args['date']['start'] ) );
574
575
					$where .= " AND `date_created` >= '{$start}'";
576
577
				}
578
579 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...
580
581
					$end = date( 'Y-m-d H:i:s', strtotime( $args['date']['end'] ) );
582
583
					$where .= " AND `date_created` <= '{$end}'";
584
585
				}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
586
587 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...
588
589
				$year  = date( 'Y', strtotime( $args['date'] ) );
590
				$month = date( 'm', strtotime( $args['date'] ) );
591
				$day   = date( 'd', strtotime( $args['date'] ) );
592
593
				$where .= " AND $year = YEAR ( date_created ) AND $month = MONTH ( date_created ) AND $day = DAY ( date_created )";
594
			}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
595
596
		}
597
598
		$args['orderby'] = ! array_key_exists( $args['orderby'], $this->get_columns() ) ? 'id' : $args['orderby'];
599
600
		if ( 'purchase_value' == $args['orderby'] ) {
601
			$args['orderby'] = 'purchase_value+0';
602
		}
603
604
		$cache_key = md5( 'give_donors_' . serialize( $args ) );
605
606
		$donors = wp_cache_get( $cache_key, 'donors' );
607
608
		$args['orderby'] = esc_sql( $args['orderby'] );
609
		$args['order']   = esc_sql( $args['order'] );
610
611
		if ( $donors === false ) {
0 ignored issues
show
introduced by
Found "=== false". Use Yoda Condition checks, you must
Loading history...
612
			$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...
613
			wp_cache_set( $cache_key, $donors, 'donors', 3600 );
614
		}
615
616
		return $donors;
617
618
	}
619
620
621
	/**
622
	 * Count the total number of donors in the database
623
	 *
624
	 * @since  1.0
625
	 * @access public
626
	 *
627
	 * @param  array $args
628
	 *
629
	 * @return int         Total number of donors.
630
	 */
631
	public function count( $args = array() ) {
632
		/* @var WPDB $wpdb */
633
		global $wpdb;
634
635
		$where = ' WHERE 1=1 ';
636
637
		if ( ! empty( $args['date'] ) ) {
638
639
			if ( is_array( $args['date'] ) ) {
640
641
				$start = date( 'Y-m-d H:i:s', strtotime( $args['date']['start'] ) );
642
				$end   = date( 'Y-m-d H:i:s', strtotime( $args['date']['end'] ) );
643
644
				$where .= " AND `date_created` >= '{$start}' AND `date_created` <= '{$end}'";
645
646 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...
647
648
				$year  = date( 'Y', strtotime( $args['date'] ) );
649
				$month = date( 'm', strtotime( $args['date'] ) );
650
				$day   = date( 'd', strtotime( $args['date'] ) );
651
652
				$where .= " AND $year = YEAR ( date_created ) AND $month = MONTH ( date_created ) AND $day = DAY ( date_created )";
653
			}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
654
655
		}
656
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
657
658
		$cache_key = md5( 'give_donors_count' . serialize( $args ) );
659
660
		$count = wp_cache_get( $cache_key, 'donors' );
661
662
		if ( $count === false ) {
0 ignored issues
show
introduced by
Found "=== false". Use Yoda Condition checks, you must
Loading history...
663
			$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...
664
			wp_cache_set( $cache_key, $count, 'donors', 3600 );
665
		}
666
667
		return absint( $count );
668
669
	}
670
671
	/**
672
	 * Create the table
673
	 *
674
	 * @since  1.0
675
	 * @access public
676
	 *
677
	 * @return void
678
	 */
679 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...
680
681
		require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
682
683
		$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...
684
		id bigint(20) NOT NULL AUTO_INCREMENT,
685
		user_id bigint(20) NOT NULL,
686
		email varchar(50) NOT NULL,
687
		name mediumtext NOT NULL,
688
		purchase_value mediumtext NOT NULL,
689
		purchase_count bigint(20) NOT NULL,
690
		payment_ids longtext NOT NULL,
691
		notes longtext NOT NULL,
692
		date_created datetime NOT NULL,
693
		PRIMARY KEY  (id),
694
		UNIQUE KEY email (email),
695
		KEY user (user_id)
696
		) CHARACTER SET utf8 COLLATE utf8_general_ci;";
697
698
		dbDelta( $sql );
699
700
		update_option( $this->table_name . '_db_version', $this->version );
701
	}
702
703
	/**
704
	 * Check if the Customers table was ever installed
705
	 *
706
	 * @since  1.4.3
707
	 * @access public
708
	 *
709
	 * @return bool Returns if the donors table was installed and upgrade routine run.
710
	 */
711
	public function installed() {
712
		return $this->table_exists( $this->table_name );
713
	}
714
715
}
716