Test Failed
Push — develop ( 5d1492...ddf0fb )
by Remco
03:56
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 17
CRAP Score 5.0042

Importance

Changes 5
Bugs 0 Features 0
Metric Value
cc 5
eloc 28
c 5
b 0
f 0
nc 5
nop 3
dl 0
loc 54
ccs 17
cts 18
cp 0.9444
crap 5.0042
rs 9.1608

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