Test Failed
Push — issues/370 ( da4d1b...967cb5 )
by Ravinder
05:08
created

Give_Donor::update_address()   C

Complexity

Conditions 8
Paths 48

Size

Total Lines 50
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 26
nc 48
nop 2
dl 0
loc 50
rs 6.3636
c 0
b 0
f 0
1
<?php
2
/**
3
 * Donor
4
 *
5
 * @package     Give
6
 * @subpackage  Classes/Give_Donor
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_Donor Class
19
 *
20
 * This class handles customers.
21
 *
22
 * @since 1.0
23
 */
24
class Give_Donor {
25
26
	/**
27
	 * The donor ID
28
	 *
29
	 * @since  1.0
30
	 * @access public
31
	 *
32
	 * @var    int
33
	 */
34
	public $id = 0;
35
36
	/**
37
	 * The donor's donation count.
38
	 *
39
	 * @since  1.0
40
	 * @access public
41
	 *
42
	 * @var    int
43
	 */
44
	public $purchase_count = 0;
45
46
	/**
47
	 * The donor's lifetime value.
48
	 *
49
	 * @since  1.0
50
	 * @access public
51
	 *
52
	 * @var    int
53
	 */
54
	public $purchase_value = 0;
55
56
	/**
57
	 * The donor's email.
58
	 *
59
	 * @since  1.0
60
	 * @access public
61
	 *
62
	 * @var    string
63
	 */
64
	public $email;
65
66
	/**
67
	 * The donor's emails.
68
	 *
69
	 * @since  1.7
70
	 * @access public
71
	 *
72
	 * @var    array
73
	 */
74
	public $emails;
75
76
	/**
77
	 * The donor's name.
78
	 *
79
	 * @since  1.0
80
	 * @access public
81
	 *
82
	 * @var    string
83
	 */
84
	public $name;
85
86
	/**
87
	 * The donor creation date.
88
	 *
89
	 * @since  1.0
90
	 * @access public
91
	 *
92
	 * @var    string
93
	 */
94
	public $date_created;
95
96
	/**
97
	 * The payment IDs associated with the donor.
98
	 *
99
	 * @since  1.0
100
	 * @access public
101
	 *
102
	 * @var    string
103
	 */
104
	public $payment_ids;
105
106
	/**
107
	 * The user ID associated with the donor.
108
	 *
109
	 * @since  1.0
110
	 * @access public
111
	 *
112
	 * @var    int
113
	 */
114
	public $user_id;
115
116
	/**
117
	 * Donor notes saved by admins.
118
	 *
119
	 * @since  1.0
120
	 * @access public
121
	 *
122
	 * @var    string
123
	 */
124
	public $notes;
125
126
	/**
127
	 * Donor address.
128
	 *
129
	 * @since  1.0
130
	 * @access public
131
	 *
132
	 * @var    array
133
	 */
134
	public $address;
135
136
	/**
137
	 * The Database Abstraction
138
	 *
139
	 * @since  1.0
140
	 * @access protected
141
	 *
142
	 * @var    Give_DB_Donors
143
	 */
144
	protected $db;
145
146
	/**
147
	 * Give_Donor constructor.
148
	 *
149
	 * @param bool $_id_or_email
150
	 * @param bool $by_user_id
151
	 */
152
	public function __construct( $_id_or_email = false, $by_user_id = false ) {
153
154
		$this->db = Give()->donors;
155
156
		if (
157
			false === $_id_or_email
158
			|| ( is_numeric( $_id_or_email ) && (int) $_id_or_email !== absint( $_id_or_email ) )
159
		) {
160
			return false;
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
161
		}
162
163
		$by_user_id = is_bool( $by_user_id ) ? $by_user_id : false;
164
165
		if ( is_numeric( $_id_or_email ) ) {
166
			$field = $by_user_id ? 'user_id' : 'id';
167
		} else {
168
			$field = 'email';
169
		}
170
171
		$donor = $this->db->get_donor_by( $field, $_id_or_email );
172
173
		if ( empty( $donor ) || ! is_object( $donor ) ) {
174
			return false;
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
175
		}
176
177
		$this->setup_donor( $donor );
178
179
	}
180
181
	/**
182
	 * Setup Donor
183
	 *
184
	 * Set donor variables.
185
	 *
186
	 * @since  1.0
187
	 * @access private
188
	 *
189
	 * @param  object $donor The Donor Object.
190
	 *
191
	 * @return bool             If the setup was successful or not.
192
	 */
193
	private function setup_donor( $donor ) {
194
195
		if ( ! is_object( $donor ) ) {
196
			return false;
197
		}
198
199
		foreach ( $donor as $key => $value ) {
200
201
			switch ( $key ) {
202
203
				case 'notes':
204
					$this->$key = $this->get_notes();
205
					break;
206
207
				default:
208
					$this->$key = $value;
209
					break;
210
211
			}
212
		}
213
214
		// Get donor's all email including primary email.
215
		$this->emails = (array) $this->get_meta( 'additional_email', false );
216
		$this->emails = array( 'primary' => $this->email ) + $this->emails;
217
218
		$this->setup_address();
219
220
		// Donor ID and email are the only things that are necessary, make sure they exist.
221
		if ( ! empty( $this->id ) && ! empty( $this->email ) ) {
222
			return true;
223
		}
224
225
		return false;
226
227
	}
228
229
230
	/**
231
	 * Setup donor address.
232
	 *
233
	 * @since 2.0
234
	 * @access public
235
	 */
236
	public function setup_address() {
237
		global $wpdb;
238
		$meta_type = Give()->donor_meta->meta_type;
239
240
		$addresses = $wpdb->get_results(
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...
241
			$wpdb->prepare(
242
				"
243
				SELECT meta_key, meta_value FROM {$wpdb->donormeta}
244
				WHERE meta_key
245
				LIKE '%%%s%%'
246
				AND {$meta_type}_id=%d
247
				",
248
				'give_donor_address',
249
				$this->id
250
			),
251
			ARRAY_N
252
		);
253
254
		if ( empty( $addresses ) ) {
255
			return array();
256
		}
257
258
		foreach ( $addresses as $address ) {
259
			$address[0] = str_replace( '_give_donor_address_', '', $address[0] );
260
			$address[0] = explode( '_', $address[0] );
261
262
			if ( 'address1' === $address[0][1] ) {
263
				$address[0][1] = 'line1';
264
			} elseif ( 'address2' === $address[0][1] ) {
265
				$address[0][1] = 'line2';
266
			}
267
268
			if ( 3 === count( $address[0] ) ) {
269
				$this->address[ $address[0][0] ][ $address[0][2] ][ $address[0][1] ] = $address[1];
270
			} else {
271
				$this->address[ $address[0][0] ][ $address[0][1] ] = $address[1];
272
			}
273
		}
274
	}
275
276
	/**
277
	 * Magic __get function to dispatch a call to retrieve a private property.
278
	 *
279
	 * @since  1.0
280
	 * @access public
281
	 * @param $key
282
	 *
283
	 * @return mixed|\WP_Error
284
	 */
285 View Code Duplication
	public function __get( $key ) {
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...
286
287
		if ( method_exists( $this, 'get_' . $key ) ) {
288
289
			return call_user_func( array( $this, 'get_' . $key ) );
290
291
		} else {
292
293
			/* translators: %s: property key */
294
			return new WP_Error( 'give-donor-invalid-property', sprintf( esc_html__( 'Can\'t get property %s.', 'give' ), $key ) );
295
296
		}
297
298
	}
299
300
	/**
301
	 * Creates a donor.
302
	 *
303
	 * @since  1.0
304
	 * @access public
305
	 *
306
	 * @param  array $data Array of attributes for a donor.
307
	 *
308
	 * @return bool|int    False if not a valid creation, donor ID if user is found or valid creation.
309
	 */
310
	public function create( $data = array() ) {
311
312
		if ( $this->id != 0 || empty( $data ) ) {
0 ignored issues
show
introduced by
Found "!= 0". Use Yoda Condition checks, you must
Loading history...
313
			return false;
314
		}
315
316
		$defaults = array(
317
			'payment_ids' => '',
318
		);
319
320
		$args = wp_parse_args( $data, $defaults );
321
		$args = $this->sanitize_columns( $args );
322
323
		if ( empty( $args['email'] ) || ! is_email( $args['email'] ) ) {
324
			return false;
325
		}
326
327 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...
328
			$args['payment_ids'] = implode( ',', array_unique( array_values( $args['payment_ids'] ) ) );
329
		}
330
331
		/**
332
		 * Fires before creating donors.
333
		 *
334
		 * @since 1.0
335
		 *
336
		 * @param array $args Donor attributes.
337
		 */
338
		do_action( 'give_donor_pre_create', $args );
339
340
		$created = false;
341
342
		// The DB class 'add' implies an update if the donor being asked to be created already exists
343 View Code Duplication
		if ( $this->db->add( $data ) ) {
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...
344
345
			// We've successfully added/updated the donor, reset the class vars with the new data
346
			$donor = $this->db->get_donor_by( 'email', $args['email'] );
347
348
			// Setup the donor data with the values from DB
349
			$this->setup_donor( $donor );
350
351
			$created = $this->id;
352
		}
353
354
		/**
355
		 * Fires after creating donors.
356
		 *
357
		 * @since 1.0
358
		 *
359
		 * @param bool|int $created False if not a valid creation, donor ID if user is found or valid creation.
360
		 * @param array $args Customer attributes.
361
		 */
362
		do_action( 'give_donor_post_create', $created, $args );
363
364
		return $created;
365
366
	}
