Completed
Push — master ( fb1e2f...9a3784 )
by Justin
25:57
created

WC_Customer::set_id()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
include_once( 'legacy/class-wc-legacy-customer.php' );
3
4
if ( ! defined( 'ABSPATH' ) ) {
5
	exit;
6
}
7
8
/**
9
 * The WooCommerce customer class handles storage of the current customer's data, such as location.
10
 *
11
 * @class    WC_Customer
12
 * @version  2.7.0
13
 * @package  WooCommerce/Classes
14
 * @category Class
15
 * @author   WooThemes
16
 */
17
class WC_Customer extends WC_Legacy_Customer {
18
19
	/**
20
	 * Stores customer data.
21
	 * @var array
22
	 */
23
	protected $data = array(
24
		'date_created'       => '',
25
		'date_modified'      => '',
26
		'email'              => '',
27
		'first_name'         => '',
28
		'last_name'          => '',
29
		'role'               => 'customer',
30
		'username'           => '',
31
		'billing'            => array(
32
			'first_name'     => '',
33
			'last_name'      => '',
34
			'company'        => '',
35
			'address_1'      => '',
36
			'address_2'      => '',
37
			'city'           => '',
38
			'state'          => '',
39
			'postcode'       => '',
40
			'country'        => '',
41
			'email'          => '',
42
			'phone'          => '',
43
		),
44
		'shipping'           => array(
45
			'first_name'     => '',
46
			'last_name'      => '',
47
			'company'        => '',
48
			'address_1'      => '',
49
			'address_2'      => '',
50
			'city'           => '',
51
			'state'          => '',
52
			'postcode'       => '',
53
			'country'        => '',
54
		),
55
		'is_paying_customer' => false,
56
	);
57
58
	/**
59
	 * Keys which are also stored in a session (so we can make sure they get updated...)
60
	 * @var array
61
	 */
62
	protected $session_keys = array(
63
		'billing_postcode',
64
		'billing_city',
65
		'billing_address_1',
66
		'billing_address',
67
		'billing_address_2',
68
		'billing_state',
69
		'billing_country',
70
		'shipping_postcode',
71
		'shipping_city',
72
		'shipping_address_1',
73
		'shipping_address',
74
		'shipping_address_2',
75
		'shipping_state',
76
		'shipping_country',
77
		'is_vat_exempt',
78
		'calculated_shipping',
79
		'billing_first_name',
80
		'billing_last_name',
81
		'billing_company',
82
		'billing_phone',
83
		'billing_email',
84
		'shipping_first_name',
85
		'shipping_last_name',
86
		'shipping_company',
87
	);
88
89
	/**
90
	 * Data stored in meta keys, but not considered "meta"
91
	 * @since 2.7.0
92
	 * @var array
93
	 */
94
	protected $internal_meta_keys = array(
95
		'billing_postcode',
96
		'billing_city',
97
		'billing_address_1',
98
		'billing_address_2',
99
		'billing_state',
100
		'billing_country',
101
		'shipping_postcode',
102
		'shipping_city',
103
		'shipping_address_1',
104
		'shipping_address_2',
105
		'shipping_state',
106
		'shipping_country',
107
		'paying_customer',
108
		'last_update',
109
		'first_name',
110
		'last_name',
111
		'show_admin_bar_front',
112
		'use_ssl',
113
		'admin_color',
114
		'rich_editing',
115
		'comment_shortcuts',
116
		'dismissed_wp_pointers',
117
		'show_welcome_panel',
118
		'_woocommerce_persistent_cart',
119
		'session_tokens',
120
		'nickname',
121
		'description',
122
		'billing_first_name',
123
		'billing_last_name',
124
		'billing_company',
125
		'billing_phone',
126
		'billing_email',
127
		'shipping_first_name',
128
		'shipping_last_name',
129
		'shipping_company',
130
		'default_password_nag',
131
		'primary_blog',
132
		'source_domain',
133
	);
134
135
	/**
136
	 * Internal meta type used to store user data.
137
	 * @var string
138
	 */
139
	protected $meta_type = 'user';
140
141
	/**
142
	 * If this is the customer session, this is true. When true, guest accounts will not be saved to the DB.
143
	 * @var boolean
144
	 */
145
	protected $is_session = false;
146
147
	/**
148
	 * Stores a password if this needs to be changed. Write-only and hidden from _data.
149
	 * @var string
150
	 */
151
	protected $password = '';
152
153
	/**
154
	 * Stores if user is VAT exempt for this session.
155
	 * @var string
156
	 */
157
	protected $is_vat_exempt = false;
158
159
	/**
160
	 * Stores if user has calculated shipping in this session.
161
	 * @var string
162
	 */
163
	protected $calculated_shipping = false;
164
165
	/**
166
	 * Load customer data based on how WC_Customer is called.
167
	 *
168
	 * If $customer is 'new', you can build a new WC_Customer object. If it's empty, some
169
	 * data will be pulled from the session for the current user/customer.
170
	 *
171
	 * @param int $customer_id Customer ID
172
	 * @param bool $is_session True if this is the customer session
173
	 */
174
	public function __construct( $customer_id = 0, $is_session = false ) {
175
		if ( $customer_id > 0 ) {
176
			$this->read( $customer_id );
177
		}
178
		if ( $is_session ) {
179
			$this->is_session = true;
180
			$this->load_session();
181
			add_action( 'shutdown', array( $this, 'save_to_session' ), 10 );
182
		}
183
	}
184
185
	/**
186
	 * Loads a WC session into the customer class.
187
	 */
188
	public function load_session() {
189
		$data = (array) WC()->session->get( 'customer' );
190
		if ( ! empty( $data ) ) {
191
			foreach ( $this->session_keys as $session_key ) {
192
				$function_key = $session_key;
193
				if ( 'billing_' === substr( $session_key, 0, 8 ) ) {
194
					$session_key = str_replace( 'billing_', '', $session_key );
195
				}
196
				if ( ! empty( $data[ $session_key ] ) && is_callable( array( $this, "set_{$function_key}" ) ) ) {
197
					$this->{"set_{$function_key}"}( $data[ $session_key ] );
198
				}
199
			}
200
		}
201
		$this->load_defaults();
202
	}
203
204
	/**
205
	 * Load default values if props are unset.
206
	 */
207
	protected function load_defaults() {
208
		$default = wc_get_customer_default_location();
209
210
		// Set some defaults if some of our values are still not set.
211
		if ( ! $this->get_billing_country() ) {
212
			$this->set_billing_country( $default['country'] );
213
		}
214
215
		if ( ! $this->get_shipping_country() ) {
216
			$this->set_shipping_country( $this->get_billing_country() );
217
		}
218
219
		if ( ! $this->get_billing_state() ) {
220
			$this->set_billing_state( $default['state'] );
221
		}
222
223
		if ( ! $this->get_shipping_state() ) {
224
			$this->set_shipping_state( $this->get_billing_state() );
225
		}
226
	}
227
228
	/**
229
	 * Gets the customers last order.
230
	 * @return WC_Order|false
231
	 */
232
	public function get_last_order() {
233
		global $wpdb;
234
235
		$last_order = $wpdb->get_var( "SELECT posts.ID
236
			FROM $wpdb->posts AS posts
237
			LEFT JOIN {$wpdb->postmeta} AS meta on posts.ID = meta.post_id
238
			WHERE meta.meta_key = '_customer_user'
239
			AND   meta.meta_value = '" . esc_sql( $this->get_id() ) . "'
240
			AND   posts.post_type = 'shop_order'
241
			AND   posts.post_status IN ( '" . implode( "','", array_map( 'esc_sql', array_keys( wc_get_order_statuses() ) ) ) . "' )
242
			ORDER BY posts.ID DESC
243
		" );
244
245
		if ( $last_order ) {
246
			return wc_get_order( absint( $last_order ) );
247
		} else {
248
			return false;
249
		}
250
	}
251
252
	/**
253
	 * Return the number of orders this customer has.
254
	 * @since 2.7.0
255
	 * @return integer
256
	 */
257
	public function get_order_count() {
258
		global $wpdb;
259
260
		$count = $wpdb->get_var( "SELECT COUNT(*)
261
			FROM $wpdb->posts as posts
262
			LEFT JOIN {$wpdb->postmeta} AS meta ON posts.ID = meta.post_id
263
			WHERE   meta.meta_key = '_customer_user'
264
			AND     posts.post_type = 'shop_order'
265
			AND     posts.post_status IN ( '" . implode( "','", array_map( 'esc_sql', array_keys( wc_get_order_statuses() ) ) ) . "' )
266
			AND     meta_value = '" . esc_sql( $this->get_id() ) . "'
267
		" );
268
269
		return absint( $count );
270
	}
271
272
	/**
273
	 * Return how much money this customer has spent.
274
	 * @since 2.7.0
275
	 * @return float
276
	 */
277
	public function get_total_spent() {
278
		global $wpdb;
279
280
		$spent = $wpdb->get_var( "SELECT SUM(meta2.meta_value)
281
			FROM $wpdb->posts as posts
282
			LEFT JOIN {$wpdb->postmeta} AS meta ON posts.ID = meta.post_id
283
			LEFT JOIN {$wpdb->postmeta} AS meta2 ON posts.ID = meta2.post_id
284
			WHERE   meta.meta_key       = '_customer_user'
285
			AND     meta.meta_value     = '" . esc_sql( $this->get_id() ) . "'
286
			AND     posts.post_type     = 'shop_order'
287
			AND     posts.post_status   IN ( 'wc-completed', 'wc-processing' )
288
			AND     meta2.meta_key      = '_order_total'
289
		" );
290
291
		if ( ! $spent ) {
292
			$spent = 0;
293
		}
294
295
		return wc_format_decimal( $spent, 2 );
296
	}
297
298
	/**
299
	 * Is customer outside base country (for tax purposes)?
300
	 * @return bool
301
	 */
302
	public function is_customer_outside_base() {
303
		list( $country, $state ) = $this->get_taxable_address();
304
		if ( $country ) {
305
			$default = wc_get_base_location();
306
			if ( $default['country'] !== $country ) {
307
				return true;
308
			}
309
			if ( $default['state'] && $default['state'] !== $state ) {
310
				return true;
311
			}
312
		}
313
		return false;
314
	}
315
316
	/**
317
	 * Is customer VAT exempt?
318
	 * @return bool
319
	 */
320
	public function is_vat_exempt() {
321
		return $this->get_is_vat_exempt();
322
	}
323
324
	/**
325
	 * Has calculated shipping?
326
	 * @return bool
327
	 */
328
	public function has_calculated_shipping() {
329
		return $this->get_calculated_shipping();
330
	}
331
332
	/*
333
	 |--------------------------------------------------------------------------
334
	 | Getters
335
	 |--------------------------------------------------------------------------
336
	 | Methods for getting data from the customer object.
337
	 */
338
339
	/**
340
	 * Return the customer's username.
341
	 * @since 2.7.0
342
	 * @return string
343
	 */
344
	public function get_username() {
345
		return $this->data['username'];
346
	}
347
348
	/**
349
	 * Return the customer's email.
350
	 * @since 2.7.0
351
	 * @return string
352
	 */
353
	public function get_email() {
354
		return $this->data['email'];
355
	}
356
357
	/**
358
	 * Return customer's first name.
359
	 * @since 2.7.0
360
	 * @return string
361
	 */
362
	public function get_first_name() {
363
		return $this->data['first_name'];
364
	}
365
366
	/**
367
	 * Return customer's last name.
368
	 * @since 2.7.0
369
	 * @return string
370
	 */
371
	public function get_last_name() {
372
		return $this->data['last_name'];
373
	}
374
375
	/**
376
	 * Return customer's user role.
377
	 * @since 2.7.0
378
	 * @return string
379
	 */
380
	public function get_role() {
381
		return $this->data['role'];
382
	}
383
384
	/**
385
	 * Return this customer's avatar.
386
	 * @since 2.7.0
387
	 * @return string
388
	 */
389 View Code Duplication
	public function get_avatar_url() {
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...
390
		$avatar_html = get_avatar( $this->get_email() );
391
392
		// Get the URL of the avatar from the provided HTML
393
		preg_match( '/src=["|\'](.+)[\&|"|\']/U', $avatar_html, $matches );
394
395
		if ( isset( $matches[1] ) && ! empty( $matches[1] ) ) {
396
			return esc_url( $matches[1] );
397
		}
398
399
		return '';
400
	}
401
402
	/**
403
	 * Return the date this customer was created.
404
	 * @since 2.7.0
405
	 * @return integer
406
	 */
407
	public function get_date_created() {
408
		return absint( $this->data['date_created'] );
409
	}
410
411
	/**
412
	 * Return the date this customer was last updated.
413
	 * @since 2.7.0
414
	 * @return integer
415
	 */
416
	public function get_date_modified() {
417
		return absint( $this->data['date_modified'] );
418
	}
419
420
	/**
421
	 * Gets customer billing first name.
422
	 * @return string
423
	 */
424
	public function get_billing_first_name() {
425
		return $this->data['billing']['first_name'];
426
	}
427
428
	/**
429
	 * Gets customer billing last name.
430
	 * @return string
431
	 */
432
	public function get_billing_last_name() {
433
		return $this->data['billing']['last_name'];
434
	}
435
436
	/**
437
	 * Gets customer billing company.
438
	 * @return string
439
	 */
440
	public function get_billing_company() {
441
		return $this->data['billing']['company'];
442
	}
443
444
	/**
445
	 * Gets billing phone.
446
	 * @return string
447
	 */
448
	public function get_billing_phone() {
449
		return $this->data['billing']['phone'];
450
	}
451
452
	/**
453
	 * Gets billing email.
454
	 * @return string
455
	 */
456
	public function get_billing_email() {
457
		return $this->data['billing']['email'];
458
	}
459
460
	/**
461
	 * Gets customer postcode.
462
	 * @return string
463
	 */
464
	public function get_billing_postcode() {
465
		return wc_format_postcode( $this->data['billing']['postcode'], $this->get_billing_country() );
466
	}
467
468
	/**
469
	 * Get customer city.
470
	 * @return string
471
	 */
472
	public function get_billing_city() {
473
		return $this->data['billing']['city'];
474
	}
475
476
	/**
477
	 * Get customer address.
478
	 * @return string
479
	 */
480
	public function get_billing_address() {
481
		return $this->data['billing']['address_1'];
482
	}
483
484
	/**
485
	 * Get customer address.
486
	 * @return string
487
	 */
488
	public function get_billing_address_1() {
489
		return $this->get_billing_address();
490
	}
491
492
	/**
493
	 * Get customer's second address.
494
	 * @return string
495
	 */
496
	public function get_billing_address_2() {
497
		return $this->data['billing']['address_2'];
498
	}
499
500
	/**
501
	 * Get customer state.
502
	 * @return string
503
	 */
504
	public function get_billing_state() {
505
		return $this->data['billing']['state'];
506
	}
507
508
	/**
509
	 * Get customer country.
510
	 * @return string
511
	 */
512
	public function get_billing_country() {
513
		return $this->data['billing']['country'];
514
	}
515
516
	/**
517
	 * Gets customer shipping first name.
518
	 * @return string
519
	 */
520
	public function get_shipping_first_name() {
521
		return $this->data['shipping']['first_name'];
522
	}
523
524
	/**
525
	 * Gets customer shipping last name.
526
	 * @return string
527
	 */
528
	public function get_shipping_last_name() {
529
		return $this->data['shipping']['last_name'];
530
	}
531
532
	/**
533
	 * Gets customer shipping company.
534
	 * @return string
535
	 */
536
	public function get_shipping_company() {
537
		return $this->data['shipping']['company'];
538
	}
539
540
	/**
541
	 * Get customer's shipping state.
542
	 * @return string
543
	 */
544
	public function get_shipping_state() {
545
		return $this->data['shipping']['state'];
546
	}
547
548
	/**
549
	 * Get customer's shipping country.
550
	 * @return string
551
	 */
552
	public function get_shipping_country() {
553
		return $this->data['shipping']['country'];
554
	}
555
556
	/**
557
	 * Get customer's shipping postcode.
558
	 * @return string
559
	 */
560
	public function get_shipping_postcode() {
561
		return wc_format_postcode( $this->data['shipping']['postcode'], $this->get_shipping_country() );
562
	}
563
564
	/**
565
	 * Get customer's shipping city.
566
	 * @return string
567
	 */
568
	public function get_shipping_city() {
569
		return $this->data['shipping']['city'];
570
	}
571
572
	/**
573
	 * Get customer's shipping address.
574
	 * @return string
575
	 */
576
	public function get_shipping_address() {
577
		return $this->data['shipping']['address_1'];
578
	}
579
580
	/**
581
	 * Get customer address.
582
	 * @return string
583
	 */
584
	public function get_shipping_address_1() {
585
		return $this->get_shipping_address();
586
	}
587
588
	/**
589
	 * Get customer's second shipping address.
590
	 * @return string
591
	 */
592
	public function get_shipping_address_2() {
593
		return $this->data['shipping']['address_2'];
594
	}
595
596
	/**
597
	 * Get if customer is VAT exempt?
598
	 * @since 2.7.0
599
	 * @return bool
600
	 */
601
	public function get_is_vat_exempt() {
602
		return $this->is_vat_exempt;
603
	}
604
605
	/**
606
	 * Has customer calculated shipping?
607
	 * @return bool
608
	 */
609
	public function get_calculated_shipping() {
610
		return $this->calculated_shipping;
611
	}
612
613
	/**
614
	 * Get taxable address.
615
	 * @return array
616
	 */
617
	public function get_taxable_address() {
618
		$tax_based_on = get_option( 'woocommerce_tax_based_on' );
619
620
		// Check shipping method at this point to see if we need special handling
621
		if ( true === apply_filters( 'woocommerce_apply_base_tax_for_local_pickup', true ) && sizeof( array_intersect( wc_get_chosen_shipping_method_ids(), apply_filters( 'woocommerce_local_pickup_methods', array( 'legacy_local_pickup', 'local_pickup' ) ) ) ) > 0 ) {
622
			$tax_based_on = 'base';
623
		}
624
625
		if ( 'base' === $tax_based_on ) {
626
			$country  = WC()->countries->get_base_country();
627
			$state    = WC()->countries->get_base_state();
628
			$postcode = WC()->countries->get_base_postcode();
629
			$city     = WC()->countries->get_base_city();
630
		} elseif ( 'billing' === $tax_based_on ) {
631
			$country  = $this->get_billing_country();
632
			$state    = $this->get_billing_state();
633
			$postcode = $this->get_billing_postcode();
634
			$city     = $this->get_billing_city();
635
		} else {
636
			$country  = $this->get_shipping_country();
637
			$state    = $this->get_shipping_state();
638
			$postcode = $this->get_shipping_postcode();
639
			$city     = $this->get_shipping_city();
640
		}
641
642
		return apply_filters( 'woocommerce_customer_taxable_address', array( $country, $state, $postcode, $city ) );
643
	}
644
645
	/**
646
	 * Gets a customer's downloadable products.
647
	 * @return array Array of downloadable products
648
	 */
649
	public function get_downloadable_products() {
650
		$downloads = array();
651
		if ( $this->get_id() ) {
652
			$downloads = wc_get_customer_available_downloads( $this->get_id() );
653
		}
654
		return apply_filters( 'woocommerce_customer_get_downloadable_products', $downloads );
655
	}
656
657
	/**
658
	 * Is the user a paying customer?
659
	 * @since 2.7.0
660
	 * @return bool
661
	 */
662
	function get_is_paying_customer() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
663
		return (bool) $this->data['is_paying_customer'];
664
	}
665
666
	/*
667
	|--------------------------------------------------------------------------
668
	| Setters
669
	|--------------------------------------------------------------------------
670
	| Functions for setting customer data. These should not update anything in the
671
	| database itself and should only change what is stored in the class
672
	| object.
673
	*/
674
675
	/**
676
	 * Set customer's username.
677
	 * @since 2.7.0
678
	 * @param string $username
679
	 * @throws WC_Data_Exception
680
	 */
681
	public function set_username( $username ) {
682
		$this->data['username'] = $username;
683
	}
684
685
	/**
686
	 * Set customer's email.
687
	 * @since 2.7.0
688
	 * @param string $value
689
	 * @throws WC_Data_Exception
690
	 */
691
	public function set_email( $value ) {
692
		if ( $value && ! is_email( $value ) ) {
693
			$this->error( 'customer_invalid_email', __( 'Invalid email address', 'woocommerce' ) );
694
		}
695
		$this->data['email'] = sanitize_email( $value );
696
	}
697
698
	/**
699
	 * Set customer's first name.
700
	 * @since 2.7.0
701
	 * @param string $first_name
702
	 * @throws WC_Data_Exception
703
	 */
704
	public function set_first_name( $first_name ) {
705
		$this->data['first_name'] = $first_name;
706
	}
707
708
	/**
709
	 * Set customer's last name.
710
	 * @since 2.7.0
711
	 * @param string $last_name
712
	 * @throws WC_Data_Exception
713
	 */
714
	public function set_last_name( $last_name ) {
715
		$this->data['last_name'] = $last_name;
716
	}
717
718
	/**
719
	 * Set customer's user role(s).
720
	 * @since 2.7.0
721
	 * @param mixed $role
722
	 * @throws WC_Data_Exception
723
	 */
724
	public function set_role( $role ) {
725
		global $wp_roles;
726
727
		if ( $role && ! empty( $wp_roles->roles ) && ! in_array( $role, array_keys( $wp_roles->roles ) ) ) {
728
			$this->error( 'customer_invalid_role', __( 'Invalid role', 'woocommerce' ) );
729
		}
730
		$this->data['role'] = $role;
731
	}
732
733
	/**
734
	 * Set customer's password.
735
	 * @since 2.7.0
736
	 * @param string $password
737
	 * @throws WC_Data_Exception
738
	 */
739
	public function set_password( $password ) {
740
		$this->password = wc_clean( $password );
0 ignored issues
show
Documentation Bug introduced by
It seems like wc_clean($password) can also be of type array. However, the property $password 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...
741
	}
742
743
	/**
744
	 * Set the date this customer was last updated.
745
	 * @since 2.7.0
746
	 * @param integer $timestamp
747
	 * @throws WC_Data_Exception
748
	 */
749
	public function set_date_modified( $timestamp ) {
750
		$this->data['date_modified'] = is_numeric( $timestamp ) ? $timestamp : strtotime( $timestamp );
751
	}
752
753
	/**
754
	 * Set the date this customer was last updated.
755
	 * @since 2.7.0
756
	 * @param integer $timestamp
757
	 * @throws WC_Data_Exception
758
	 */
759
	public function set_date_created( $timestamp ) {
760
		$this->data['date_created'] = is_numeric( $timestamp ) ? $timestamp : strtotime( $timestamp );
761
	}
762
763
	/**
764
	 * Set customer address to match shop base address.
765
	 * @since 2.7.0
766
	 * @throws WC_Data_Exception
767
	 */
768
	public function set_billing_address_to_base() {
769
		$base = wc_get_customer_default_location();
770
		$this->data['billing']['country']  = $base['country'];
771
		$this->data['billing']['state']    = $base['state'];
772
		$this->data['billing']['postcode'] = '';
773
		$this->data['billing']['city']     = '';
774
	}
775
776
	/**
777
	 * Set customer shipping address to base address.
778
	 * @since 2.7.0
779
	 * @throws WC_Data_Exception
780
	 */
781
	public function set_shipping_address_to_base() {
782
		$base = wc_get_customer_default_location();
783
		$this->data['shipping']['country']  = $base['country'];
784
		$this->data['shipping']['state']    = $base['state'];
785
		$this->data['shipping']['postcode'] = '';
786
		$this->data['shipping']['city']     = '';
787
	}
788
789
	/**
790
	 * Sets all shipping info at once.
791
	 * @param string $country
792
	 * @param string $state
793
	 * @param string $postcode
794
	 * @param string $city
795
	 * @throws WC_Data_Exception
796
	 */
797 View Code Duplication
	public function set_shipping_location( $country, $state = '', $postcode = '', $city = '' ) {
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...
798
		$this->data['shipping']['country']  = $country;
799
		$this->data['shipping']['state']    = $state;
800
		$this->data['shipping']['postcode'] = $postcode;
801
		$this->data['shipping']['city']     = $city;
802
	}
803
804
	/**
805
	 * Sets all address info at once.
806
	 * @param string $country
807
	 * @param string $state
808
	 * @param string $postcode
809
	 * @param string $city
810
	 * @throws WC_Data_Exception
811
	 */
812 View Code Duplication
	public function set_billing_location( $country, $state, $postcode = '', $city = '' ) {
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...
813
		$this->data['billing']['country']  = $country;
814
		$this->data['billing']['state']    = $state;
815
		$this->data['billing']['postcode'] = $postcode;
816
		$this->data['billing']['city']     = $city;
817
	}
818
819
	/**
820
	 * Set billing first name.
821
	 * @return string
822
	 * @throws WC_Data_Exception
823
	 */
824
	public function set_billing_first_name( $value ) {
825
		$this->data['billing']['first_name'] = $value;
826
	}
827
828
	/**
829
	 * Set billing last name.
830
	 * @return string
831
	 * @throws WC_Data_Exception
832
	 */
833
	public function set_billing_last_name( $value ) {
834
		$this->data['billing']['last_name'] = $value;
835
	}
836
837
	/**
838
	 * Set billing company.
839
	 * @return string
840
	 * @throws WC_Data_Exception
841
	 */
842
	public function set_billing_company( $value ) {
843
		$this->data['billing']['company'] = $value;
844
	}
845
846
	/**
847
	 * Set billing phone.
848
	 * @return string
849
	 * @throws WC_Data_Exception
850
	 */
851
	public function set_billing_phone( $value ) {
852
		$this->data['billing']['phone'] = $value;
853
	}
854
855
	/**
856
	 * Set billing email.
857
	 * @param string $value
858
	 * @return string
859
	 * @throws WC_Data_Exception
860
	 */
861
	public function set_billing_email( $value ) {
862
		if ( $value && ! is_email( $value ) ) {
863
			$this->error( 'customer_invalid_billing_email', __( 'Invalid billing email address', 'woocommerce' ) );
864
		}
865
		$this->data['billing']['email'] = sanitize_email( $value );
866
	}
867
868
	/**
869
	 * Set customer country.
870
	 * @param mixed $country
871
	 * @throws WC_Data_Exception
872
	 */
873
	public function set_billing_country( $country ) {
874
		$this->data['billing']['country'] = $country;
875
	}
876
877
	/**
878
	 * Set customer state.
879
	 * @param mixed $state
880
	 * @throws WC_Data_Exception
881
	 */
882
	public function set_billing_state( $state ) {
883
		$this->data['billing']['state'] = $state;
884
	}
885
886
	/**
887
	 * Sets customer postcode.
888
	 * @param mixed $postcode
889
	 * @throws WC_Data_Exception
890
	 */
891
	public function set_billing_postcode( $postcode ) {
892
		$this->data['billing']['postcode'] = $postcode;
893
	}
894
895
	/**
896
	 * Sets customer city.
897
	 * @param mixed $city
898
	 * @throws WC_Data_Exception
899
	 */
900
	public function set_billing_city( $city ) {
901
		$this->data['billing']['city'] = $city;
902
	}
903
904
	/**
905
	 * Set customer address.
906
	 * @param mixed $address
907
	 * @throws WC_Data_Exception
908
	 */
909
	public function set_billing_address( $address ) {
910
		$this->data['billing']['address_1'] = $address;
911
	}
912
913
	/**
914
	 * Set customer address.
915
	 * @param mixed $address
916
	 * @throws WC_Data_Exception
917
	 */
918
	public function set_billing_address_1( $address ) {
919
		$this->set_billing_address( $address );
920
	}
921
922
	/**
923
	 * Set customer's second address.
924
	 * @param mixed $address
925
	 * @throws WC_Data_Exception
926
	 */
927
	public function set_billing_address_2( $address ) {
928
		$this->data['billing']['address_2'] = $address;
929
	}
930
931
	/**
932
	 * Sets customer shipping first name.
933
	 * @param string $first_name
934
	 * @throws WC_Data_Exception
935
	 */
936
	public function set_shipping_first_name( $first_name ) {
937
		$this->data['shipping']['first_name'] = $first_name;
938
	}
939
940
	/**
941
	 * Sets customer shipping last name.
942
	 * @param string $last_name
943
	 * @throws WC_Data_Exception
944
	 */
945
	public function set_shipping_last_name( $last_name ) {
946
		$this->data['shipping']['last_name'] = $last_name;
947
	}
948
949
	/**
950
	 * Sets customer shipping company.
951
	 * @param string $company.
0 ignored issues
show
Documentation introduced by
There is no parameter named $company.. Did you maybe mean $company?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
952
	 * @throws WC_Data_Exception
953
	 */
954
	public function set_shipping_company( $company ) {
955
		$this->data['shipping']['company'] = $company;
956
	}
957
958
	/**
959
	 * Set shipping country.
960
	 * @param string $country
961
	 * @throws WC_Data_Exception
962
	 */
963
	public function set_shipping_country( $country ) {
964
		$this->data['shipping']['country'] = $country;
965
	}
966
967
	/**
968
	 * Set shipping state.
969
	 * @param string $state
970
	 * @throws WC_Data_Exception
971
	 */
972
	public function set_shipping_state( $state ) {
973
		$this->data['shipping']['state'] = $state;
974
	}
975
976
	/**
977
	 * Set shipping postcode.
978
	 * @param string $postcode
979
	 * @throws WC_Data_Exception
980
	 */
981
	public function set_shipping_postcode( $postcode ) {
982
		$this->data['shipping']['postcode'] = $postcode;
983
	}
984
985
	/**
986
	 * Sets shipping city.
987
	 * @param string $city
988
	 * @throws WC_Data_Exception
989
	 */
990
	public function set_shipping_city( $city ) {
991
		$this->data['shipping']['city'] = $city;
992
	}
993
994
	/**
995
	 * Set shipping address.
996
	 * @param string $address
997
	 * @throws WC_Data_Exception
998
	 */
999
	public function set_shipping_address( $address ) {
1000
		$this->data['shipping']['address_1'] = $address;
1001
	}
1002
1003
	/**
1004
	 * Set customer shipping address.
1005
	 * @param mixed $address
1006
	 * @throws WC_Data_Exception
1007
	 */
1008
	public function set_shipping_address_1( $address ) {
1009
		$this->set_shipping_address( $address );
1010
	}
1011
1012
	/**
1013
	 * Set second shipping address.
1014
	 * @param string $address
1015
	 * @throws WC_Data_Exception
1016
	 */
1017
	public function set_shipping_address_2( $address ) {
1018
		$this->data['shipping']['address_2'] = $address;
1019
	}
1020
1021
	/**
1022
	 * Set if the user a paying customer.
1023
	 * @since 2.7.0
1024
	 * @param boolean $is_paying_customer
1025
	 * @throws WC_Data_Exception
1026
	 */
1027
	function set_is_paying_customer( $is_paying_customer ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1028
		$this->data['is_paying_customer'] = (bool) $is_paying_customer;
1029
	}
1030
1031
	/**
1032
	 * Set if customer has tax exemption.
1033
	 * @param bool $is_vat_exempt
1034
	 */
1035
	public function set_is_vat_exempt( $is_vat_exempt ) {
1036
		$this->is_vat_exempt = (bool) $is_vat_exempt;
0 ignored issues
show
Documentation Bug introduced by
The property $is_vat_exempt was declared of type string, but (bool) $is_vat_exempt is of type boolean. 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...
1037
	}
1038
1039
	/**
1040
	 * Calculated shipping?
1041
	 * @param boolean $calculated
1042
	 */
1043
	public function set_calculated_shipping( $calculated = true ) {
1044
		$this->calculated_shipping = (bool) $calculated;
0 ignored issues
show
Documentation Bug introduced by
The property $calculated_shipping was declared of type string, but (bool) $calculated is of type boolean. 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...
1045
	}
1046
1047
	/*
1048
	 |--------------------------------------------------------------------------
1049
	 | CRUD methods
1050
	 |--------------------------------------------------------------------------
1051
	 | Methods which create, read, update and delete from the database.
1052
	 |
1053
	 | A save method is included for convenience (chooses update or create based
1054
	 | on if the order exists yet).
1055
	 */
1056
1057
	 /**
1058
	  * Create a customer.
1059
	  * @since 2.7.0.
1060
	  */
1061
	public function create() {
1062
		$customer_id = wc_create_new_customer( $this->get_email(), $this->get_username(), $this->password );
1063
1064
		if ( ! is_wp_error( $customer_id ) ) {
1065
			$this->set_id( $customer_id );
1066
			update_user_meta( $this->get_id(), 'billing_first_name', $this->get_billing_first_name() );
1067
			update_user_meta( $this->get_id(), 'billing_last_name', $this->get_billing_last_name() );
1068
			update_user_meta( $this->get_id(), 'billing_company', $this->get_billing_company() );
1069
			update_user_meta( $this->get_id(), 'billing_phone', $this->get_billing_phone() );
1070
			update_user_meta( $this->get_id(), 'billing_email', $this->get_billing_email() );
1071
			update_user_meta( $this->get_id(), 'billing_postcode', $this->get_billing_postcode() );
1072
			update_user_meta( $this->get_id(), 'billing_city', $this->get_billing_city() );
1073
			update_user_meta( $this->get_id(), 'billing_address_1', $this->get_billing_address() );
1074
			update_user_meta( $this->get_id(), 'billing_address_2', $this->get_billing_address_2() );
1075
			update_user_meta( $this->get_id(), 'billing_state', $this->get_billing_state() );
1076
			update_user_meta( $this->get_id(), 'billing_country', $this->get_billing_country() );
1077
			update_user_meta( $this->get_id(), 'shipping_first_name', $this->get_shipping_first_name() );
1078
			update_user_meta( $this->get_id(), 'shipping_last_name', $this->get_shipping_last_name() );
1079
			update_user_meta( $this->get_id(), 'shipping_company', $this->get_shipping_company() );
1080
			update_user_meta( $this->get_id(), 'shipping_postcode', $this->get_shipping_postcode() );
1081
			update_user_meta( $this->get_id(), 'shipping_city', $this->get_shipping_city() );
1082
			update_user_meta( $this->get_id(), 'shipping_address_1', $this->get_shipping_address() );
1083
			update_user_meta( $this->get_id(), 'shipping_address_2', $this->get_shipping_address_2() );
1084
			update_user_meta( $this->get_id(), 'shipping_state', $this->get_shipping_state() );
1085
			update_user_meta( $this->get_id(), 'shipping_country', $this->get_shipping_country() );
1086
			update_user_meta( $this->get_id(), 'paying_customer', $this->get_is_paying_customer() );
1087
			update_user_meta( $this->get_id(), 'last_update',  $this->get_date_modified() );
1088
			update_user_meta( $this->get_id(), 'first_name', $this->get_first_name() );
1089
			update_user_meta( $this->get_id(), 'last_name', $this->get_last_name() );
1090
			wp_update_user( array( 'ID' => $this->get_id(), 'role' => $this->get_role() ) );
1091
			$wp_user = new WP_User( $this->get_id() );
1092
			$this->set_date_created( strtotime( $wp_user->user_registered ) );
1093
			$this->set_date_modified( get_user_meta( $this->get_id(), 'last_update', true ) );
1094
			$this->read_meta_data();
1095
		}
1096
	}
1097
1098
	/**
1099
	 * Callback which flattens post meta (gets the first value).
1100
	 * @param  array $value
1101
	 * @return mixed
1102
	 */
1103
	private function flatten_post_meta( $value ) {
1104
		return is_array( $value ) ? current( $value ) : $value;
1105
	}
1106
1107
	/**
1108
	 * Read a customer from the database.
1109
	 * @since 2.7.0
1110
	 * @param integer $id
1111
	 */
1112
	public function read( $id ) {
1113
		global $wpdb;
1114
1115
		// User object is required.
1116
		if ( ! $id || ! ( $user_object = get_user_by( 'id', $id ) ) || empty( $user_object->ID ) ) {
1117
			$this->set_id( 0 );
1118
			return;
1119
		}
1120
1121
		// Only users on this site should be read.
1122
		if ( is_multisite() && ! is_user_member_of_blog( $id ) ) {
1123
			$this->set_id( 0 );
1124
			return;
1125
		}
1126
1127
		$this->set_id( $user_object->ID );
1128
		$this->set_props( array_map( array( $this, 'flatten_post_meta' ), get_user_meta( $id ) ) );
1129
		$this->set_props( array(
1130
			'is_paying_customer' => get_user_meta( $id, 'paying_customer', true ),
1131
			'email'              => $user_object->user_email,
1132
			'username'           => $user_object->user_login,
1133
			'date_created'       => strtotime( $user_object->user_registered ),
1134
			'date_modified'      => get_user_meta( $id, 'last_update', true ),
1135
			'role'               => ! empty( $user_object->roles[0] ) ? $user_object->roles[0] : 'customer',
1136
		) );
1137
		$this->read_meta_data();
1138
	}
1139
1140
	/**
1141
	 * Update a customer.
1142
	 * @since 2.7.0
1143
	 */
1144
	public function update() {
1145
		wp_update_user( array( 'ID' => $this->get_id(), 'user_email' => $this->get_email() ) );
1146
		// Only update password if a new one was set with set_password
1147
		if ( ! empty( $this->password ) ) {
1148
			wp_update_user( array( 'ID' => $this->get_id(), 'user_pass' => $this->password ) );
1149
			$this->password = '';
1150
		}
1151
1152
		update_user_meta( $this->get_id(), 'billing_first_name', $this->get_billing_first_name() );
1153
		update_user_meta( $this->get_id(), 'billing_last_name', $this->get_billing_last_name() );
1154
		update_user_meta( $this->get_id(), 'billing_company', $this->get_billing_company() );
1155
		update_user_meta( $this->get_id(), 'billing_phone', $this->get_billing_phone() );
1156
		update_user_meta( $this->get_id(), 'billing_email', $this->get_billing_email() );
1157
		update_user_meta( $this->get_id(), 'billing_postcode', $this->get_billing_postcode() );
1158
		update_user_meta( $this->get_id(), 'billing_city', $this->get_billing_city() );
1159
		update_user_meta( $this->get_id(), 'billing_address_1', $this->get_billing_address() );
1160
		update_user_meta( $this->get_id(), 'billing_address_2', $this->get_billing_address_2() );
1161
		update_user_meta( $this->get_id(), 'billing_state', $this->get_billing_state() );
1162
		update_user_meta( $this->get_id(), 'shipping_first_name', $this->get_shipping_first_name() );
1163
		update_user_meta( $this->get_id(), 'shipping_last_name', $this->get_shipping_last_name() );
1164
		update_user_meta( $this->get_id(), 'shipping_company', $this->get_shipping_company() );
1165
		update_user_meta( $this->get_id(), 'billing_country', $this->get_billing_country() );
1166
		update_user_meta( $this->get_id(), 'shipping_first_name', $this->get_shipping_first_name() );
1167
		update_user_meta( $this->get_id(), 'shipping_last_name', $this->get_shipping_last_name() );
1168
		update_user_meta( $this->get_id(), 'shipping_company', $this->get_shipping_company() );
1169
		update_user_meta( $this->get_id(), 'shipping_postcode', $this->get_shipping_postcode() );
1170
		update_user_meta( $this->get_id(), 'shipping_city', $this->get_shipping_city() );
1171
		update_user_meta( $this->get_id(), 'shipping_address_1', $this->get_shipping_address() );
1172
		update_user_meta( $this->get_id(), 'shipping_address_2', $this->get_shipping_address_2() );
1173
		update_user_meta( $this->get_id(), 'shipping_state', $this->get_shipping_state() );
1174
		update_user_meta( $this->get_id(), 'shipping_country', $this->get_shipping_country() );
1175
		update_user_meta( $this->get_id(), 'paying_customer', $this->get_is_paying_customer() );
1176
		update_user_meta( $this->get_id(), 'first_name', $this->get_first_name() );
1177
		update_user_meta( $this->get_id(), 'last_name', $this->get_last_name() );
1178
		wp_update_user( array( 'ID' => $this->get_id(), 'role' => $this->get_role() ) );
1179
		$this->set_date_modified( get_user_meta( $this->get_id(), 'last_update', true ) );
1180
		$this->save_meta_data();
1181
	}
1182
1183
	/**
1184
	 * Delete a customer.
1185
	 * @since 2.7.0
1186
	 */
1187
	public function delete() {
1188
		if ( ! $this->get_id() ) {
1189
			return;
1190
		}
1191
		return wp_delete_user( $this->get_id() );
1192
	}
1193
1194
	/**
1195
	 * Delete a customer and reassign posts..
1196
	 *
1197
	 * @param int $reassign Reassign posts and links to new User ID.
1198
	 * @since 2.7.0
1199
	 */
1200
	public function delete_and_reassign( $reassign = null ) {
1201
		if ( ! $this->get_id() ) {
1202
			return;
1203
		}
1204
		return wp_delete_user( $this->get_id(), $reassign );
1205
	}
1206
1207
	/**
1208
	 * Save data. Create when creating a new user/class, update when editing
1209
	 * an existing user, and save session when working on a logged out guest
1210
	 * session.
1211
	 * @since 2.7.0
1212
	 */
1213
	public function save() {
1214
		if ( $this->is_session ) {
1215
			$this->save_to_session();
1216
		} elseif ( ! $this->get_id() ) {
1217
			$this->create();
1218
		} else {
1219
			$this->update();
1220
		}
1221
	}
1222
1223
	/**
1224
	 * Saves data to the session only (does not overwrite DB values).
1225
	 * @since 2.7.0
1226
	 */
1227
	public function save_to_session() {
1228
		$data = array();
1229
		foreach ( $this->session_keys as $session_key ) {
1230
			$function_key = $session_key;
1231
			if ( 'billing_' === substr( $session_key, 0, 8 ) ) {
1232
				$session_key = str_replace( 'billing_', '', $session_key );
1233
			}
1234
			$data[ $session_key ] = $this->{"get_$function_key"}();
1235
		}
1236
		if ( $data !== WC()->session->get( 'customer' ) ) {
1237
			WC()->session->set( 'customer', $data );
1238
		}
1239
	}
1240
1241
	/**
1242
	 * Callback to remove unwanted meta data.
1243
	 *
1244
	 * @param object $meta
1245
	 * @return bool
1246
	 */
1247
	protected function exclude_internal_meta_keys( $meta ) {
1248
		global $wpdb;
1249
		return ! in_array( $meta->meta_key, $this->get_internal_meta_keys() )
1250
			&& 0 !== strpos( $meta->meta_key, 'closedpostboxes_' )
1251
			&& 0 !== strpos( $meta->meta_key, 'metaboxhidden_' )
1252
			&& 0 !== strpos( $meta->meta_key, 'manageedit-' )
1253
			&& ! strstr( $meta->meta_key, $wpdb->prefix );
1254
	}
1255
1256
}
1257