Passed
Push — master ( 5bd17a...71a32c )
by Mike
04:53
created

PaymentGateways::prepare_item_for_response()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 29
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 17
nc 4
nop 2
dl 0
loc 29
rs 9.7
c 0
b 0
f 0
1
<?php
2
/**
3
 * REST API WC Payment gateways controller
4
 *
5
 * Handles requests to the /payment_gateways endpoint.
6
 *
7
 * @package WooCommerce/RestApi
8
 */
9
10
namespace WooCommerce\RestApi\Controllers\Version4;
11
12
defined( 'ABSPATH' ) || exit;
13
14
use \WooCommerce\RestApi\Controllers\Version4\Utilities\SettingsTrait;
15
16
/**
17
 * Payment gateways controller class.
18
 */
19
class PaymentGateways extends AbstractController {
20
	use SettingsTrait;
21
22
	/**
23
	 * Route base.
24
	 *
25
	 * @var string
26
	 */
27
	protected $rest_base = 'payment_gateways';
28
29
	/**
30
	 * Permission to check.
31
	 *
32
	 * @var string
33
	 */
34
	protected $resource_type = 'payment_gateways';
35
36
	/**
37
	 * Register the route for /payment_gateways and /payment_gateways/<id>
38
	 */
39
	public function register_routes() {
40
		register_rest_route(
41
			$this->namespace,
42
			'/' . $this->rest_base,
43
			array(
44
				array(
45
					'methods'             => \WP_REST_Server::READABLE,
46
					'callback'            => array( $this, 'get_items' ),
47
					'permission_callback' => array( $this, 'get_items_permissions_check' ),
48
					'args'                => $this->get_collection_params(),
49
				),
50
				'schema' => array( $this, 'get_public_item_schema' ),
51
			),
52
			true
53
		);
54
		register_rest_route(
55
			$this->namespace,
56
			'/' . $this->rest_base . '/(?P<id>[\w-]+)',
57
			array(
58
				'args'   => array(
59
					'id' => array(
60
						'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
61
						'type'        => 'string',
62
					),
63
				),
64
				array(
65
					'methods'             => \WP_REST_Server::READABLE,
66
					'callback'            => array( $this, 'get_item' ),
67
					'permission_callback' => array( $this, 'get_item_permissions_check' ),
68
					'args'                => array(
69
						'context' => $this->get_context_param( array( 'default' => 'view' ) ),
70
					),
71
				),
72
				array(
73
					'methods'             => \WP_REST_Server::EDITABLE,
74
					'callback'            => array( $this, 'update_item' ),
75
					'permission_callback' => array( $this, 'update_item_permissions_check' ),
76
					'args'                => $this->get_endpoint_args_for_item_schema( \WP_REST_Server::EDITABLE ),
77
				),
78
				'schema' => array( $this, 'get_public_item_schema' ),
79
			),
80
			true
81
		);
82
	}
83
84
	/**
85
	 * Get payment gateways.
86
	 *
87
	 * @param \WP_REST_Request $request Full details about the request.
88
	 * @return \WP_Error|\WP_REST_Response
89
	 */
90
	public function get_items( $request ) {
91
		$payment_gateways = WC()->payment_gateways->payment_gateways();
0 ignored issues
show
Bug introduced by
The method payment_gateways() does not exist on null. ( Ignorable by Annotation )

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

91
		/** @scrutinizer ignore-call */ 
92
  $payment_gateways = WC()->payment_gateways->payment_gateways();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
92
		$response         = array();
93
		foreach ( $payment_gateways as $payment_gateway_id => $payment_gateway ) {
94
			$payment_gateway->id = $payment_gateway_id;
95
			$gateway             = $this->prepare_item_for_response( $payment_gateway, $request );
96
			$gateway             = $this->prepare_response_for_collection( $gateway );
97
			$response[]          = $gateway;
98
		}
99
		return rest_ensure_response( $response );
100
	}
101
102
	/**
103
	 * Get a single payment gateway.
104
	 *
105
	 * @param \WP_REST_Request $request Request data.
106
	 * @return \WP_REST_Response|\WP_Error
107
	 */
108
	public function get_item( $request ) {
109
		$gateway = $this->get_gateway( $request );
110
111
		if ( is_null( $gateway ) ) {
112
			return new \WP_Error( 'woocommerce_rest_payment_gateway_invalid', __( 'Resource does not exist.', 'woocommerce' ), array( 'status' => 404 ) );
113
		}
114
115
		$gateway = $this->prepare_item_for_response( $gateway, $request );
116
		return rest_ensure_response( $gateway );
117
	}
118
119
	/**
120
	 * Update A Single Payment Method.
121
	 *
122
	 * @param \WP_REST_Request $request Request data.
123
	 * @return \WP_REST_Response|\WP_Error
124
	 */
125
	public function update_item( $request ) {
126
		$gateway = $this->get_gateway( $request );
127
128
		if ( is_null( $gateway ) ) {
129
			return new \WP_Error( 'woocommerce_rest_payment_gateway_invalid', __( 'Resource does not exist.', 'woocommerce' ), array( 'status' => 404 ) );
130
		}
131
132
		// Get settings.
133
		$gateway->init_form_fields();
0 ignored issues
show
Bug introduced by
The method init_form_fields() does not exist on WP_REST_Response. ( Ignorable by Annotation )

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

133
		$gateway->/** @scrutinizer ignore-call */ 
134
            init_form_fields();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
134
		$settings = $gateway->settings;
0 ignored issues
show
Bug introduced by
The property settings does not seem to exist on WP_REST_Response.
Loading history...
135
136
		// Update settings.
137
		if ( isset( $request['settings'] ) ) {
138
			$errors_found = false;
139
			foreach ( $gateway->form_fields as $key => $field ) {
0 ignored issues
show
Bug introduced by
The property form_fields does not seem to exist on WP_REST_Response.
Loading history...
140
				if ( isset( $request['settings'][ $key ] ) ) {
141
					if ( is_callable( array( $this, 'validate_setting_' . $field['type'] . '_field' ) ) ) {
142
						$value = $this->{'validate_setting_' . $field['type'] . '_field'}( $request['settings'][ $key ], $field );
143
					} else {
144
						$value = $this->validate_setting_text_field( $request['settings'][ $key ], $field );
145
					}
146
					if ( is_wp_error( $value ) ) {
147
						$errors_found = true;
148
						break;
149
					}
150
					$settings[ $key ] = $value;
151
				}
152
			}
153
154
			if ( $errors_found ) {
155
				return new \WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'woocommerce' ), array( 'status' => 400 ) );
156
			}
157
		}