367
368
	/**
369
	 * Updates a donor record.
370
	 *
371
	 * @since  1.0
372
	 * @access public
373
	 *
374
	 * @param  array $data Array of data attributes for a donor (checked via whitelist).
375
	 *
376
	 * @return bool        If the update was successful or not.
377
	 */
378
	public function update( $data = array() ) {
379
380
		if ( empty( $data ) ) {
381
			return false;
382
		}
383
384
		$data = $this->sanitize_columns( $data );
385
386
		/**
387
		 * Fires before updating donors.
388
		 *
389
		 * @since 1.0
390
		 *
391
		 * @param int $donor_id Donor id.
392
		 * @param array $data Donor attributes.
393
		 */
394
		do_action( 'give_donor_pre_update', $this->id, $data );
395
396
		$updated = false;
397
398 View Code Duplication
		if ( $this->db->update( $this->id, $data ) ) {
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...
399
400
			$donor = $this->db->get_donor_by( 'id', $this->id );
401
			$this->setup_donor( $donor );
402
403
			$updated = true;
404
		}
405
406
		/**
407
		 * Fires after updating donors.
408
		 *
409
		 * @since 1.0
410
		 *
411
		 * @param bool $updated If the update was successful or not.
412
		 * @param int $donor_id Donor id.
413
		 * @param array $data Donor attributes.
414
		 */
415
		do_action( 'give_donor_post_update', $updated, $this->id, $data );
416
417
		return $updated;
418
	}
419
420
	/**
421
	 * Attach Payment
422
	 *
423
	 * Attach payment to the donor then triggers increasing stats.
424
	 *
425
	 * @since  1.0
426
	 * @access public
427
	 *
428
	 * @param  int $payment_id The payment ID to attach to the donor.
429
	 * @param  bool $update_stats For backwards compatibility, if we should increase the stats or not.
430
	 *
431
	 * @return bool            If the attachment was successfully.
432
	 */
