Passed
Push — master ( bba4c5...886ed1 )
by Remco
04:49 queued 02:31
created

Client::get_first_valid_mandate_datetime()   C

Complexity

Conditions 7
Paths 11

Size

Total Lines 36
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 36
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 18
nc 11
nop 2
1
<?php
2
3
namespace Pronamic\WordPress\Pay\Gateways\Mollie;
4
5
use Pronamic\WordPress\DateTime\DateTime;
0 ignored issues
show
Bug introduced by
The type Pronamic\WordPress\DateTime\DateTime was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use Pronamic\WordPress\Pay\Core\XML\Security;
7
use WP_Error;
0 ignored issues
show
Bug introduced by
The type WP_Error was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
9
/**
10
 * Title: Mollie
11
 * Description:
12
 * Copyright: Copyright (c) 2005 - 2018
13
 * Company: Pronamic
14
 *
15
 * @author  Remco Tolsma
16
 * @version 2.0.0
17
 * @since   1.0.0
18
 */
19
class Client {
20
	/**
21
	 * Mollie API endpoint URL
22
	 *
23
	 * @var string
24
	 */
25
	const API_URL = 'https://api.mollie.nl/v1/';
26
27
	/**
28
	 * Mollie API Key ID
29
	 *
30
	 * @var string
31
	 */
32
	private $api_key;
33
34
	/**
35
	 * Mode
36
	 *
37
	 * @since 1.1.9
38
	 * @var string
39
	 */
40
	private $mode;
41
42
	/**
43
	 * Error
44
	 *
45
	 * @var WP_Error
46
	 */
47
	private $error;
48
49
	/**
50
	 * Constructs and initializes an Mollie client object
51
	 *
52
	 * @param string $api_key
53
	 */
54
	public function __construct( $api_key ) {
55
		$this->api_key = $api_key;
56
	}
57
58
	/**
59
	 * Set mode
60
	 *
61
	 * @since 1.1.9
62
	 * @param string $mode
63
	 */
64
	public function set_mode( $mode ) {
65
		$this->mode = $mode;
66
	}
67
68
	/**
69
	 * Error
70
	 *
71
	 * @return WP_Error
72
	 */
73
	public function get_error() {
74
		return $this->error;
75
	}
76
77
	/**
78
	 * Send request with the specified action and parameters
79
	 *
80
	 * @param string $end_point
81
	 * @param string $method
82
	 * @param array $data
83
	 * @param int $expected_response_code
84
	 *
85
	 * @return bool|object
86
	 */
87
	private function send_request( $end_point, $method = 'GET', array $data = array(), $expected_response_code = 200 ) {
88
		// Request
89
		$url = self::API_URL . $end_point;
90
91
		$response = wp_remote_request( $url, array(
0 ignored issues
show
Bug introduced by
The function wp_remote_request was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

91
		$response = /** @scrutinizer ignore-call */ wp_remote_request( $url, array(
Loading history...
92
			'method'  => $method,
93
			'headers' => array(
94
				'Authorization' => 'Bearer ' . $this->api_key,
95
			),
96
			'body'    => $data,
97
		) );
98
99
		// Response code
100
		$response_code = wp_remote_retrieve_response_code( $response );
0 ignored issues
show
Bug introduced by
The function wp_remote_retrieve_response_code was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

100
		$response_code = /** @scrutinizer ignore-call */ wp_remote_retrieve_response_code( $response );
Loading history...
101
102
		if ( $expected_response_code != $response_code ) { // WPCS: loose comparison ok.
103
			$this->error = new WP_Error( 'mollie_error', 'Unexpected response code.' );
104
		}
105
106
		// Body
107
		$body = wp_remote_retrieve_body( $response );
0 ignored issues
show
Bug introduced by
The function wp_remote_retrieve_body was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

107
		$body = /** @scrutinizer ignore-call */ wp_remote_retrieve_body( $response );
Loading history...
108
109
		$data = json_decode( $body );
110
111
		if ( ! is_object( $data ) ) {
112
			$this->error = new WP_Error( 'mollie_error', 'Could not parse response.' );
113
114
			return false;
115
		}
116
117
		// Mollie error
118
		if ( isset( $data->error, $data->error->message ) ) {
119
			$this->error = new \WP_Error( 'mollie_error', $data->error->message, $data->error );
120
121
			return false;
122
		}
123
124
		return $data;
125
	}
126
127
	public function create_payment( PaymentRequest $request ) {
128
		return $this->send_request( 'payments/', 'POST', $request->get_array(), 201 );
129
	}
130
131
	public function get_payments() {
132
		return $this->send_request( 'payments/', 'GET' );
133
	}
134
135
	public function get_payment( $payment_id ) {
136
		if ( empty( $payment_id ) ) {
137
			return false;
138
		}
139
140
		return $this->send_request( 'payments/' . $payment_id, 'GET' );
141
	}
142
143
	/**
144
	 * Get issuers
145
	 *
146
	 * @return array
147
	 */
148
	public function get_issuers() {
149
		$response = $this->send_request( 'issuers/', 'GET' );
150
151
		if ( false === $response ) {
152
			return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
153
		}
154
155
		$issuers = array();
156
157
		if ( isset( $response->data ) ) {
158
			foreach ( $response->data as $issuer ) {
159
				if ( Methods::IDEAL === $issuer->method ) {
160
					$id   = Security::filter( $issuer->id );
161
					$name = Security::filter( $issuer->name );
162
163
					$issuers[ $id ] = $name;
164
				}
165
			}
166
		}
167
168
		return $issuers;
169
	}
170
171
	/**
172
	 * Get payment methods
173
	 *
174
	 * @param string $recurring_type Recurring type.
175
	 *
176
	 * @return array
177
	 */
178
	public function get_payment_methods( $recurring_type = '' ) {
179
		$data = array();
180
181
		if ( '' !== $recurring_type ) {
182
			$data['recurringType'] = $recurring_type;
183
		}
184
185
		$response = $this->send_request( 'methods/', 'GET', $data );
186
187
		if ( false === $response ) {
188
			return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
189
		}
190
191
		$payment_methods = array();
192
193
		if ( isset( $response->data ) ) {
194
			foreach ( $response->data as $payment_method ) {
195
				$id   = Security::filter( $payment_method->id );
196
				$name = Security::filter( $payment_method->description );
197
198
				$payment_methods[ $id ] = $name;
199
			}
200
		}
201
202
		return $payment_methods;
203
	}
204
205
	/**
206
	 * Create customer.
207
	 *
208
	 * @since 1.1.6
209
	 *
210
	 * @param string $email
211
	 * @param string $name
212
	 *
213
	 * @return array|bool
214
	 */
215
	public function create_customer( $email, $name ) {
216
		if ( empty( $email ) || empty( $name ) ) {
217
			return false;
218
		}
219
220
		$response = $this->send_request( 'customers/', 'POST', array(
221
			'name'  => $name,
222
			'email' => $email,
223
		), 201 );
224
225
		if ( false === $response ) {
226
			return false;
227
		}
228
229
		if ( ! isset( $response->id ) ) {
230
			return false;
231
		}
232
233
		return $response->id;
234
	}
235
236
	/**
237
	 * Get customer.
238
	 *
239
	 * @param $customer_id
240
	 *
241
	 * @since unreleased
242
	 *
243
	 * @return array
244
	 */
245
	public function get_customer( $customer_id ) {
246
		if ( empty( $customer_id ) ) {
247
			return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
248
		}
249
250
		$response = $this->send_request( 'customers/' . $customer_id, 'GET', array(), 200 );
251
252
		if ( false === $response ) {
253
			return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
254
		}
255
256
		if ( is_wp_error( $this->error ) ) {
0 ignored issues
show
Bug introduced by
The function is_wp_error was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

256
		if ( /** @scrutinizer ignore-call */ is_wp_error( $this->error ) ) {
Loading history...
257
			return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
258
		}
259
260
		return $response;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $response returns the type object which is incompatible with the documented return type array.
Loading history...
261
	}
262
263
	/**
264
	 * Get mandates for customer.
265
	 *
266
	 * @param $customer_id
267
	 *
268
	 * @return array
269
	 */
270
	public function get_mandates( $customer_id ) {
271
		if ( '' === $customer_id ) {
272
			return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
273
		}
274
275
		return $this->send_request( 'customers/' . $customer_id . '/mandates?count=250', 'GET' );
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->send_reque...ates?count=250', 'GET') returns the type object|false which is incompatible with the documented return type array.
Loading history...
276
	}
277
278
	/**
279
	 * Is there a valid mandate for customer?
280
	 *
281
	 * @param $customer_id
282
	 *
283
	 * @return boolean
284
	 */
285
	public function has_valid_mandate( $customer_id, $payment_method = null ) {
286
		$mandates = $this->get_mandates( $customer_id );
287
288
		if ( ! $mandates ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $mandates of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
289
			return false;
290
		}
291
292
		$mollie_method = Methods::transform( $payment_method );
293
294
		foreach ( $mandates->data as $mandate ) {
295
			if ( $mollie_method !== $mandate->method ) {
296
				continue;
297
			}
298
299
			if ( 'valid' === $mandate->status ) {
300
				return true;
301
			}
302
		}
303
304
		return false;
305
	}
306
307
	/**
308
	 * Get formatted date and time of first valid mandate.
309
	 *
310
	 * @param string $customer_id    Mollie customer ID.
311
	 * @param string $payment_method Payment method.
312
	 *
313
	 * @return string
314
	 */
315
	public function get_first_valid_mandate_datetime( $customer_id, $payment_method = null ) {
316
		$mandates = $this->get_mandates( $customer_id );
317
318
		if ( ! $mandates ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $mandates of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
319
			return null;
320
		}
321
322
		$mollie_method = Methods::transform( $payment_method );
323
324
		foreach ( $mandates->data as $mandate ) {
325
			if ( $mollie_method !== $mandate->method ) {
326
				continue;
327
			}
328
329
			if ( 'valid' !== $mandate->status ) {
330
				continue;
331
			}
332
333
			if ( ! isset( $valid_mandates ) ) {
334
				$valid_mandates = array();
335
			}
336
337
			$valid_mandates[ $mandate->createdDatetime ] = $mandate;
338
		}
339
340
		if ( isset( $valid_mandates ) ) {
341
			ksort( $valid_mandates );
342
343
			$mandate = array_shift( $valid_mandates );
344
345
			$create_date = new DateTime( $mandate->createdDatetime );
346
347
			return $create_date;
348
		}
349
350
		return null;
351
	}
352
}
353