158
159
		// Update if this method is enabled or not.
160
		if ( isset( $request['enabled'] ) ) {
161
			$settings['enabled'] = wc_bool_to_string( $request['enabled'] );
162
			$gateway->enabled    = $settings['enabled'];
0 ignored issues
show
Bug introduced by
The property enabled does not seem to exist on WP_REST_Response.
Loading history...
163
		}
164
165
		// Update title.
166
		if ( isset( $request['title'] ) ) {
167
			$settings['title'] = $request['title'];
168
			$gateway->title    = $settings['title'];
0 ignored issues
show
Bug introduced by
The property title does not seem to exist on WP_REST_Response.
Loading history...
169
		}
170
171
		// Update description.
172
		if ( isset( $request['description'] ) ) {
173
			$settings['description'] = $request['description'];
174
			$gateway->description    = $settings['description'];
0 ignored issues
show
Bug introduced by
The property description does not seem to exist on WP_REST_Response.
Loading history...
175
		}
176
177
		// Update options.
178
		$gateway->settings = $settings;
179
		update_option( $gateway->get_option_key(), apply_filters( 'woocommerce_gateway_' . $gateway->id . '_settings_values', $settings, $gateway ) );
0 ignored issues
show
Bug introduced by
The method get_option_key() does not exist on WP_REST_Response. ( Ignorable by Annotation )

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

179
		update_option( $gateway->/** @scrutinizer ignore-call */ get_option_key(), apply_filters( 'woocommerce_gateway_' . $gateway->id . '_settings_values', $settings, $gateway ) );

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The property id does not seem to exist on WP_REST_Response.
Loading history...
180
181
		// Update order.
182
		if ( isset( $request['order'] ) ) {
183
			$order                 = (array) get_option( 'woocommerce_gateway_order' );
184
			$order[ $gateway->id ] = $request['order'];
185
			update_option( 'woocommerce_gateway_order', $order );
186
			$gateway->order = absint( $request['order'] );
0 ignored issues
show
Bug introduced by
The property order does not seem to exist on WP_REST_Response.
Loading history...
187
		}
188
189
		$gateway = $this->prepare_item_for_response( $gateway, $request );
190
		return rest_ensure_response( $gateway );
191
	}