433
	public function attach_payment( $payment_id = 0, $update_stats = true ) {
434
435
		if ( empty( $payment_id ) ) {
436
			return false;
437
		}
438
439
		if ( empty( $this->payment_ids ) ) {
440
441
			$new_payment_ids = $payment_id;
442
443
		} else {
444
445
			$payment_ids = array_map( 'absint', explode( ',', $this->payment_ids ) );
446
447
			if ( in_array( $payment_id, $payment_ids ) ) {
448
				$update_stats = false;
449
			}
450
451
			$payment_ids[] = $payment_id;
452
453
			$new_payment_ids = implode( ',', array_unique( array_values( $payment_ids ) ) );
454
455
		}
456
457
		/**
458
		 * Fires before attaching payments to customers.
459
		 *
460
		 * @since 1.0
461
		 *
462
		 * @param int $payment_id Payment id.
463
		 * @param int $donor_id Customer id.
464
		 */
465
		do_action( 'give_donor_pre_attach_payment', $payment_id, $this->id );
466
467
		$payment_added = $this->update( array( 'payment_ids' => $new_payment_ids ) );
468
469 View Code Duplication
		if ( $payment_added ) {
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...
470
471
			$this->payment_ids = $new_payment_ids;
0 ignored issues
show
Documentation Bug introduced by
It seems like $new_payment_ids can also be of type integer. However, the property $payment_ids is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
472
473
			// We added this payment successfully, increment the stats
474
			if ( $update_stats ) {
475
				$payment_amount = give_get_payment_amount( $payment_id );
476
477
				if ( ! empty( $payment_amount ) ) {
478
					$this->increase_value( $payment_amount );
479
				}
480
481
				$this->increase_purchase_count();
482
			}
483
		}
484
485
		/**
486
		 * Fires after attaching payments to the donor.
487
		 *
488
		 * @since 1.0
489
		 *
490
		 * @param bool $payment_added If the attachment was successfully.
491
		 * @param int $payment_id Payment id.
492
		 * @param int $donor_id Donor id.
493
		 */
494
		do_action( 'give_donor_post_attach_payment', $payment_added, $payment_id, $this->id );
495
496
		return $payment_added;
497
	}
498
499
	/**
500
	 * Remove Payment
501
	 *
502
	 * Remove a payment from this donor, then triggers reducing stats.
503
	 *
504
	 * @since  1.0
505
	 * @access public
506
	 *
507
	 * @param  int $payment_id The Payment ID to remove.
508
	 * @param  bool $update_stats For backwards compatibility, if we should increase the stats or not.
509
	 *
510
	 * @return boolean               If the removal was successful.
511
	 */
512
	public function remove_payment( $payment_id = 0, $update_stats = true ) {
513
514
		if ( empty( $payment_id ) ) {
515
			return false;
516
		}
517
518
		$payment = new Give_Payment( $payment_id );
519
520
		if ( 'publish' !== $payment->status && 'revoked' !== $payment->status ) {
521
			$update_stats = false;
522
		}
523
524
		$new_payment_ids = '';
525
526
		if ( ! empty( $this->payment_ids ) ) {
527
528
			$payment_ids = array_map( 'absint', explode( ',', $this->payment_ids ) );
529
530
			$pos = array_search( $payment_id, $payment_ids );
531
			if ( false === $pos ) {
532
				return false;
533
			}
534
535
			unset( $payment_ids[ $pos ] );
536
			$payment_ids = array_filter( $payment_ids );
537
538
			$new_payment_ids = implode( ',', array_unique( array_values( $payment_ids ) ) );
539
540
		}
541
542
		/**
543
		 * Fires before removing payments from customers.
544
		 *
545
		 * @since 1.0
546
		 *
547
		 * @param int $payment_id Payment id.
548
		 * @param int $donor_id Customer id.
549
		 */
550
		do_action( 'give_donor_pre_remove_payment', $payment_id, $this->id );
551
552
		$payment_removed = $this->update( array( 'payment_ids' => $new_payment_ids ) );
553
554 View Code Duplication
		if ( $payment_removed ) {
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...
555
556
			$this->payment_ids = $new_payment_ids;
557
558
			if ( $update_stats ) {
559
				// We removed this payment successfully, decrement the stats
560
				$payment_amount = give_get_payment_amount( $payment_id );
561
562
				if ( ! empty( $payment_amount ) ) {
563
					$this->decrease_value( $payment_amount );
564
				}
565
566
				$this->decrease_donation_count();
567
			}
568
		}
569
570
		/**
571
		 * Fires after removing payments from donors.
572
		 *
573
		 * @since 1.0
574
		 *
575
		 * @param bool $payment_removed If the removal was successfully.
576
		 * @param int $payment_id Payment id.
577
		 * @param int $donor_id Donor id.
578
		 */
579
		do_action( 'give_donor_post_remove_payment', $payment_removed, $payment_id, $this->id );
580
581
		return $payment_removed;
582
583
	}
584
585
	/**
586
	 * Increase the donation count of a donor.
587
	 *
588
	 * @since  1.0
589
	 * @access public
590
	 *
591
	 * @param  int $count The number to increase by.
592
	 *
593
	 * @return int        The donation count.
594
	 */
595
	public function increase_purchase_count( $count = 1 ) {
596
597
		// Make sure it's numeric and not negative.
598
		if ( ! is_numeric( $count ) || $count != absint( $count ) ) {
599
			return false;
600
		}
601
602
		$new_total = (int) $this->purchase_count + (int) $count;
603
604
		/**
605
		 * Fires before increasing the donor's donation count.
606
		 *
607
		 * @since 1.0
608
		 *
609
		 * @param int $count The number to increase by.
610
		 * @param int $donor_id Donor id.
611
		 */
612
		do_action( 'give_donor_pre_increase_donation_count', $count, $this->id );
613
614
		if ( $this->update( array( 'purchase_count' => $new_total ) ) ) {
615
			$this->purchase_count = $new_total;
616
		}
617
618
		/**
619
		 * Fires after increasing the donor's donation count.
620
		 *
621
		 * @since 1.0
622
		 *
623
		 * @param int $purchase_count Donor donation count.
624
		 * @param int $count The number increased by.
625
		 * @param int $donor_id Donor id.
626
		 */
627
		do_action( 'give_donor_post_increase_donation_count', $this->purchase_count, $count, $this->id );
628
629
		return $this->purchase_count;
630
	}
