Completed
Push — master ( e1ae54...c6044c )
by Roy
02:21
created

WC_Stripe_Customer::get_default_source()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 2
nop 0
1
<?php
2
if ( ! defined( 'ABSPATH' ) ) {
3
	exit;
4
}
5
6
/**
7
 * WC_Stripe_Customer class.
8
 *
9
 * Represents a Stripe Customer.
10
 */
11
class WC_Stripe_Customer {
12
13
	/**
14
	 * Stripe customer ID
15
	 * @var string
16
	 */
17
	private $id = '';
18
19
	/**
20
	 * WP User ID
21
	 * @var integer
22
	 */
23
	private $user_id = 0;
24
25
	/**
26
	 * Data from API
27
	 * @var array
28
	 */
29
	private $customer_data = array();
30
31
	/**
32
	 * Constructor
33
	 * @param int $user_id The WP user ID
34
	 */
35
	public function __construct( $user_id = 0 ) {
36
		if ( $user_id ) {
37
			$this->set_user_id( $user_id );
38
			$this->set_id( get_user_meta( $user_id, '_stripe_customer_id', true ) );
39
		}
40
	}
41
42
	/**
43
	 * Get Stripe customer ID.
44
	 * @return string
45
	 */
46
	public function get_id() {
47
		return $this->id;
48
	}
49
50
	/**
51
	 * Set Stripe customer ID.
52
	 * @param [type] $id [description]
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
53
	 */
54
	public function set_id( $id ) {
55
		$this->id = wc_clean( $id );
56
	}
57
58
	/**
59
	 * User ID in WordPress.
60
	 * @return int
61
	 */
62
	public function get_user_id() {
63
		return absint( $this->user_id );
64
	}
65
66
	/**
67
	 * Set User ID used by WordPress.
68
	 * @param int $user_id
69
	 */
70
	public function set_user_id( $user_id ) {
71
		$this->user_id = absint( $user_id );
72
	}
73
74
	/**
75
	 * Get user object.
76
	 * @return WP_User
77
	 */
78
	protected function get_user() {
79
		return $this->get_user_id() ? get_user_by( 'id', $this->get_user_id() ) : false;
80
	}
81
82
	/**
83
	 * Store data from the Stripe API about this customer
84
	 */
85
	public function set_customer_data( $data ) {
86
		$this->customer_data = $data;
87
	}
88
89
	/**
90
	 * Create a customer via API.
91
	 * @param array $args
92
	 * @return WP_Error|int
93
	 */
94
	public function create_customer( $args = array() ) {
95
		$billing_email = isset( $_POST['billing_email'] ) ? filter_var( $_POST['billing_email'], FILTER_SANITIZE_EMAIL ) : '';
96
		$user = $this->get_user();
97
98
		if ( $user ) {
99
			$billing_first_name = get_user_meta( $user->ID, 'billing_first_name', true );
100
			$billing_last_name  = get_user_meta( $user->ID, 'billing_last_name', true );
101
102
			$defaults = array(
103
				'email'       => $user->user_email,
104
				'description' => $billing_first_name . ' ' . $billing_last_name,
105
			);
106
		} else {
107
			$defaults = array(
108
				'email'       => $billing_email,
109
				'description' => '',
110
			);
111
		}
112
113
		$metadata = array();
114
115
		$defaults['metadata'] = apply_filters( 'wc_stripe_customer_metadata', $metadata, $user );
116
117
		$args     = wp_parse_args( $args, $defaults );
118
		$response = WC_Stripe_API::request( apply_filters( 'wc_stripe_create_customer_args', $args ), 'customers' );
119
120
		if ( ! empty( $response->error ) ) {
121
			throw new WC_Stripe_Exception( print_r( $response, true ), $response->error->message );
122
		}
123
124
		$this->set_id( $response->id );
125
		$this->clear_cache();
126
		$this->set_customer_data( $response );
127
128
		if ( $this->get_user_id() ) {
129
			update_user_meta( $this->get_user_id(), '_stripe_customer_id', $response->id );
130
		}
131
132
		do_action( 'woocommerce_stripe_add_customer', $args, $response );
133
134
		return $response->id;
135
	}
136
137
	/**
138
	 * Add a source for this stripe customer.
139
	 * @param string $source_id
140
	 * @param bool $retry
141
	 * @return WP_Error|int
142
	 */
143
	public function add_source( $source_id, $retry = true ) {
0 ignored issues
show
Unused Code introduced by
The parameter $retry is not used and could be removed.

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

Loading history...
144
		if ( ! $this->get_id() ) {
145
			$this->set_id( $this->create_customer() );
146
		}
147
148
		$response = WC_Stripe_API::request( array(
0 ignored issues
show
Bug Compatibility introduced by
The expression \WC_Stripe_API::request(...get_id() . '/sources'); of type array|WP_Error adds the type array to the return on line 161 which is incompatible with the return type documented by WC_Stripe_Customer::add_source of type WP_Error|integer.
Loading history...
149
			'source' => $source_id,
150
		), 'customers/' . $this->get_id() . '/sources' );
151
152
		if ( ! empty( $response->error ) ) {
153
			// It is possible the WC user once was linked to a customer on Stripe
154
			// but no longer exists. Instead of failing, lets try to create a
155
			// new customer.
156
			if ( preg_match( '/No such customer/i', $response->error->message ) ) {
157
				delete_user_meta( $this->get_user_id(), '_stripe_customer_id' );
158
				$this->create_customer();
159
				return $this->add_source( $source_id, false );
160
			} else {
161
				return $response;
162
			}
163
		} elseif ( empty( $response->id ) ) {
164
			return new WP_Error( 'error', __( 'Unable to add payment source.', 'woocommerce-gateway-stripe' ) );
165
		}
166
167
		// Add token to WooCommerce.
168
		if ( $this->get_user_id() && class_exists( 'WC_Payment_Token_CC' ) ) {
169
			if ( ! empty( $response->type ) ) {
170
				switch ( $response->type ) {
171
					case 'alipay':
172
						break;
173
					case 'sepa_debit':
174
						$wc_token = new WC_Payment_Token_SEPA();
175
						$wc_token->set_token( $response->id );
176
						$wc_token->set_gateway_id( 'stripe_sepa' );
177
						$wc_token->set_last4( $response->sepa_debit->last4 );
178
						break;
179
					default:
180
						if ( 'source' === $response->object && 'card' === $response->type ) {
181
							$wc_token = new WC_Payment_Token_CC();
182
							$wc_token->set_token( $response->id );
183
							$wc_token->set_gateway_id( 'stripe' );
184
							$wc_token->set_card_type( strtolower( $response->card->brand ) );
185
							$wc_token->set_last4( $response->card->last4 );
186
							$wc_token->set_expiry_month( $response->card->exp_month );
187
							$wc_token->set_expiry_year( $response->card->exp_year );
188
						}
189
						break;
190
				}
191
			} else {
192
				// Legacy.
193
				$wc_token = new WC_Payment_Token_CC();
194
				$wc_token->set_token( $response->id );
195
				$wc_token->set_gateway_id( 'stripe' );
196
				$wc_token->set_card_type( strtolower( $response->brand ) );
197
				$wc_token->set_last4( $response->last4 );
198
				$wc_token->set_expiry_month( $response->exp_month );
199
				$wc_token->set_expiry_year( $response->exp_year );
200
			}
201
202
			$wc_token->set_user_id( $this->get_user_id() );
0 ignored issues
show
Bug introduced by
The variable $wc_token does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
203
			$wc_token->save();
204
		}
205
206
		$this->clear_cache();
207
208
		do_action( 'woocommerce_stripe_add_source', $this->get_id(), $wc_token, $response, $source_id );
209
210
		return $response->id;
211
	}
212
213
	/**
214
	 * Get a customers saved sources using their Stripe ID.
215
	 *
216
	 * @param  string $customer_id
0 ignored issues
show
Bug introduced by
There is no parameter named $customer_id. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

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

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

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

Loading history...
217
	 * @return array
218
	 */
219
	public function get_sources() {
220
		if ( ! $this->get_id() ) {
221
			return array();
222
		}
223
224
		$sources = get_transient( 'stripe_sources_' . $this->get_id() );
225
226
		$response = WC_Stripe_API::request( array(
227
			'limit'       => 100,
228
		), 'customers/' . $this->get_id() . '/sources', 'GET' );
229
230
		if ( ! empty( $response->error ) ) {
231
			return array();
232
		}
233
234
		if ( is_array( $response->data ) ) {
235
			$sources = $response->data;
236
		}
237
238
		return empty( $sources ) ? array() : $sources;
239
	}
240
241
	/**
242
	 * Delete a source from stripe.
243
	 * @param string $source_id
244
	 */
245
	public function delete_source( $source_id ) {
246
		if ( ! $this->get_id() ) {
247
			return false;
248
		}
249
250
		$response = WC_Stripe_API::request( array(), 'customers/' . $this->get_id() . '/sources/' . sanitize_text_field( $source_id ), 'DELETE' );
251
252
		$this->clear_cache();
253
254
		if ( empty( $response->error ) ) {
255
			do_action( 'wc_stripe_delete_source', $this->get_id(), $response );
256
257
			return true;
258
		}
259
260
		return false;
261
	}
262
263
	/**
264
	 * Set default source in Stripe
265
	 * @param string $source_id
266
	 */
267
	public function set_default_source( $source_id ) {
268
		$response = WC_Stripe_API::request( array(
269
			'default_source' => sanitize_text_field( $source_id ),
270
		), 'customers/' . $this->get_id(), 'POST' );
271
272
		$this->clear_cache();
273
274
		if ( empty( $response->error ) ) {
275
			do_action( 'wc_stripe_set_default_source', $this->get_id(), $response );
276
277
			return true;
278
		}
279
280
		return false;
281
	}
282
283
	/**
284
	 * Deletes caches for this users cards.
285
	 */
286
	public function clear_cache() {
287
		delete_transient( 'stripe_sources_' . $this->get_id() );
288
		delete_transient( 'stripe_customer_' . $this->get_id() );
289
		$this->customer_data = array();
290
	}
291
}
292