192
193
	/**
194
	 * Get a gateway based on the current request object.
195
	 *
196
	 * @param \WP_REST_Request $request Request data.
197
	 * @return \WP_REST_Response|null
198
	 */
199
	public function get_gateway( $request ) {
200
		$gateway          = null;
201
		$payment_gateways = WC()->payment_gateways->payment_gateways();
202
		foreach ( $payment_gateways as $payment_gateway_id => $payment_gateway ) {
203
			if ( $request['id'] !== $payment_gateway_id ) {
204
				continue;
205
			}
206
			$payment_gateway->id = $payment_gateway_id;
207
			$gateway             = $payment_gateway;
208
		}
209
		return $gateway;
210
	}
211
212
	/**
213
	 * Get data for this object in the format of this endpoint's schema.
214
	 *
215
	 * @param \WC_Payment_Gateway $object Object to prepare.
216
	 * @param \WP_REST_Request    $request Request object.
217
	 * @return array Array of data in the correct format.
218
	 */
219
	protected function get_data_for_response( $object, $request ) {
220
		$order = (array) get_option( 'woocommerce_gateway_order' );
221
		return array(
222
			'id'                 => $object->id,
223
			'title'              => $object->title,
224
			'description'        => $object->description,
225
			'order'              => isset( $order[ $object->id ] ) ? $order[ $object->id ] : '',
226
			'enabled'            => ( 'yes' === $object->enabled ),
227
			'method_title'       => $object->get_method_title(),
228
			'method_description' => $object->get_method_description(),
229
			'method_supports'    => $object->supports,
230
			'settings'           => $this->get_settings( $object ),
231
		);
232
	}
233
234
	/**
235
	 * Return settings associated with this payment gateway.
236
	 *
237
	 * @param WC_Payment_Gateway $gateway Gateway instance.
0 ignored issues
show
Bug introduced by
The type WooCommerce\RestApi\Cont...ion4\WC_Payment_Gateway was not found. Did you mean WC_Payment_Gateway? If so, make sure to prefix the type with \.
Loading history...
238
	 *
239
	 * @return array
240
	 */
241
	public function get_settings( $gateway ) {
242
		$settings = array();
243
		$gateway->init_form_fields();
244
		foreach ( $gateway->form_fields as $id => $field ) {
245
			// Make sure we at least have a title and type.
246
			if ( empty( $field['title'] ) || empty( $field['type'] ) ) {
247
				continue;
248
			}
249
250
			// Ignore 'enabled' and 'description' which get included elsewhere.
251
			if ( in_array( $id, array( 'enabled', 'description' ), true ) ) {
252
				continue;
253
			}
254
255
			$data = array(
256
				'id'          => $id,
257
				'label'       => empty( $field['label'] ) ? $field['title'] : $field['label'],
258
				'description' => empty( $field['description'] ) ? '' : $field['description'],
259
				'type'        => $field['type'],
260
				'value'       => empty( $gateway->settings[ $id ] ) ? '' : $gateway->settings[ $id ],
261
				'default'     => empty( $field['default'] ) ? '' : $field['default'],
262
				'tip'         => empty( $field['description'] ) ? '' : $field['description'],
263
				'placeholder' => empty( $field['placeholder'] ) ? '' : $field['placeholder'],
264
			);
265
			if ( ! empty( $field['options'] ) ) {
266
				$data['options'] = $field['options'];
267
			}
268
			$settings[ $id ] = $data;
269
		}
270
		return $settings;
271
	}
272
273
	/**
274
	 * Prepare links for the request.
275
	 *
276
	 * @param mixed            $item Object to prepare.
277
	 * @param \WP_REST_Request $request Request object.
278
	 * @return array
279
	 */
280
	protected function prepare_links( $item, $request ) {
281
		$links = array(
282
			'self'       => array(
283
				'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $item->id ) ),
284
			),
285
			'collection' => array(
286
				'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),
287
			),
288
		);
289
290
		return $links;
291
	}
292
293
	/**
294
	 * Get the payment gateway schema, conforming to JSON Schema.
295
	 *
296
	 * @return array
297
	 */