631
632
	/**
633
	 * Decrease the donor donation count.
634
	 *
635
	 * @since  1.0
636
	 * @access public
637
	 *
638
	 * @param  int $count The amount to decrease by.
639
	 *
640
	 * @return mixed      If successful, the new count, otherwise false.
641
	 */
642
	public function decrease_donation_count( $count = 1 ) {
643
644
		// Make sure it's numeric and not negative
645
		if ( ! is_numeric( $count ) || $count != absint( $count ) ) {
646
			return false;
647
		}
648
649
		$new_total = (int) $this->purchase_count - (int) $count;
650
651
		if ( $new_total < 0 ) {
652
			$new_total = 0;
653
		}
654
655
		/**
656
		 * Fires before decreasing the donor's donation count.
657
		 *
658
		 * @since 1.0
659
		 *
660
		 * @param int $count The number to decrease by.
661
		 * @param int $donor_id Customer id.
662
		 */
663
		do_action( 'give_donor_pre_decrease_donation_count', $count, $this->id );
664
665
		if ( $this->update( array( 'purchase_count' => $new_total ) ) ) {
666
			$this->purchase_count = $new_total;
667
		}
668
669
		/**
670
		 * Fires after decreasing the donor's donation count.
671
		 *
672
		 * @since 1.0
673
		 *
674
		 * @param int $purchase_count Donor's donation count.
675
		 * @param int $count The number decreased by.
676
		 * @param int $donor_id Donor id.
677
		 */
678
		do_action( 'give_donor_post_decrease_donation_count', $this->purchase_count, $count, $this->id );
679
680
		return $this->purchase_count;
681
	}
682
683
	/**
684
	 * Increase the donor's lifetime value.
685
	 *
686
	 * @since  1.0
687
	 * @access public
688
	 *
689
	 * @param  float $value The value to increase by.
690
	 *
691
	 * @return mixed        If successful, the new value, otherwise false.
692
	 */
693
	public function increase_value( $value = 0.00 ) {
694
695
		$new_value = floatval( $this->purchase_value ) + $value;
696
697
		/**
698
		 * Fires before increasing donor lifetime value.
699
		 *
700
		 * @since 1.0
701
		 *
702
		 * @param float $value The value to increase by.
703
		 * @param int $donor_id Customer id.
704
		 */
705
		do_action( 'give_donor_pre_increase_value', $value, $this->id );
706
707
		if ( $this->update( array( 'purchase_value' => $new_value ) ) ) {
708
			$this->purchase_value = $new_value;
0 ignored issues
show
Documentation Bug introduced by
The property $purchase_value was declared of type integer, but $new_value is of type double. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
709
		}
710
711
		/**
712
		 * Fires after increasing donor lifetime value.
713
		 *
714
		 * @since 1.0
715
		 *
716
		 * @param float $purchase_value Donor's lifetime value.
717
		 * @param float $value The value increased by.
718
		 * @param int $donor_id Donor id.
719
		 */
720
		do_action( 'give_donor_post_increase_value', $this->purchase_value, $value, $this->id );
721
722
		return $this->purchase_value;
723
	}
724
725
	/**
726
	 * Decrease a donor's lifetime value.
727
	 *
728
	 * @since  1.0
729
	 * @access public
730
	 *
731
	 * @param  float $value The value to decrease by.
732
	 *
733
	 * @return mixed        If successful, the new value, otherwise false.
734
	 */
735
	public function decrease_value( $value = 0.00 ) {
736
737
		$new_value = floatval( $this->purchase_value ) - $value;
738
739
		if ( $new_value < 0 ) {
740
			$new_value = 0.00;
741
		}
742
743
		/**
744
		 * Fires before decreasing donor lifetime value.
745
		 *
746
		 * @since 1.0
747
		 *
748
		 * @param float $value The value to decrease by.
749
		 * @param int $donor_id Donor id.
750
		 */
751
		do_action( 'give_donor_pre_decrease_value', $value, $this->id );
752
753
		if ( $this->update( array( 'purchase_value' => $new_value ) ) ) {
754
			$this->purchase_value = $new_value;
0 ignored issues
show
Documentation Bug introduced by
The property $purchase_value was declared of type integer, but $new_value is of type double. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
755
		}
756
757
		/**
758
		 * Fires after decreasing donor lifetime value.
759
		 *
760
		 * @since 1.0
761
		 *
762
		 * @param float $purchase_value Donor lifetime value.
763
		 * @param float $value The value decreased by.
764
		 * @param int $donor_id Donor id.
765
		 */
766
		do_action( 'give_donor_post_decrease_value', $this->purchase_value, $value, $this->id );
767
768
		return $this->purchase_value;
769
	}
770
771
	/**
772
	 * Decrease/Increase a donor's lifetime value.
773
	 *
774
	 * This function will update donation stat on basis of current amount and new amount donation difference.
775
	 * Difference value can positive or negative. Negative value will decrease user donation stat while positive value increase donation stat.
776
	 *
777
	 * @since  1.0
778
	 * @access public
779
	 *
780
	 * @param  float $curr_amount Current Donation amount.
781
	 * @param  float $new_amount New (changed) Donation amount.
782
	 *
783
	 * @return mixed              If successful, the new donation stat value, otherwise false.
784
	 */
785
	public function update_donation_value( $curr_amount, $new_amount ) {
786
		/**
787
		 * Payment total difference value can be:
788
		 *  zero   (in case amount not change)
789
		 *  or -ve (in case amount decrease)
790
		 *  or +ve (in case amount increase)
791
		 */
792
		$payment_total_diff = $new_amount - $curr_amount;
793
794
		// We do not need to update donation stat if donation did not change.
795
		if ( ! $payment_total_diff ) {
796
			return false;
797
		}
798
799
		if ( $payment_total_diff > 0 ) {
800
			$this->increase_value( $payment_total_diff );
801
		} else {
802
			// Pass payment total difference as +ve value to decrease amount from user lifetime stat.
803
			$this->decrease_value( - $payment_total_diff );
804
		}
805
806
		return $this->purchase_value;
807
	}
