Test Failed
Push — develop ( 7dfe94...172541 )
by Remco
04:09
created

Client::send_request()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 54
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 5.1314

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 5
eloc 28
c 4
b 0
f 0
nc 5
nop 3
dl 0
loc 54
rs 9.1608
ccs 19
cts 23
cp 0.8261
crap 5.1314

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Mollie client.
4
 *
5
 * @author    Pronamic <[email protected]>
6
 * @copyright 2005-2019 Pronamic
7
 * @license   GPL-3.0-or-later
8
 * @package   Pronamic\WordPress\Pay
9
 */
10
11
namespace Pronamic\WordPress\Pay\Gateways\Mollie;
12
13
use Pronamic\WordPress\DateTime\DateTime;
14
use Pronamic\WordPress\Pay\Core\XML\Security;
15
16
/**
17
 * Title: Mollie
18
 * Description:
19
 * Copyright: 2005-2019 Pronamic
20
 * Company: Pronamic
21
 *
22
 * @author  Remco Tolsma
23
 * @version 2.0.8
24
 * @since   1.0.0
25
 */
26
class Client {
27
	/**
28
	 * Mollie API endpoint URL
29
	 *
30
	 * @var string
31
	 */
32
	const API_URL = 'https://api.mollie.com/v2/';
33
34
	/**
35
	 * Mollie API Key ID
36
	 *
37
	 * @var string
38
	 */
39
	private $api_key;
40
41
	/**
42
	 * Mode
43
	 *
44
	 * @since 1.1.9
45
	 * @var string
46
	 */
47
	private $mode;
48
49
	/**
50
	 * Error
51
	 *
52
	 * @var \WP_Error
53
	 */
54
	private $error;
55
56
	/**
57
	 * Constructs and initializes an Mollie client object
58
	 *
59
	 * @param string $api_key Mollie API key.
60
	 */
61
	public function __construct( $api_key ) {
62 38
		$this->api_key = $api_key;
63 38
	}
64 38
65
	/**
66
	 * Set mode
67
	 *
68
	 * @since 1.1.9
69
	 * @param string $mode Mode (test or live).
70
	 */
71
	public function set_mode( $mode ) {
72 38
		$this->mode = $mode;
73 38
	}
74 38
75
	/**
76
	 * Error
77
	 *
78
	 * @return \WP_Error
79
	 */
80
	public function get_error() {
81 3
		return $this->error;
82 3
	}
83
84
	/**
85
	 * Send request with the specified action and parameters
86
	 *
87
	 * @param string $end_point              Requested endpoint.
88
	 * @param string $method                 HTTP method to use.
89
	 * @param array  $data                   Request data.
90
	 * @return object
91
	 * @throws \Exception Throws exception when error occurs.
92
	 */
93
	private function send_request( $end_point, $method = 'GET', array $data = array() ) {
94
		// Request.
95 8
		$url = self::API_URL . $end_point;
96
97 8
		$response = wp_remote_request(
98
			$url,
99 8
			array(
100 8
				'method'  => $method,
101
				'headers' => array(
102 8
					'Authorization' => 'Bearer ' . $this->api_key,
103
				),
104 8
				'body'    => $data,
105
			)
106 8
		);
107
108
		if ( $response instanceof \WP_Error ) {
109
			throw new \Exception( $response->get_error_message() );
110 8
		}
111
112
		// Body.
113
		$body = wp_remote_retrieve_body( $response );
114
115 8
		$data = json_decode( $body );
116
117
		// JSON error.
118 8
		$json_error = \json_last_error();
119 8
120 8
		if ( \JSON_ERROR_NONE !== $json_error ) {
121 8
			throw new \Exception(
122 8
				\sprintf( 'JSON: %s', \json_last_error_msg() ),
123
				$json_error
124
			);
125
		}
126
127
		// Object.
128
		if ( ! \is_object( $data ) ) {
129
			$code = \wp_remote_retrieve_response_code( $response );
130 8
131
			throw new \Exception(
132 8
				\sprintf( 'Could not JSON decode Mollie response to an object (HTTP Status Code: %s).', $code ),
133
				\intval( $code )
134
			);
135 8
		}
136
137 8
		// Mollie error from JSON response.
138
		if ( isset( $data->status, $data->title, $data->detail ) ) {
139
			throw new Error(
140
				$data->status,
141
				$data->title,
142
				$data->detail
143
			);
144
		}
145 8
146
		return $data;
147
	}
148
149
	/**
150
	 * Create payment.
151
	 *
152
	 * @param PaymentRequest $request Payment request.
153
	 * @return object
154
	 */
155 8
	public function create_payment( PaymentRequest $request ) {
156 8
		return $this->send_request( 'payments', 'POST', $request->get_array() );
157
	}
158 8
159
	/**
160
	 * Get payments.
161
	 *
162
	 * @return bool|object
163
	 */
164
	public function get_payments() {
165
		return $this->send_request( 'payments', 'GET' );
166
	}
167
168
	/**
169
	 * Get payment.
170
	 *
171
	 * @param string $payment_id Payment ID.
172
	 * @return object
173
	 */
174
	public function get_payment( $payment_id ) {
175
		if ( empty( $payment_id ) ) {
176
			throw new \Exception( 'Mollie payment ID can not be empty string.' );
177
		}
178
179
		return $this->send_request( 'payments/' . $payment_id, 'GET' );
180
	}
181
182
	/**
183
	 * Get issuers
184
	 *
185
	 * @return array
186
	 */
187
	public function get_issuers() {
188
		$response = $this->send_request( 'methods/ideal?include=issuers', 'GET' );
189
190
		$issuers = array();
191
192
		if ( isset( $response->issuers ) ) {
193
			foreach ( $response->issuers as $issuer ) {
194
				$id   = Security::filter( $issuer->id );
195
				$name = Security::filter( $issuer->name );
196
197
				$issuers[ $id ] = $name;
198
			}
199
		}
200
201
		return $issuers;
202
	}
203
204 2
	/**
205 2
	 * Get payment methods
206
	 *
207 2
	 * @param string $sequence_type Sequence type.
208 2
	 * @return array
209
	 */
210
	public function get_payment_methods( $sequence_type = '' ) {
211
		$data = array();
212
213
		if ( '' !== $sequence_type ) {
214
			$data['sequenceType'] = $sequence_type;
215
		}
216
217
		$response = $this->send_request( 'methods', 'GET', $data );
218
219
		$payment_methods = array();
220
221
		if ( ! isset( $response->_embedded ) ) {
222
			throw new \Exception( 'No embbedded data in Mollie response.' );
223
		}
224
225
		if ( isset( $response->_embedded->methods ) ) {
226
			foreach ( $response->_embedded->methods as $payment_method ) {
227
				$id   = Security::filter( $payment_method->id );
228
				$name = Security::filter( $payment_method->description );
229
230
				$payment_methods[ $id ] = $name;
231
			}
232 1
		}
233 1
234
		return $payment_methods;
235 1
	}
236 1
237
	/**
238
	 * Create customer.
239 1
	 *
240
	 * @since 1.1.6
241 1
	 *
242
	 * @param string|null $email Customer email address.
243 1
	 * @param string|null $name  Customer name.
244
	 * @return string|bool
245
	 */
246
	public function create_customer( $email, $name ) {
247
		if ( empty( $email ) ) {
248
			return false;
249
		}
250
251
		$response = $this->send_request(
252 1
			'customers',
253
			'POST',
254
			array(
255
				'name'  => $name,
256
				'email' => $email,
257
			)
258
		);
259
260
		if ( ! isset( $response->id ) ) {
261
			return false;
262
		}
263
264
		return $response->id;
265
	}
266
267
	/**
268
	 * Get customer.
269
	 *
270
	 * @param string $customer_id Mollie customer ID.
271
	 * @return object
272
	 */
273
	public function get_customer( $customer_id ) {
274
		if ( empty( $customer_id ) ) {
275
			throw new \Exception( 'Mollie customer ID can not be empty string.' );
276
		}
277
278
		return $this->send_request( 'customers/' . $customer_id, 'GET' );
279
	}
280
281
	/**
282
	 * Get mandates for customer.
283
	 *
284
	 * @param string $customer_id Mollie customer ID.
285
	 * @return object
286
	 */
287
	public function get_mandates( $customer_id ) {
288
		if ( '' === $customer_id ) {
289
			throw new \Exception( 'Mollie customer ID can not be empty string.' );
290
		}
291
292
		return $this->send_request( 'customers/' . $customer_id . '/mandates?limit=250', 'GET' );
293
	}
294
295
	/**
296 5
	 * Is there a valid mandate for customer?
297 5
	 *
298
	 * @param string      $customer_id    Mollie customer ID.
299
	 * @param string|null $payment_method Payment method to find mandates for.
300
	 * @return boolean
301 5
	 */
302
	public function has_valid_mandate( $customer_id, $payment_method = null ) {
303 5
		$mandates = $this->get_mandates( $customer_id );
304 5
305
		$mollie_method = Methods::transform( $payment_method );
306
307
		if ( ! isset( $mandates->_embedded ) ) {
308
			throw new \Exception( 'No embbedded data in Mollie response.' );
309
		}
310
311
		foreach ( $mandates->_embedded as $mandate ) {
312
			if ( $mollie_method !== $mandate->method ) {
313
				continue;
314
			}
315
316
			if ( 'valid' === $mandate->status ) {
317
				return true;
318
			}
319
		}
320
321
		return false;
322
	}
323
324
	/**
325
	 * Get formatted date and time of first valid mandate.
326
	 *
327
	 * @param string $customer_id    Mollie customer ID.
328
	 * @param string $payment_method Payment method.
329
	 * @return null|DateTime
330
	 */
331
	public function get_first_valid_mandate_datetime( $customer_id, $payment_method = null ) {
332
		$mandates = $this->get_mandates( $customer_id );
333
334
		$mollie_method = Methods::transform( $payment_method );
335
336
		if ( ! isset( $mandates->_embedded ) ) {
337
			throw new \Exception( 'No embbedded data in Mollie response.' );
338
		}
339
340
		foreach ( $mandates->_embedded as $mandate ) {
341
			if ( $mollie_method !== $mandate->method ) {
342
				continue;
343
			}
344
345
			if ( 'valid' !== $mandate->status ) {
346
				continue;
347
			}
348
349
			if ( ! isset( $valid_mandates ) ) {
350
				$valid_mandates = array();
351
			}
352
353
			// @codingStandardsIgnoreStart
354
			$valid_mandates[ $mandate->createdAt ] = $mandate;
355
			// @codingStandardsIgnoreEnd
356
		}
357
358
		if ( isset( $valid_mandates ) ) {
359
			ksort( $valid_mandates );
360
361
			$mandate = array_shift( $valid_mandates );
362
363
			// @codingStandardsIgnoreStart
364
			$create_date = new DateTime( $mandate->createdAt );
365
			// @codingStandardsIgnoreEnd
366
367
			return $create_date;
368
		}
369
370
		return null;
371
	}
372
}
373