298
	public function get_item_schema() {
299
		$schema = array(
300
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
301
			'title'      => 'payment_gateway',
302
			'type'       => 'object',
303
			'properties' => array(
304
				'id'                 => array(
305
					'description' => __( 'Payment gateway ID.', 'woocommerce' ),
306
					'type'        => 'string',
307
					'context'     => array( 'view', 'edit' ),
308
					'readonly'    => true,
309
				),
310
				'title'              => array(
311
					'description' => __( 'Payment gateway title on checkout.', 'woocommerce' ),
312
					'type'        => 'string',
313
					'context'     => array( 'view', 'edit' ),
314
				),
315
				'description'        => array(
316
					'description' => __( 'Payment gateway description on checkout.', 'woocommerce' ),
317
					'type'        => 'string',
318
					'context'     => array( 'view', 'edit' ),
319
				),
320
				'order'              => array(
321
					'description' => __( 'Payment gateway sort order.', 'woocommerce' ),
322
					'type'        => 'integer',
323
					'context'     => array( 'view', 'edit' ),
324
					'arg_options' => array(
325
						'sanitize_callback' => 'absint',
326
					),
327
				),
328
				'enabled'            => array(
329
					'description' => __( 'Payment gateway enabled status.', 'woocommerce' ),
330
					'type'        => 'boolean',
331
					'context'     => array( 'view', 'edit' ),
332
				),
333
				'method_title'       => array(
334
					'description' => __( 'Payment gateway method title.', 'woocommerce' ),
335
					'type'        => 'string',
336
					'context'     => array( 'view', 'edit' ),
337
					'readonly'    => true,
338
				),
339
				'method_description' => array(
340
					'description' => __( 'Payment gateway method description.', 'woocommerce' ),
341
					'type'        => 'string',
342
					'context'     => array( 'view', 'edit' ),
343
					'readonly'    => true,
344
				),
345
				'method_supports'    => array(
346
					'description' => __( 'Supported features for this payment gateway.', 'woocommerce' ),
347
					'type'        => 'array',
348
					'context'     => array( 'view', 'edit' ),
349
					'readonly'    => true,
350
					'items'       => array(
351
						'type' => 'string',
352
					),
353
				),
354
				'settings'           => array(
355
					'description' => __( 'Payment gateway settings.', 'woocommerce' ),
356
					'type'        => 'object',
357
					'context'     => array( 'view', 'edit' ),
358
					'properties'  => array(
359
						'id'          => array(
360
							'description' => __( 'A unique identifier for the setting.', 'woocommerce' ),
361
							'type'        => 'string',
362
							'context'     => array( 'view', 'edit' ),
363
							'readonly'    => true,
364
						),
365
						'label'       => array(
366
							'description' => __( 'A human readable label for the setting used in interfaces.', 'woocommerce' ),
367
							'type'        => 'string',
368
							'context'     => array( 'view', 'edit' ),
369
							'readonly'    => true,
370
						),
371
						'description' => array(
372
							'description' => __( 'A human readable description for the setting used in interfaces.', 'woocommerce' ),
373
							'type'        => 'string',
374
							'context'     => array( 'view', 'edit' ),
375
							'readonly'    => true,
376
						),
377
						'type'        => array(
378
							'description' => __( 'Type of setting.', 'woocommerce' ),
379
							'type'        => 'string',
380
							'context'     => array( 'view', 'edit' ),
381
							'enum'        => array( 'text', 'email', 'number', 'color', 'password', 'textarea', 'select', 'multiselect', 'radio', 'image_width', 'checkbox' ),
382
							'readonly'    => true,
383
						),
384
						'value'       => array(
385
							'description' => __( 'Setting value.', 'woocommerce' ),
386
							'type'        => 'string',
387
							'context'     => array( 'view', 'edit' ),
388
						),
389
						'default'     => array(
390
							'description' => __( 'Default value for the setting.', 'woocommerce' ),
391
							'type'        => 'string',
392
							'context'     => array( 'view', 'edit' ),
393
							'readonly'    => true,
394
						),
395
						'tip'         => array(
396
							'description' => __( 'Additional help text shown to the user about the setting.', 'woocommerce' ),
397
							'type'        => 'string',
398
							'context'     => array( 'view', 'edit' ),
399
							'readonly'    => true,
400
						),
401
						'placeholder' => array(
402
							'description' => __( 'Placeholder text to be displayed in text inputs.', 'woocommerce' ),
403
							'type'        => 'string',
404
							'context'     => array( 'view', 'edit' ),
405
							'readonly'    => true,
406
						),
407
					),
408
				),
409
			),
410
		);
411
412
		return $this->add_additional_fields_schema( $schema );
413
	}
414
415
	/**
416
	 * Get any query params needed.
417
	 *
418
	 * @return array
419
	 */
420
	public function get_collection_params() {
421
		return array(
422
			'context' => $this->get_context_param( array( 'default' => 'view' ) ),
423
		);
424
	}
425
426
}
427