808
809
	/**
810
	 * Get the parsed notes for a donor as an array.
811
	 *
812
	 * @since  1.0
813
	 * @access public
814
	 *
815
	 * @param  int $length The number of notes to get.
816
	 * @param  int $paged What note to start at.
817
	 *
818
	 * @return array       The notes requested.
819
	 */
820
	public function get_notes( $length = 20, $paged = 1 ) {
821
822
		$length = is_numeric( $length ) ? $length : 20;
823
		$offset = is_numeric( $paged ) && $paged != 1 ? ( ( absint( $paged ) - 1 ) * $length ) : 0;
824
825
		$all_notes   = $this->get_raw_notes();
826
		$notes_array = array_reverse( array_filter( explode( "\n\n", $all_notes ) ) );
827
828
		$desired_notes = array_slice( $notes_array, $offset, $length );
829
830
		return $desired_notes;
831
832
	}
833
834
	/**
835
	 * Get the total number of notes we have after parsing.
836
	 *
837
	 * @since  1.0
838
	 * @access public
839
	 *
840
	 * @return int The number of notes for the donor.
841
	 */
842
	public function get_notes_count() {
843
844
		$all_notes   = $this->get_raw_notes();
845
		$notes_array = array_reverse( array_filter( explode( "\n\n", $all_notes ) ) );
846
847
		return count( $notes_array );
848
849
	}
850
851
	/**
852
	 * Add a note for the donor.
853
	 *
854
	 * @since  1.0
855
	 * @access public
856
	 *
857
	 * @param  string $note The note to add. Default is empty.
858
	 *
859
	 * @return string|boolean The new note if added successfully, false otherwise.
860
	 */
861
	public function add_note( $note = '' ) {
862
863
		$note = trim( $note );
864
		if ( empty( $note ) ) {
865
			return false;
866
		}
867
868
		$notes = $this->get_raw_notes();
869
870
		if ( empty( $notes ) ) {
871
			$notes = '';
872
		}
873
874
		$note_string = date_i18n( 'F j, Y H:i:s', current_time( 'timestamp' ) ) . ' - ' . $note;
875
		$new_note    = apply_filters( 'give_customer_add_note_string', $note_string );
876
		$notes       .= "\n\n" . $new_note;
877
878
		/**
879
		 * Fires before donor note is added.
880
		 *
881
		 * @since 1.0
882
		 *
883
		 * @param string $new_note New note to add.
884
		 * @param int $donor_id Donor id.
885
		 */
886
		do_action( 'give_donor_pre_add_note', $new_note, $this->id );
887
888
		$updated = $this->update( array( 'notes' => $notes ) );
889
890
		if ( $updated ) {
891
			$this->notes = $this->get_notes();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->get_notes() of type array is incompatible with the declared type string of property $notes.

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...
892
		}
893
894
		/**
895
		 * Fires after donor note added.
896
		 *
897
		 * @since 1.0
898
		 *
899
		 * @param array $donor_notes Donor notes.
900
		 * @param string $new_note New note added.
901
		 * @param int $donor_id Donor id.
902
		 */
903
		do_action( 'give_donor_post_add_note', $this->notes, $new_note, $this->id );
904
905
		// Return the formatted note, so we can test, as well as update any displays
906
		return $new_note;
907
908
	}
909
910
	/**
911
	 * Get the notes column for the donor
912
	 *
913
	 * @since  1.0
914
	 * @access private
915
	 *
916
	 * @return string The Notes for the donor, non-parsed.
917
	 */
918
	private function get_raw_notes() {
919
920
		$all_notes = $this->db->get_column( 'notes', $this->id );
921
922
		return $all_notes;
923
924
	}
925
926
	/**
927
	 * Retrieve a meta field for a donor.
928
	 *
929
	 * @since  1.6
930
	 * @access public
931
	 *
932
	 * @param  string $meta_key The meta key to retrieve. Default is empty.
933
	 * @param  bool $single Whether to return a single value. Default is true.
934
	 *
935
	 * @return mixed            Will be an array if $single is false. Will be value of meta data field if $single is true.
936
	 */
937
	public function get_meta( $meta_key = '', $single = true ) {
938
		return Give()->donor_meta->get_meta( $this->id, $meta_key, $single );
939
	}
940
941
	/**
942
	 * Add a meta data field to a donor.
943
	 *
944
	 * @since  1.6
945
	 * @access public
946
	 *
947
	 * @param  string $meta_key Metadata name. Default is empty.
948
	 * @param  mixed $meta_value Metadata value.
949
	 * @param  bool $unique Optional. Whether the same key should not be added. Default is false.
950
	 *
951
	 * @return bool               False for failure. True for success.
952
	 */
953
	public function add_meta( $meta_key = '', $meta_value, $unique = false ) {
954
		return Give()->donor_meta->add_meta( $this->id, $meta_key, $meta_value, $unique );
955
	}
956
957
	/**
958
	 * Update a meta field based on donor ID.
959
	 *
960
	 * @since  1.6
961
	 * @access public
962
	 *
963
	 * @param  string $meta_key Metadata key. Default is empty.
964
	 * @param  mixed $meta_value Metadata value.
965
	 * @param  mixed $prev_value Optional. Previous value to check before removing. Default is empty.
966
	 *
967
	 * @return bool               False on failure, true if success.
968
	 */
969
	public function update_meta( $meta_key = '', $meta_value, $prev_value = '' ) {
970
		return Give()->donor_meta->update_meta( $this->id, $meta_key, $meta_value, $prev_value );
971
	}
972
973
	/**
974
	 * Remove metadata matching criteria from a donor.
975
	 *
976
	 * @since  1.6
977
	 * @access public
978
	 *
979
	 * @param  string $meta_key Metadata name. Default is empty.
980
	 * @param  mixed $meta_value Optional. Metadata value. Default is empty.
981
	 *
982
	 * @return bool               False for failure. True for success.
983
	 */
