Failed Conditions
Push — develop ( 7efbd4...bbd286 )
by Reüel
03:26
created

src/Client.php (3 issues)

1
<?php
2
/**
3
 * Adyen client
4
 *
5
 * @author    Pronamic <[email protected]>
6
 * @copyright 2005-2019 Pronamic
7
 * @license   GPL-3.0-or-later
8
 * @package   Pronamic\WordPress\Pay\Gateways\Adyen
9
 */
10
11
namespace Pronamic\WordPress\Pay\Gateways\Adyen;
12
13
use Pronamic\WordPress\Pay\Core\Gateway as Core_Gateway;
14
use Pronamic\WordPress\Pay\Core\XML\Security;
15
use WP_Error;
16
17
/**
18
 * Adyen client
19
 *
20
 * @author  Remco Tolsma
21
 * @version 1.0.0
22
 * @since   1.0.0
23
 * @link    https://github.com/adyenpayments/php/blob/master/generatepaymentform.php
24
 */
25
class Client {
26
	/**
27
	 * API endpoint test URL.
28
	 *
29
	 * @var string
30
	 */
31
	const API_URL_TEST = 'https://checkout-test.adyen.com/v40/';
32
33
	/**
34
	 * API endpoint live URL suffix.
35
	 *
36
	 * @var string
37
	 */
38
	const API_URL_LIVE_SUFFIX = '-checkout-live.adyenpayments.com/checkout';
39
40
	/**
41
	 * Mode.
42
	 *
43
	 * @var string
44
	 */
45
	private $mode;
46
47
	/**
48
	 * API Key.
49
	 *
50
	 * @var string
51
	 */
52
	private $api_key;
53
54
	/**
55
	 * API Live URL Prefix.
56
	 *
57
	 * @var string
58
	 */
59
	private $api_live_url_prefix;
60
61
	/**
62
	 * Merchant Account.
63
	 *
64
	 * @var string
65
	 */
66
	private $merchant_account;
67
68
	/**
69
	 * Error
70
	 *
71
	 * @var WP_Error
72
	 */
73
	private $error;
74
75
	/**
76
	 * Constructs and initializes an Adyen client object.
77
	 *
78
	 * @param string $api_key             Adyen API key.
79
	 * @param string $api_live_url_prefix Adyen API live URL prefix.
80
	 */
81
	public function __construct( $api_key, $api_live_url_prefix ) {
82
		$this->api_key             = $api_key;
83
		$this->api_live_url_prefix = $api_live_url_prefix;
84
	}
85
86
	/**
87
	 * Set mode.
88
	 *
89
	 * @param string $mode Mode.
90
	 */
91
	public function set_mode( $mode ) {
92
		$this->mode = $mode;
93
	}
94
95
	/**
96
	 * Set merchant account.
97
	 *
98
	 * @param string $merchant_account Merchant account.
99
	 */
100
	public function set_merchant_account( $merchant_account ) {
101
		$this->merchant_account = $merchant_account;
102
	}
103
104
	/**
105
	 * Error
106
	 *
107
	 * @return WP_Error
108
	 */
109
	public function get_error() {
110
		return $this->error;
111
	}
112
113
	/**
114
	 * Get API URL for current mode.
115
	 *
116
	 * @return string
117
	 */
118
	public function get_api_url() {
119
		if ( Core_Gateway::MODE_TEST === $this->mode ) {
120
			return self::API_URL_TEST;
121
		}
122
123
		return sprintf(
124
			'https://%1$s%2$s',
125
			$this->api_live_url_prefix,
126
			self::API_URL_LIVE_SUFFIX
127
		);
128
	}
129
130
	/**
131
	 * Send request with the specified action and parameters
132
	 *
133
	 * @param string $end_point              Requested endpoint.
134
	 * @param string $method                 HTTP method to use.
135
	 * @param array  $data                   Request data.
136
	 * @param int    $expected_response_code Expected response code.
137
	 *
138
	 * @return bool|object
139
	 */
140
	private function send_request( $end_point, $method = 'GET', array $data = array(), $expected_response_code = 200 ) {
141
		// Request.
142
		$url = $this->get_api_url() . $end_point;
143
144
		$response = wp_remote_request(
145
			$url,
146
			array(
147
				'method'  => $method,
148
				'headers' => array(
149
					'X-API-key'    => $this->api_key,
150
					'Content-Type' => 'application/json',
151
				),
152
				'body'    => wp_json_encode( $data ),
153
			)
154
		);
155
156
		// Response code.
157
		$response_code = wp_remote_retrieve_response_code( $response );
0 ignored issues
show
It seems like $response can also be of type WP_Error; however, parameter $response of wp_remote_retrieve_response_code() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

157
		$response_code = wp_remote_retrieve_response_code( /** @scrutinizer ignore-type */ $response );
Loading history...
158
159
		if ( $expected_response_code != $response_code ) { // WPCS: loose comparison ok.
160
			$this->error = new WP_Error( 'adyen_error', 'Unexpected response code.' );
161
		}
162
163
		// Body.
164
		$body = wp_remote_retrieve_body( $response );
0 ignored issues
show
It seems like $response can also be of type WP_Error; however, parameter $response of wp_remote_retrieve_body() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

164
		$body = wp_remote_retrieve_body( /** @scrutinizer ignore-type */ $response );
Loading history...
165
166
		$data = json_decode( $body );
167
168
		if ( ! is_object( $data ) ) {
169
			$this->error = new WP_Error( 'adyen_error', 'Could not parse response.' );
170
171
			return false;
172
		}
173
174
		// Adyen error.
175
		if ( isset( $data->errorCode, $data->message ) ) {
176
			$message = sprintf(
177
				'%1$s %2$s - %3$s',
178
				$data->status,
179
				$data->errorCode,
180
				$data->message
181
			);
182
183
			$this->error = new WP_Error( 'adyen_error', $message, $data->errorCode );
184
185
			return false;
186
		}
187
188
		return $data;
189
	}
190
191
	/**
192
	 * Create payment.
193
	 *
194
	 * @param PaymentRequest $request Payment request.
195
	 *
196
	 * @return bool|object
197
	 */
198
	public function create_payment( PaymentRequest $request ) {
199
		return $this->send_request( 'payments/', 'POST', $request->get_array(), 200 );
200
	}
201
202
	/**
203
	 * Create payment session.
204
	 *
205
	 * @param PaymentRequest $request Payment request.
206
	 *
207
	 * @return bool|object
208
	 */
209
	public function create_payment_session( PaymentRequest $request ) {
210
211
		return $this->send_request( 'paymentSession', 'POST', $request->get_array(), 200 );
212
	}
213
214
	/**
215
	 * Get payments.
216
	 *
217
	 * @return bool|object
218
	 */
219
	public function get_payments() {
220
		return $this->send_request( 'payments/', 'GET' );
221
	}
222
223
	/**
224
	 * Get payment details.
225
	 *
226
	 * @param string $payload Payload to get payment details for.
227
	 *
228
	 * @return bool|object
229
	 */
230
	public function get_payment_details( $payload ) {
231
		if ( empty( $payload ) ) {
232
			return false;
233
		}
234
235
		$data = array(
236
			'details' => array(
237
				'payload' => $payload,
238
			),
239
		);
240
241
		return $this->send_request( 'payments/details', 'POST', $data );
242
	}
243
244
	/**
245
	 * Get payment result.
246
	 *
247
	 * @param string $payload Payload to get payment details for.
248
	 *
249
	 * @return bool|object
250
	 */
251
	public function get_payment_result( $payload ) {
252
		if ( empty( $payload ) ) {
253
			return false;
254
		}
255
256
		$data = array(
257
			'payload' => $payload,
258
		);
259
260
		return $this->send_request( 'payments/result', 'POST', $data );
261
	}
262
263
	/**
264
	 * Get issuers.
265
	 *
266
	 * @param string $payment_method Payment method.
267
	 *
268
	 * @return array|bool
269
	 */
270
	public function get_issuers( $payment_method = null ) {
271
		// Check payment method.
272
		if ( empty( $payment_method ) ) {
273
			return false;
274
		}
275
276
		// Get issuers.
277
		$methods = $this->get_payment_methods();
278
279
		if ( false === $methods ) {
280
			return false;
281
		}
282
283
		$issuers = array();
284
285
		foreach ( $methods as $method_type => $method ) {
286
			if ( $payment_method !== $method_type ) {
287
				continue;
288
			}
289
290
			if ( ! isset( $method['details']['issuer'] ) ) {
291
				return false;
292
			}
293
294
			foreach ( $method['details']['issuer']['items'] as $issuer ) {
295
				$id   = Security::filter( $issuer['id'] );
296
				$name = Security::filter( $issuer['name'] );
297
298
				$issuers[ $id ] = $name;
299
			}
300
		}
301
302
		return $issuers;
303
	}
304
305
	/**
306
	 * Get payment methods
307
	 *
308
	 * @param string $recurring_type Recurring type.
309
	 *
310
	 * @return array|bool
311
	 */
312
	public function get_payment_methods() {
313
		$data = array(
314
			'merchantAccount'       => $this->merchant_account,
315
			'allowedPaymentMethods' => array(),
316
		);
317
318
		$response = $this->send_request( 'paymentMethods/', 'POST', $data );
319
320
		if ( false === $response ) {
321
			return false;
322
		}
323
324
		$payment_methods = array();
325
326
		if ( isset( $response->paymentMethods ) ) {
327
			foreach ( $response->paymentMethods as $payment_method ) {
328
				$type = Security::filter( $payment_method->type );
329
				$name = Security::filter( $payment_method->name );
330
331
				$method = array(
332
					'name' => $name,
333
				);
334
335
				if ( isset( $payment_method->details ) ) {
336
					$details = json_decode( wp_json_encode( $payment_method->details ), true );
0 ignored issues
show
It seems like wp_json_encode($payment_method->details) can also be of type false; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

336
					$details = json_decode( /** @scrutinizer ignore-type */ wp_json_encode( $payment_method->details ), true );
Loading history...
337
338
					foreach ( $details as $detail ) {
339
						$key = $detail['key'];
340
341
						$method['details'][ $key ] = $detail;
342
343
						unset( $method['details'][ $key ]['key'] );
344
					}
345
				}
346
347
				$payment_methods[ $type ] = $method;
348
			}
349
		}
350
351
		return $payment_methods;
352
	}
353
}
354