Completed
Pull Request — master (#834)
by Devin
18:40
created

Give_Customer   D

Complexity

Total Complexity 85

Size/Duplication

Total Lines 735
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 88.7%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 735
rs 4.4444
ccs 204
cts 230
cp 0.887
wmc 85
lcom 1
cbo 3

20 Methods

Rating   Name   Duplication   Size   Complexity  
D __construct() 0 25 9
B setup_customer() 0 30 6
C create() 0 42 8
B update() 0 24 3
C attach_payment() 0 49 7
A increase_purchase_count() 0 19 4
B decrease_purchase_count() 0 23 5
A increase_value() 0 14 2
A decrease_value() 0 18 3
B remove_payment() 0 56 9
A get_notes() 0 13 4
A get_notes_count() 0 8 1
B add_note() 0 31 4
A get_raw_notes() 0 7 1
B update_donation_value() 0 24 3
A __get() 0 14 2
A get_meta() 0 3 1
A add_meta() 0 3 1
A update_meta() 0 3 1
C sanitize_columns() 0 53 11

How to fix   Complexity   

Complex Class

Complex classes like Give_Customer often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Give_Customer, and based on these observations, apply Extract Interface, too.

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 22 and the first side effect is on line 14.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * Customer (Donor) Object
4
 *
5
 * @package     Give
6
 * @subpackage  Classes/Customer
7
 * @copyright   Copyright (c) 2016, WordImpress
8
 * @license     http://opensource.org/licenses/gpl-2.0.php 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_Customer Class
19
 *
20
 * @since 1.0
21
 */
22
class Give_Customer {
23
24
	/**
25
	 * The customer ID
26
	 *
27
	 * @since 1.0
28
	 */
29
	public $id = 0;
30
31
	/**
32
	 * The customer's purchase count
33
	 *
34
	 * @since 1.0
35
	 */
36
	public $purchase_count = 0;
37
38
	/**
39
	 * The customer's lifetime value
40
	 *
41
	 * @since 1.0
42
	 */
43
	public $purchase_value = 0;
44
45
	/**
46
	 * The customer's email
47
	 *
48
	 * @since 1.0
49
	 */
50
	public $email;
51
52
	/**
53
	 * The customer's name
54
	 *
55
	 * @since 1.0
56
	 */
57
	public $name;
58
59
	/**
60
	 * The customer's creation date
61
	 *
62
	 * @since 1.0
63
	 */
64
	public $date_created;
65
66
	/**
67
	 * The payment IDs associated with the customer
68
	 *
69
	 * @since  1.0
70
	 */
71
	public $payment_ids;
72
73
	/**
74
	 * The user ID associated with the customer
75
	 *
76
	 * @since  1.0
77
	 */
78
	public $user_id;
79
80
	/**
81
	 * Customer Notes
82
	 *
83
	 * @since  1.0
84
	 */
85
	public $notes;
86
87
	/**
88
	 * The Database Abstraction
89
	 *
90
	 * @since  1.0
91
	 */
92
	protected $db;
93
94
	/**
95
	 * Give_Customer constructor.
96
	 *
97
	 * @param bool $_id_or_email
98
	 * @param bool $by_user_id
99
	 */
100 52
	public function __construct( $_id_or_email = false, $by_user_id = false ) {
101
102 52
		$this->db = new Give_DB_Customers;
103
104 52
		if ( false === $_id_or_email || ( is_numeric( $_id_or_email ) && (int) $_id_or_email !== absint( $_id_or_email ) ) ) {
105
			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...
106
		}
107
108 52
		$by_user_id = is_bool( $by_user_id ) ? $by_user_id : false;
109
110 52
		if ( is_numeric( $_id_or_email ) ) {
111 52
			$field = $by_user_id ? 'user_id' : 'id';
112 52
		} else {
113 52
			$field = 'email';
114
		}
115
116 52
		$customer = $this->db->get_customer_by( $field, $_id_or_email );
117
118 52
		if ( empty( $customer ) || ! is_object( $customer ) ) {
119 52
			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...
120
		}
121
122 52
		$this->setup_customer( $customer );
123
124 52
	}
125
126
	/**
127
	 * Given the customer data, let's set the variables
128
	 *
129
	 * @since  1.0
130
	 *
131
	 * @param  object $customer The Customer Object
132
	 *
133
	 * @return bool             If the setup was successful or not
134
	 */
135 52
	private function setup_customer( $customer ) {
136
137 52
		if ( ! is_object( $customer ) ) {
138
			return false;
139
		}
140
141 52
		foreach ( $customer as $key => $value ) {
142
143
			switch ( $key ) {
144
145 52
				case 'notes':
146 52
					$this->$key = $this->get_notes();
147 52
					break;
148
149 52
				default:
150 52
					$this->$key = $value;
151 52
					break;
152
153 52
			}
154
155 52
		}
156
157
		// Customer ID and email are the only things that are necessary, make sure they exist
158 52
		if ( ! empty( $this->id ) && ! empty( $this->email ) ) {
159 52
			return true;
160
		}
161
162
		return false;
163
164
	}
165
166
	/**
167
	 * Magic __get function to dispatch a call to retrieve a private property
168
	 *
169
	 * @since 1.0
170
	 */
171 1
	public function __get( $key ) {
172
173 1
		if ( method_exists( $this, 'get_' . $key ) ) {
174
175
			return call_user_func( array( $this, 'get_' . $key ) );
176
177
		} else {
178
179
			/* translators: %s: property key */
180 1
			return new WP_Error( 'give-customer-invalid-property', sprintf( esc_html__( 'Can\'t get property %s.', 'give' ), $key ) );
181
182
		}
183
184
	}
185
186
	/**
187
	 * Creates a customer
188
	 *
189
	 * @since  1.0
190
	 *
191
	 * @param  array $data Array of attributes for a customer
192
	 *
193
	 * @return mixed        False if not a valid creation, Customer ID if user is found or valid creation
194
	 */
195 53
	public function create( $data = array() ) {
196
197 53
		if ( $this->id != 0 || empty( $data ) ) {
198
			return false;
199
		}
200
201
		$defaults = array(
202
			'payment_ids' => ''
203 53
		);
204
205 53
		$args = wp_parse_args( $data, $defaults );
206 53
		$args = $this->sanitize_columns( $args );
207
208 53
		if ( empty( $args['email'] ) || ! is_email( $args['email'] ) ) {
209 1
			return false;
210
		}
211
212 53
		if ( ! empty( $args['payment_ids'] ) && is_array( $args['payment_ids'] ) ) {
213
			$args['payment_ids'] = implode( ',', array_unique( array_values( $args['payment_ids'] ) ) );
214
		}
215
216 53
		do_action( 'give_customer_pre_create', $args );
217
218 53
		$created = false;
219
220
		// The DB class 'add' implies an update if the customer being asked to be created already exists
221 53
		if ( $this->db->add( $data ) ) {
222
223
			// We've successfully added/updated the customer, reset the class vars with the new data
224 53
			$customer = $this->db->get_customer_by( 'email', $args['email'] );
225
226
			// Setup the customer data with the values from DB
227 53
			$this->setup_customer( $customer );
228
229 53
			$created = $this->id;
230 53
		}
231
232 53
		do_action( 'give_customer_post_create', $created, $args );
233
234 53
		return $created;
235
236
	}
237
238
	/**
239
	 * Update a customer record
240
	 *
241
	 * @since  1.0
242
	 *
243
	 * @param  array $data Array of data attributes for a customer (checked via whitelist)
244
	 *
245
	 * @return bool         If the update was successful or not
246
	 */
247 53
	public function update( $data = array() ) {
248
249 53
		if ( empty( $data ) ) {
250 1
			return false;
251
		}
252
253 53
		$data = $this->sanitize_columns( $data );
254
255 53
		do_action( 'give_customer_pre_update', $this->id, $data );
256
257 53
		$updated = false;
258
259 53
		if ( $this->db->update( $this->id, $data ) ) {
260
261 53
			$customer = $this->db->get_customer_by( 'id', $this->id );
262 53
			$this->setup_customer( $customer );
263
264 53
			$updated = true;
265 53
		}
266
267 53
		do_action( 'give_customer_post_update', $updated, $this->id, $data );
268
269 53
		return $updated;
270
	}
271
272
273
	/**
274
	 * Attach payment to the customer then triggers increasing stats
275
	 *
276
	 * @since  1.0
277
	 *
278
	 * @param  int  $payment_id   The payment ID to attach to the customer
279
	 * @param  bool $update_stats For backwards compatibility, if we should increase the stats or not
280
	 *
281
	 * @return bool            If the attachment was successfuly
282
	 */
283 52
	public function attach_payment( $payment_id = 0, $update_stats = true ) {
284
285 52
		if ( empty( $payment_id ) ) {
286 1
			return false;
287
		}
288
289 52
		if ( empty( $this->payment_ids ) ) {
290
291 52
			$new_payment_ids = $payment_id;
292
293 52
		} else {
294
295 7
			$payment_ids = array_map( 'absint', explode( ',', $this->payment_ids ) );
296
297 7
			if ( in_array( $payment_id, $payment_ids ) ) {
298 1
				$update_stats = false;
299 1
			}
300
301 7
			$payment_ids[] = $payment_id;
302
303 7
			$new_payment_ids = implode( ',', array_unique( array_values( $payment_ids ) ) );
304
305
		}
306
307 52
		do_action( 'give_customer_pre_attach_payment', $payment_id, $this->id );
308
309 52
		$payment_added = $this->update( array( 'payment_ids' => $new_payment_ids ) );
310
311 52
		if ( $payment_added ) {
312
313 52
			$this->payment_ids = $new_payment_ids;
314
315
			// We added this payment successfully, increment the stats
316 52
			if ( $update_stats ) {
317 1
				$payment_amount = give_get_payment_amount( $payment_id );
318
319 1
				if ( ! empty( $payment_amount ) ) {
320
					$this->increase_value( $payment_amount );
321
				}
322
323 1
				$this->increase_purchase_count();
324 1
			}
325
326 52
		}
327
328 52
		do_action( 'give_customer_post_attach_payment', $payment_added, $payment_id, $this->id );
329
330 52
		return $payment_added;
331
	}
332
333
334
	/**
335
	 * Remove a payment from this customer, then triggers reducing stats
336
	 *
337
	 * @since  1.0
338
	 *
339
	 * @param  integer $payment_id   The Payment ID to remove
340
	 * @param  bool    $update_stats For backwards compatibility, if we should increase the stats or not
341
	 *
342
	 * @return boolean             If the removal was successful
343
	 */
344 3
	public function remove_payment( $payment_id = 0, $update_stats = true ) {
345
346 3
		if ( empty( $payment_id ) ) {
347
			return false;
348
		}
349
350 3
		$payment = new Give_Payment( $payment_id );
351
352 3
		if ( 'publish' !== $payment->status && 'revoked' !== $payment->status ) {
0 ignored issues
show
Documentation introduced by
The property $status is declared protected in Give_Payment. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
353 3
			$update_stats = false;
354 3
		}
355
356 3
		$new_payment_ids = '';
357
358 3
		if ( ! empty( $this->payment_ids ) ) {
359
360 3
			$payment_ids = array_map( 'absint', explode( ',', $this->payment_ids ) );
361
362 3
			$pos = array_search( $payment_id, $payment_ids );
363 3
			if ( false === $pos ) {
364
				return false;
365
			}
366
367 3
			unset( $payment_ids[ $pos ] );
368 3
			$payment_ids = array_filter( $payment_ids );
369
370 3
			$new_payment_ids = implode( ',', array_unique( array_values( $payment_ids ) ) );
371
372 3
		}
373
374 3
		do_action( 'give_customer_pre_remove_payment', $payment_id, $this->id );
375
376 3
		$payment_removed = $this->update( array( 'payment_ids' => $new_payment_ids ) );
377
378 3
		if ( $payment_removed ) {
379
380 3
			$this->payment_ids = $new_payment_ids;
381
382 3
			if ( $update_stats ) {
383
				// We removed this payment successfully, decrement the stats
384
				$payment_amount = give_get_payment_amount( $payment_id );
385
386
				if ( ! empty( $payment_amount ) ) {
387
					$this->decrease_value( $payment_amount );
388
				}
389
390
				$this->decrease_purchase_count();
391
			}
392
393 3
		}
394
395 3
		do_action( 'give_customer_post_remove_payment', $payment_removed, $payment_id, $this->id );
396
397 3
		return $payment_removed;
398
399
	}
400
401
	/**
402
	 * Increase the purchase count of a customer.
403
	 *
404
	 * @since  1.0
405
	 *
406
	 * @param  integer $count The number to increment by.
407
	 *
408
	 * @return int            The purchase count.
409
	 */
410 42
	public function increase_purchase_count( $count = 1 ) {
411
412
		// Make sure it's numeric and not negative.
413 42
		if ( ! is_numeric( $count ) || $count != absint( $count ) ) {
414 1
			return false;
415
		}
416
417 42
		$new_total = (int) $this->purchase_count + (int) $count;
418
419 42
		do_action( 'give_customer_pre_increase_purchase_count', $count, $this->id );
420
421 42
		if ( $this->update( array( 'purchase_count' => $new_total ) ) ) {
422 41
			$this->purchase_count = $new_total;
423 41
		}
424
425 42
		do_action( 'give_customer_post_increase_purchase_count', $this->purchase_count, $count, $this->id );
426
427 42
		return $this->purchase_count;
428
	}
429
430
	/**
431
	 * Decrease the customer purchase count.
432
	 *
433
	 * @since  1.0
434
	 *
435
	 * @param  integer $count The amount to decrease by.
436
	 *
437
	 * @return mixed          If successful, the new count, otherwise false.
438
	 */
439 6
	public function decrease_purchase_count( $count = 1 ) {
440
441
		// Make sure it's numeric and not negative
442 6
		if ( ! is_numeric( $count ) || $count != absint( $count ) ) {
443 1
			return false;
444
		}
445
446 6
		$new_total = (int) $this->purchase_count - (int) $count;
447
448 6
		if ( $new_total < 0 ) {
449 1
			$new_total = 0;
450 1
		}
451
452 6
		do_action( 'give_customer_pre_decrease_purchase_count', $count, $this->id );
453
454 6
		if ( $this->update( array( 'purchase_count' => $new_total ) ) ) {
455 6
			$this->purchase_count = $new_total;
456 6
		}
457
458 6
		do_action( 'give_customer_post_decrease_purchase_count', $this->purchase_count, $count, $this->id );
459
460 6
		return $this->purchase_count;
461
	}
462
463
	/**
464
	 * Increase the customer's lifetime value.
465
	 *
466
	 * @since  1.0
467
	 *
468
	 * @param  float $value The value to increase by.
469
	 *
470
	 * @return mixed         If successful, the new value, otherwise false.
471
	 */
472 42
	public function increase_value( $value = 0.00 ) {
473
474 42
		$new_value = floatval( $this->purchase_value ) + $value;
475
476 42
		do_action( 'give_customer_pre_increase_value', $value, $this->id );
477
478 42
		if ( $this->update( array( 'purchase_value' => $new_value ) ) ) {
479 41
			$this->purchase_value = $new_value;
480 41
		}
481
482 42
		do_action( 'give_customer_post_increase_value', $this->purchase_value, $value, $this->id );
483
484 42
		return $this->purchase_value;
485
	}
486
487
	/**
488
	 * Decrease a customer's lifetime value.
489
	 *
490
	 * @since  1.0
491
	 *
492
	 * @param  float $value The value to decrease by.
493
	 *
494
	 * @return mixed         If successful, the new value, otherwise false.
495
	 */
496 7
	public function decrease_value( $value = 0.00 ) {
497
498 7
		$new_value = floatval( $this->purchase_value ) - $value;
499
500 7
		if ( $new_value < 0 ) {
501 2
			$new_value = 0.00;
502 2
		}
503
504 7
		do_action( 'give_customer_pre_decrease_value', $value, $this->id );
505
506 7
		if ( $this->update( array( 'purchase_value' => $new_value ) ) ) {
507 6
			$this->purchase_value = $new_value;
508 6
		}
509
510 7
		do_action( 'give_customer_post_decrease_value', $this->purchase_value, $value, $this->id );
511
512 7
		return $this->purchase_value;
513
	}
514
515
	/**
516
	 * Decrease/Increase a customer's lifetime value.
517
     *
518
     * This function will update donation stat on basis of current amount and new amount donation difference.
519
     * Difference value can positive or negative. Negative value will decrease user donation stat while positive value increase donation stat.
520
     *
521
     *
522
     * @access public
523
	 * @since  1.0
524
	 *
525 52
	 * @param  float $curr_amount Current Donation amount.
526
	 * @param  float $new_amount  New ( changed ) Donation amount.
527 52
	 *
528 52
	 * @return mixed              If successful, the new donation stat value, otherwise false.
529
	 */
530 52
	public function update_donation_value( $curr_amount, $new_amount ) {
531 52
        /**
532
         * Payment total difference value can be:
533 52
         *  zero   (in case amount not change)
534
         *  or -ve (in case amount decrease)
535 52
         *  or +ve (in case amount increase)
536
         */
537
        $payment_total_diff = $new_amount - $curr_amount;
538
539
        // We do not need to update donation stat if donation did not change.
540
        if( ! $payment_total_diff ) {
541
            return false;
542
        }
543
544
545 1
        if( $payment_total_diff > 0 ) {
546
            $this->increase_value( $payment_total_diff );
547 1
        }else{
548 1
            // Pass payment total difference as +ve value to decrease amount from user lifetime stat.
549
            $this->decrease_value( -$payment_total_diff );
550 1
        }
551
552
        return $this->purchase_value;
553
	}
554
555
	/**
556
	 * Get the parsed notes for a customer as an array.
557
	 *
558
	 * @since  1.0
559
	 *
560
	 * @param  integer $length The number of notes to get.
561
	 * @param  integer $paged  What note to start at.
562
	 *
563 1
	 * @return array           The notes requested.
564
	 */
565 1
	public function get_notes( $length = 20, $paged = 1 ) {
566 1
567
		$length = is_numeric( $length ) ? $length : 20;
568
		$offset = is_numeric( $paged ) && $paged != 1 ? ( ( absint( $paged ) - 1 ) * $length ) : 0;
569
570 1
		$all_notes   = $this->get_raw_notes();
571
		$notes_array = array_reverse( array_filter( explode( "\n\n", $all_notes ) ) );
572 1
573 1
		$desired_notes = array_slice( $notes_array, $offset, $length );
574 1
575
		return $desired_notes;
576 1
577 1
	}
578 1
579
	/**
580 1
	 * Get the total number of notes we have after parsing.
581
	 *
582 1
	 * @since  1.0
583
	 * @return int The number of notes for the customer.
584 1
	 */
585 1
	public function get_notes_count() {
586 1
587
		$all_notes   = $this->get_raw_notes();
588 1
		$notes_array = array_reverse( array_filter( explode( "\n\n", $all_notes ) ) );
589
590
		return count( $notes_array );
591 1
592
	}
593
594
	/**
595
	 * Add a note for the customer.
596
	 *
597
	 * @since  1.0
598
	 *
599
	 * @param string $note The note to add.
600
	 *
601 52
	 * @return string|boolean The new note if added successfully, false otherwise.
602
	 */
603 52
	public function add_note( $note = '' ) {
604
605 52
		$note = trim( $note );
606
		if ( empty( $note ) ) {
607
			return false;
608
		}
609
610
		$notes = $this->get_raw_notes();
611
612
		if ( empty( $notes ) ) {
613
			$notes = '';
614
		}
615
616
		$note_string = date_i18n( 'F j, Y H:i:s', current_time( 'timestamp' ) ) . ' - ' . $note;
617
		$new_note    = apply_filters( 'give_customer_add_note_string', $note_string );
618 52
		$notes .= "\n\n" . $new_note;
619
620 52
		do_action( 'give_customer_pre_add_note', $new_note, $this->id );
621 52
622
		$updated = $this->update( array( 'notes' => $notes ) );
623 52
624
		if ( $updated ) {
625
			$this->notes = $this->get_notes();
626 52
		}
627 52
628
		do_action( 'give_customer_post_add_note', $this->notes, $new_note, $this->id );
629
630
		// Return the formatted note, so we can test, as well as update any displays
631
		return $new_note;
632 52
633 52
	}
634 52
635 52
	/**
636 1
	 * Get the notes column for the customer
637 1
	 *
638 52
	 * @since  1.0
639
	 * @return string The Notes for the customer, non-parsed
640 52
	 */
641
	private function get_raw_notes() {
642 52
643 52
		$all_notes = $this->db->get_column( 'notes', $this->id );
644
645
		return $all_notes;
646 52
647
	}
648 52
649
	/**
650 42
	 * Retrieve customer meta field for a customer.
651
	 *
652 42
	 * @param   string $meta_key      The meta key to retrieve.
653
	 * @param   bool   $single        Whether to return a single value.
654 42
	 * @return  mixed                 Will be an array if $single is false. Will be value of meta data field if $single is true.
655
	 *
656
	 * @access  public
657 42
	 * @since   1.6
658
	 */
659 42
	public function get_meta( $meta_key = '', $single = true ) {
660
		return Give()->customer_meta->get_meta( $this->id, $meta_key, $single );
661
	}
662
663
	/**
664
	 * Add meta data field to a customer.
665
	 *
666
	 * @param   string $meta_key      Metadata name.
667 52
	 * @param   mixed  $meta_value    Metadata value.
668
	 * @param   bool   $unique        Optional, default is false. Whether the same key should not be added.
669 52
	 * @return  bool                  False for failure. True for success.
670
	 *
671
	 * @access  public
672
	 * @since   1.6
673
	 */
674
	public function add_meta( $meta_key = '', $meta_value, $unique = false ) {
675
		return Give()->customer_meta->add_meta( $this->id, $meta_key, $meta_value, $unique );
676
	}
677
678
	/**
679
	 * Update customer meta field based on customer ID.
680
	 *
681
	 * @param   string $meta_key      Metadata key.
682
	 * @param   mixed  $meta_value    Metadata value.
683
	 * @param   mixed  $prev_value    Optional. Previous value to check before removing.
684
	 * @return  bool                  False on failure, true if success.
685
	 *
686
	 * @access  public
687
	 * @since   1.6
688
	 */
689
	public function update_meta( $meta_key = '', $meta_value, $prev_value = '' ) {
690
		return Give()->customer_meta->update_meta( $this->id, $meta_key, $meta_value, $prev_value );
691
	}
692
693
	/**
694
	 * Sanitize the data for update/create
695
	 *
696
	 * @since  1.0
697
	 *
698
	 * @param  array $data The data to sanitize
699
	 *
700
	 * @return array       The sanitized data, based off column defaults
701
	 */
702
	private function sanitize_columns( $data ) {
703
704
		$columns        = $this->db->get_columns();
705
		$default_values = $this->db->get_column_defaults();
706
707
		foreach ( $columns as $key => $type ) {
708
709
			// Only sanitize data that we were provided
710
			if ( ! array_key_exists( $key, $data ) ) {
711
				continue;
712
			}
713
714
			switch ( $type ) {
715
716
				case '%s':
717
					if ( 'email' == $key ) {
718
						$data[ $key ] = sanitize_email( $data[ $key ] );
719
					} elseif ( 'notes' == $key ) {
720
						$data[ $key ] = strip_tags( $data[ $key ] );
721
					} else {
722
						$data[ $key ] = sanitize_text_field( $data[ $key ] );
723
					}
724
					break;
725
726
				case '%d':
727
					if ( ! is_numeric( $data[ $key ] ) || (int) $data[ $key ] !== absint( $data[ $key ] ) ) {
728
						$data[ $key ] = $default_values[ $key ];
729
					} else {
730
						$data[ $key ] = absint( $data[ $key ] );
731
					}
732
					break;
733
734
				case '%f':
735
					// Convert what was given to a float
736
					$value = floatval( $data[ $key ] );
737
738
					if ( ! is_float( $value ) ) {
739
						$data[ $key ] = $default_values[ $key ];
740
					} else {
741
						$data[ $key ] = $value;
742
					}
743
					break;
744
745
				default:
746
					$data[ $key ] = sanitize_text_field( $data[ $key ] );
747
					break;
748
749
			}
750
751
		}
752
753
		return $data;
754
	}
755
756
}
757