984
	public function delete_meta( $meta_key = '', $meta_value = '' ) {
985
		return Give()->donor_meta->delete_meta( $this->id, $meta_key, $meta_value );
986
	}
987
988
	/**
989
	 * Sanitize the data for update/create
990
	 *
991
	 * @since  1.0
992
	 * @access private
993
	 *
994
	 * @param  array $data The data to sanitize.
995
	 *
996
	 * @return array       The sanitized data, based off column defaults.
997
	 */
998
	private function sanitize_columns( $data ) {
999
1000
		$columns        = $this->db->get_columns();
1001
		$default_values = $this->db->get_column_defaults();
1002
1003
		foreach ( $columns as $key => $type ) {
1004
1005
			// Only sanitize data that we were provided
1006
			if ( ! array_key_exists( $key, $data ) ) {
1007
				continue;
1008
			}
1009
1010
			switch ( $type ) {
1011
1012
				case '%s':
1013
					if ( 'email' == $key ) {
1014
						$data[ $key ] = sanitize_email( $data[ $key ] );
1015
					} elseif ( 'notes' == $key ) {
1016
						$data[ $key ] = strip_tags( $data[ $key ] );
1017
					} else {
1018
						$data[ $key ] = sanitize_text_field( $data[ $key ] );
1019
					}
1020
					break;
1021
1022
				case '%d':
1023
					if ( ! is_numeric( $data[ $key ] ) || (int) $data[ $key ] !== absint( $data[ $key ] ) ) {
1024
						$data[ $key ] = $default_values[ $key ];
1025
					} else {
1026
						$data[ $key ] = absint( $data[ $key ] );
1027
					}
1028
					break;
1029
1030
				case '%f':
1031
					// Convert what was given to a float
1032
					$value = floatval( $data[ $key ] );
1033
1034
					if ( ! is_float( $value ) ) {
1035
						$data[ $key ] = $default_values[ $key ];
1036
					} else {
1037
						$data[ $key ] = $value;
1038
					}
1039
					break;
1040
1041
				default:
1042
					$data[ $key ] = sanitize_text_field( $data[ $key ] );
1043
					break;
1044
1045
			}
1046
		}
1047
1048
		return $data;
1049
	}
1050
1051
	/**
1052
	 * Attach an email to the donor
1053
	 *
1054
	 * @since  1.7
1055
	 * @access public
1056
	 *
1057
	 * @param  string $email The email address to attach to the donor
1058
	 * @param  bool $primary Allows setting the email added as the primary
1059
	 *
1060
	 * @return bool            If the email was added successfully
1061
	 */
1062
	public function add_email( $email = '', $primary = false ) {
1063
		if ( ! is_email( $email ) ) {
1064
			return false;
1065
		}
1066
		$existing = new Give_Donor( $email );
0 ignored issues
show
Documentation introduced by
$email is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1067
1068
		if ( $existing->id > 0 ) {
1069
			// Email address already belongs to another donor
1070
			return false;
1071
		}
1072
1073
		if ( email_exists( $email ) ) {
1074
			$user = get_user_by( 'email', $email );
1075
			if ( $user->ID != $this->user_id ) {
1076
				return false;
1077
			}
1078
		}
1079
1080
		do_action( 'give_donor_pre_add_email', $email, $this->id, $this );
1081
1082
		// Add is used to ensure duplicate emails are not added
1083
		$ret = (bool) $this->add_meta( 'additional_email', $email );
1084
1085
		do_action( 'give_donor_post_add_email', $email, $this->id, $this );
1086
1087
		if ( $ret && true === $primary ) {
1088
			$this->set_primary_email( $email );
1089
		}
1090
1091
		return $ret;
1092
	}
1093
1094
	/**
1095
	 * Remove an email from the donor.
1096
	 *
1097
	 * @since  1.7
1098
	 * @access public
1099
	 *
1100
	 * @param  string $email The email address to remove from the donor.
1101
	 *
1102
	 * @return bool          If the email was removed successfully.
1103
	 */
1104
	public function remove_email( $email = '' ) {
1105
		if ( ! is_email( $email ) ) {
1106
			return false;
1107
		}
1108
1109
		do_action( 'give_donor_pre_remove_email', $email, $this->id, $this );
1110
1111
		$ret = (bool) $this->delete_meta( 'additional_email', $email );
1112
1113
		do_action( 'give_donor_post_remove_email', $email, $this->id, $this );
1114
1115
		return $ret;
1116
	}
1117
1118
	/**
1119
	 * Set an email address as the donor's primary email.
1120
	 *
1121
	 * This will move the donor's previous primary email to an additional email.
1122
	 *
1123
	 * @since  1.7
1124
	 * @access public
1125
	 *
1126
	 * @param  string $new_primary_email The email address to remove from the donor.
1127
	 *
1128
	 * @return bool                      If the email was set as primary successfully.
1129
	 */
1130
	public function set_primary_email( $new_primary_email = '' ) {
1131
		if ( ! is_email( $new_primary_email ) ) {
1132
			return false;
1133
		}
1134
1135
		do_action( 'give_donor_pre_set_primary_email', $new_primary_email, $this->id, $this );
1136
1137
		$existing = new Give_Donor( $new_primary_email );
0 ignored issues
show
Documentation introduced by
$new_primary_email is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1138
1139
		if ( $existing->id > 0 && (int) $existing->id !== (int) $this->id ) {
1140
			// This email belongs to another donor.
1141
			return false;
1142
		}
1143
1144
		$old_email = $this->email;
1145
1146
		// Update donor record with new email.
1147
		$update = $this->update( array( 'email' => $new_primary_email ) );
1148
1149
		// Remove new primary from list of additional emails.
1150
		$remove = $this->remove_email( $new_primary_email );
1151
1152
		// Add old email to additional emails list.
1153
		$add = $this->add_email( $old_email );
1154
1155
		$ret = $update && $remove && $add;
1156
1157
		if ( $ret ) {
1158
			$this->email = $new_primary_email;
1159
		}
1160
1161
		do_action( 'give_donor_post_set_primary_email', $new_primary_email, $this->id, $this );
1162
1163
		return $ret;
1164
	}
1165
1166
	/**
1167
	 * Add donor address
1168
	 *
1169
	 * @since  2.0
1170
	 * @access public
1171
	 *
1172
	 * @param string $address_type
1173
	 * @param array  $address {
1174
	 *
1175
	 * @type string  $address2
1176
	 * @type string city
1177
	 * @type string zip
1178
	 * @type string state
1179
	 * @type string country
1180
	 * }
1181
	 *
1182
	 * @return bool
1183
	 */
1184
	public function add_address( $address_type, $address ) {
1185
		$is_address_empty = true;
1186
1187
		// Address ready to process even if only one value set.
1188
		foreach ( $address as $value ) {
1189
			if( ! empty( $value ) ) {
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...
1190
				$is_address_empty = false;
1191
				break;
1192
			}
1193
		}
1194
1195
		// Bailout.
1196
		if ( empty( $address_type ) || $is_address_empty || ! $this->id ) {
1197
			return false;
1198
		}
1199
1200
		// Check if multiple address exist or not and set params.
1201
		$multi_address_id = null;
1202
		if( $is_multi_address = ( false !== strpos( $address_type, '[]' ) ) ) {
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...
1203
			$address_type  = $is_multi_address ?
1204
				str_replace( '[]', '', $address_type ) :
1205
				$address_type;
1206
		} elseif ( $is_multi_address = ( false !== strpos( $address_type, '_' ) ) ){
1207
			$multi_address_id =  $is_multi_address ?
0 ignored issues
show
introduced by
Expected 1 space after "="; 2 found
Loading history...
1208
				array_pop( explode( '_', $address_type ) ) :
1209
				$address_type;
1210
1211
			$address_type  = $is_multi_address ?
1212
				array_shift( explode( '_', $address_type ) ) :
1213
				$address_type;
1214
		}
1215
1216
		// Bailout: do not save duplicate orders
1217
		if( $this->is_address_exist( $address_type, $address ) ) {
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...
1218
			return false;
1219
		}
1220
1221
		// Set default address.
1222
		$address = wp_parse_args(
1223
			$address,
1224
			array(
1225
				'line1' => '',
1226
				'line2' => '',
1227
				'city'     => '',
1228
				'state'    => '',
1229
				'country'  => '',
1230
				'zip'      => '',
1231
			)
1232
		);
1233
1234
		// Set meta key prefix.
1235
		global $wpdb;
1236
		$meta_key_prefix = "_give_donor_address_{$address_type}_{address_name}";
1237
		$meta_type = Give()->donor_meta->meta_type;
1238
1239
		if ( $is_multi_address ) {
1240
			if ( is_null( $multi_address_id ) ) {
1241
				$multi_address_id = $wpdb->get_var(
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...
1242
					$wpdb->prepare(
1243
						"
1244
						SELECT COUNT(*) FROM {$wpdb->donormeta}
1245
						WHERE meta_key
1246
						LIKE '%%%s%%'
1247
						AND {$meta_type}_id=%d
1248
						",
1249
						"_give_donor_address_{$address_type}_address1",
1250
						$this->id
1251
					)
1252
				);
1253
1254
				$multi_address_id = absint( $multi_address_id );
1255
			}
1256
1257
			$meta_key_prefix = "_give_donor_address_{$address_type}_{address_name}_{$multi_address_id}";
1258
		}
1259
1260
		// Save donor address.
1261
		foreach ( $address as $type => $value ) {
1262
			$meta_key = str_replace( '{address_name}', $type, $meta_key_prefix );
1263
			switch ( $type ) {
1264
				case 'line1':
1265
					$meta_key = str_replace( '{address_name}', 'address1', $meta_key_prefix );
1266
					Give()->donor_meta->update_meta( $this->id, $meta_key, $value );
1267
					break;
1268
1269
				case 'line2':
1270
					$meta_key = str_replace( '{address_name}', 'address2', $meta_key_prefix );
1271
					Give()->donor_meta->update_meta( $this->id, $meta_key, $value );
1272
					break;
1273
1274
				default:
1275
					Give()->donor_meta->update_meta( $this->id, $meta_key, $value );
1276
			}
1277
		}
1278
1279
		$this->setup_address();
1280
1281
		return true;
1282
	}
1283
1284
	/**
1285
	 * Remove donor address
1286
	 *
1287
	 * @since  2.0
1288
	 * @access public
1289
	 * @global wpdb  $wpdb
1290
	 *
1291
	 * @param string $address_id
1292
	 *
1293
	 * @return bool
1294
	 */
1295
	public function remove_address( $address_id ) {
1296
		global $wpdb;
1297
1298
		// Get address type.
1299
		$is_multi_address = false !== strpos( $address_id, '_' ) ? true : false;
1300
1301
		$address_type = false !== strpos( $address_id, '_' ) ?
1302
			array_shift( explode( '_', $address_id ) ) :
1303
			$address_id;
1304
1305
		$address_count = false !== strpos( $address_id, '_' ) ?
1306
			array_pop( explode( '_', $address_id ) ) :
1307
			null;
1308
1309
		// Set meta key prefix.
1310
		$meta_key_prefix = "_give_donor_address_{$address_type}_%";
1311
		if ( $is_multi_address && is_numeric( $address_count ) ) {
1312
			$meta_key_prefix .= "_{$address_count}";
1313
		}
1314
1315
		$meta_type = Give()->donor_meta->meta_type;
1316
1317
		// Process query.
1318
		$row_affected = $wpdb->query(
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...
1319
			$wpdb->prepare(
1320
				"
1321
				DELETE FROM {$wpdb->donormeta}
1322
				WHERE meta_key
1323
				LIKE '%s'
1324
				AND {$meta_type}_id=%d
1325
				",
1326
				$meta_key_prefix,
1327
				$this->id
1328
			)
1329
		);
1330
1331
		$this->setup_address();
1332
1333
		return (bool) $row_affected;
1334
	}
1335
1336
	/**
1337
	 * Update donor address
1338
	 *
1339
	 * @since  2.0
1340
	 * @access public
1341
	 * @global wpdb  $wpdb
1342
	 *
1343
	 * @param string $address_id
1344
	 * @param array  $address
1345
	 *
1346
	 * @return bool
1347
	 */
1348
	public function update_address( $address_id, $address ) {
1349
		global $wpdb;
1350
1351
		// Get address type.
1352
		$is_multi_address = false !== strpos( $address_id, '_' ) ? true : false;
1353
1354
		$address_type = false !== strpos( $address_id, '_' ) ?
1355
			array_shift( explode( '_', $address_id ) ) :
1356
			$address_id;
1357
1358
		$address_count = false !== strpos( $address_id, '_' ) ?
1359
			array_pop( explode( '_', $address_id ) ) :
1360
			null;
1361
1362
		// Set meta key prefix.
1363
		$meta_key_prefix = "_give_donor_address_{$address_type}_%";
1364
		if ( $is_multi_address && is_numeric( $address_count ) ) {
1365
			$meta_key_prefix .= "_{$address_count}";
1366
		}
1367
1368
		$meta_type = Give()->donor_meta->meta_type;
1369
1370
		// Process query.
1371
		$row_affected = $wpdb->get_results(
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...
1372
			$wpdb->prepare(
1373
				"
1374
				SELECT meta_key FROM {$wpdb->donormeta}
1375
				WHERE meta_key
1376
				LIKE '%s'
1377
				AND {$meta_type}_id=%d
1378
				",
1379
				$meta_key_prefix,
1380
				$this->id
1381
			)
1382
		);
1383
		
1384
		// Return result.
1385
		if( ! count( $row_affected ) ) {
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...
1386
			return false;
1387
		}
1388
1389
		// Update address.
1390
		if( ! $this->add_address( $address_id, $address ) ) {
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...
1391
			return false;
1392
		}
1393
1394
		$this->setup_address();
1395
1396
		return true;
1397
	}
1398
1399
1400
	/**
1401
	 * Check if donor already has current address
1402
	 *
1403
	 * @since 2.0
1404
	 * @access public
1405
	 *
1406
	 * @param string $current_address_type
1407
	 * @param array $current_address
1408
	 *
1409
	 * @return bool|null
1410
	 */
1411
	public function is_address_exist( $current_address_type, $current_address ) {
1412
		$status = false;
1413
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
1414
1415
		// Bailout.
1416
		if( empty( $current_address_type ) || empty( $current_address ) ) {
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...
1417
			return null;
1418
		}
1419
1420
		// Bailout.
1421
		if( empty( $this->address ) ) {
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...
1422
			return $status;
1423
		}
1424
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
1425
1426
		// Compare address.
1427
		foreach ( $this->address as $address_type => $saved_address ) {
1428
			if( $current_address_type !== $address_type ) {
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...
1429
				continue;
1430
1431
			} elseif( empty( $saved_address[0] ) || ! is_array( $saved_address[0] ) ) {
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...
1432
				$status = ( $current_address == $saved_address );
1433
1434
			} else{
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...
1435
				foreach ( $saved_address as $address ) {
1436
					if( empty( $saved_address ) ) {
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...
1437
						continue;
1438
					}
1439
1440
					$status = array_diff( $current_address, $address );
1441
					$status = empty( $status );
1442
1443
					// Exit loop immediately if address exist.
1444
					if( $status ) {
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...
1445
						break;
1446
					}
1447
				}
1448
			}
1449
1450
			// Exit loop immediately if address exist.
1451
			if( $status ) {
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...
1452
				break;
1453
			}
1454
		}
1455
1456
		return $status;
1457
	}
1458
1459
	/**
1460
	 * Split donor name into first name and last name
1461
	 *
1462
	 * @param   int     $id     Donor ID
1463
	 * @since   2.0
1464
	 * @return  object
1465
	 */
1466
	public function split_donor_name( $id ) {
1467
		$first_name = $last_name  = '';
1468
		$donor      = new Give_Donor( $id );
0 ignored issues
show
Documentation introduced by
$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...
1469
1470
		$split_donor_name = explode( ' ', $donor->name, 2 );
1471
1472
		// Check for existence of first name after split of donor name.
1473
		if( is_array( $split_donor_name ) && ! empty( $split_donor_name[0] ) ) {
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...
1474
			$first_name = $split_donor_name[0];
1475
		}
1476
1477
		// Check for existence of last name after split of donor name.
1478
		if( is_array( $split_donor_name ) && ! empty( $split_donor_name[1] ) ) {
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...
1479
			$last_name = $split_donor_name[1];
1480
		}
1481
		return (object) array( 'first_name' => $first_name, 'last_name' => $last_name );
1482
	}
1483
1484
	/**
1485
	 * Retrieves first name of donor with backward compatibility
1486
	 *
1487
	 * @since   2.0
1488
	 * @return  string
1489
	 */
1490
	public function get_first_name() {
1491
		$first_name = $this->get_meta( '_give_donor_first_name');
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
1492
		if( ! $first_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...
1493
			$first_name = $this->split_donor_name( $this->id )->first_name;
1494
		}
1495
1496
		return $first_name;
1497
	}
1498
1499
	/**
1500
	 * Retrieves last name of donor with backward compatibility
1501
	 *
1502
	 * @since   2.0
1503
	 * @return  string
1504
	 */
1505
	public function get_last_name() {
1506
		$first_name = $this->get_meta( '_give_donor_first_name');
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
1507
		$last_name = $this->get_meta( '_give_donor_last_name');
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
1508
1509
		// This condition will prevent unnecessary splitting of donor name to fetch last name.
1510
		if( ! $first_name && ! $last_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...
1511
			$last_name = $this->split_donor_name( $this->id )->last_name;
1512
		}
1513
1514
		return ( $last_name ) ? $last_name : '';
1515
	}
1516
1517
}
1518