Completed
Push — master ( f47a1d...37f03f )
by Claudio
28:06
created

WC_REST_Taxes_Controller::update_item()   C

Complexity

Conditions 10
Paths 45

Size

Total Lines 74
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
dl 0
loc 74
rs 5.8102
c 1
b 1
f 0
nc 45
cc 10
eloc 38
nop 1

How to fix   Long Method    Complexity   

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
1 ignored issue
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 23 and the first side effect is on line 14.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * REST API Taxes controller
4
 *
5
 * Handles requests to the /taxes endpoint.
6
 *
7
 * @author   WooThemes
8
 * @category API
9
 * @package  WooCommerce/API
10
 * @since    2.6.0
11
 */
12
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit;
15
}
16
17
/**
18
 * REST API Taxes controller class.
19
 *
20
 * @package WooCommerce/API
21
 * @extends WP_REST_Controller
22
 */
23
class WC_REST_Taxes_Controller extends WP_REST_Controller {
24
25
	/**
26
	 * Endpoint namespace.
27
	 *
28
	 * @var string
29
	 */
30
	protected $namespace = 'wc/v1';
31
32
	/**
33
	 * Route base.
34
	 *
35
	 * @var string
36
	 */
37
	protected $rest_base = 'taxes';
38
39
	/**
40
	 * Register the routes for taxes.
41
	 */
42 View Code Duplication
	public function register_routes() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
43
		register_rest_route( $this->namespace, '/' . $this->rest_base, 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
			array(
51
				'methods'             => WP_REST_Server::CREATABLE,
52
				'callback'            => array( $this, 'create_item' ),
53
				'permission_callback' => array( $this, 'create_item_permissions_check' ),
54
				'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
55
			),
56
			'schema' => array( $this, 'get_public_item_schema' ),
57
		) );
58
59
		register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array(
60
			array(
61
				'methods'             => WP_REST_Server::READABLE,
62
				'callback'            => array( $this, 'get_item' ),
63
				'permission_callback' => array( $this, 'get_item_permissions_check' ),
64
				'args'                => array(
65
					'context' => $this->get_context_param( array( 'default' => 'view' ) ),
66
				),
67
			),
68
			array(
69
				'methods'             => WP_REST_Server::EDITABLE,
70
				'callback'            => array( $this, 'update_item' ),
71
				'permission_callback' => array( $this, 'update_item_permissions_check' ),
72
				'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
73
			),
74
			array(
75
				'methods'             => WP_REST_Server::DELETABLE,
76
				'callback'            => array( $this, 'delete_item' ),
77
				'permission_callback' => array( $this, 'delete_item_permissions_check' ),
78
				'args'                => array(
79
					'force' => array(
80
						'default'     => false,
81
						'description' => __( 'Required to be true, as resource does not support trashing.', 'woocommerce' ),
82
					),
83
				),
84
			),
85
			'schema' => array( $this, 'get_public_item_schema' ),
86
		) );
87
	}
88
89
	/**
90
	 * Check whether a given request has permission to read taxes.
91
	 *
92
	 * @param  WP_REST_Request $request Full details about the request.
93
	 * @return WP_Error|boolean
94
	 */
95 View Code Duplication
	public function get_items_permissions_check( $request ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
96
		if ( ! wc_rest_check_manager_permissions( 'settings', 'read' ) ) {
97
			return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list taxes.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
98
		}
99
100
		return true;
101
	}
102
103
	/**
104
	 * Check if a given request has access create taxes.
105
	 *
106
	 * @param  WP_REST_Request $request Full details about the request.
107
	 * @return boolean
108
	 */
109 View Code Duplication
	public function create_item_permissions_check( $request ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
110
		if ( ! wc_rest_check_manager_permissions( 'settings', 'create' ) ) {
111
			return new WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
112
		}
113
114
		return true;
115
	}
116
117
	/**
118
	 * Check if a given request has access to read a tax.
119
	 *
120
	 * @param  WP_REST_Request $request Full details about the request.
121
	 * @return WP_Error|boolean
122
	 */
123 View Code Duplication
	public function get_item_permissions_check( $request ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
124
		if ( ! wc_rest_check_manager_permissions( 'settings', 'read' ) ) {
125
			return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
126
		}
127
128
		return true;
129
	}
130
131
	/**
132
	 * Check if a given request has access update a tax.
133
	 *
134
	 * @param  WP_REST_Request $request Full details about the request.
135
	 * @return boolean
136
	 */
137 View Code Duplication
	public function update_item_permissions_check( $request ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
138
		if ( ! wc_rest_check_manager_permissions( 'settings', 'edit' ) ) {
139
			return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you are not allowed to edit this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
140
		}
141
142
		return true;
143
	}
144
145
	/**
146
	 * Check if a given request has access delete a tax.
147
	 *
148
	 * @param  WP_REST_Request $request Full details about the request.
149
	 * @return boolean
150
	 */
151 View Code Duplication
	public function delete_item_permissions_check( $request ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
152
		if ( ! wc_rest_check_manager_permissions( 'settings', 'delete' ) ) {
153
			return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'Sorry, you are not allowed to delete this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
154
		}
155
156
		return true;
157
	}
158
159
	/**
160
	 * Get all taxes.
161
	 *
162
	 * @param WP_REST_Request $request Full details about the request.
163
	 * @return WP_Error|WP_REST_Response
164
	 */
165
	public function get_items( $request ) {
166
		global $wpdb;
167
168
		$prepared_args = array();
169
		$prepared_args['exclude'] = $request['exclude'];
170
		$prepared_args['include'] = $request['include'];
171
		$prepared_args['order']   = $request['order'];
172
		$prepared_args['number']  = $request['per_page'];
173 View Code Duplication
		if ( ! empty( $request['offset'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
174
			$prepared_args['offset'] = $request['offset'];
175
		} else {
176
			$prepared_args['offset'] = ( $request['page'] - 1 ) * $prepared_args['number'];
177
		}
178
		$orderby_possibles = array(
179
			'id'    => 'tax_rate_id',
180
			'order' => 'tax_rate_order',
181
		);
182
		$prepared_args['orderby'] = $orderby_possibles[ $request['orderby'] ];
183
		$prepared_args['class']   = $request['class'];
184
185
		/**
186
		 * Filter arguments, before passing to $wpdb->get_results(), when querying taxes via the REST API.
187
		 *
188
		 * @param array           $prepared_args Array of arguments for $wpdb->get_results().
189
		 * @param WP_REST_Request $request       The current request.
190
		 */
191
		$prepared_args = apply_filters( 'woocommerce_rest_tax_query', $prepared_args, $request );
192
193
		$query = "
194
			SELECT *
195
			FROM {$wpdb->prefix}woocommerce_tax_rates
196
			WHERE 1 = 1
197
		";
198
199
		// Filter by tax class.
200 View Code Duplication
		if ( ! empty( $prepared_args['class'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
201
			$class = 'standard' !== $prepared_args['class'] ? sanitize_title( $prepared_args['class'] ) : '';
202
			$query .= " AND tax_rate_class = '$class'";
203
		}
204
205
		// Order tax rates.
206
		$order_by = sprintf( ' ORDER BY %s', sanitize_key( $prepared_args['orderby'] ) );
207
208
		// Pagination.
209
		$pagination = sprintf( ' LIMIT %d, %d', $prepared_args['offset'], $prepared_args['number'] );
210
211
		// Query taxes.
212
		$results = $wpdb->get_results( $query . $order_by . $pagination );
213
214
		$taxes = array();
215
		foreach ( $results as $tax ) {
216
			$data = $this->prepare_item_for_response( $tax, $request );
217
			$taxes[] = $this->prepare_response_for_collection( $data );
218
		}
219
220
		$response = rest_ensure_response( $taxes );
221
222
		// Store pagation values for headers then unset for count query.
223
		$per_page = (int) $prepared_args['number'];
224
		$page = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 );
225
226
		// Query only for ids.
227
		$wpdb->get_results( str_replace( 'SELECT *', 'SELECT tax_rate_id', $query ) );
228
229
		// Calcule totals.
230
		$total_taxes = (int) $wpdb->num_rows;
231
		$response->header( 'X-WP-Total', (int) $total_taxes );
232
		$max_pages = ceil( $total_taxes / $per_page );
233
		$response->header( 'X-WP-TotalPages', (int) $max_pages );
234
235
		$base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ) );
236 View Code Duplication
		if ( $page > 1 ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
237
			$prev_page = $page - 1;
238
			if ( $prev_page > $max_pages ) {
239
				$prev_page = $max_pages;
240
			}
241
			$prev_link = add_query_arg( 'page', $prev_page, $base );
242
			$response->link_header( 'prev', $prev_link );
243
		}
244 View Code Duplication
		if ( $max_pages > $page ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
245
			$next_page = $page + 1;
246
			$next_link = add_query_arg( 'page', $next_page, $base );
247
			$response->link_header( 'next', $next_link );
248
		}
249
250
		return $response;
251
	}
252
253
	/**
254
	 * Create a single tax.
255
	 *
256
	 * @param WP_REST_Request $request Full details about the request.
257
	 * @return WP_Error|WP_REST_Response
258
	 */
259
	public function create_item( $request ) {
260
		if ( ! empty( $request['id'] ) ) {
261
			return new WP_Error( 'woocommerce_rest_tax_exists', __( 'Cannot create existing resource.', 'woocommerce' ), array( 'status' => 400 ) );
262
		}
263
264
		$data = array(
265
			'tax_rate_country'  => $request['country'],
266
			'tax_rate_state'    => $request['state'],
267
			'tax_rate'          => $request['rate'],
268
			'tax_rate_name'     => $request['name'],
269
			'tax_rate_priority' => (int) $request['priority'],
270
			'tax_rate_compound' => (int) $request['compound'],
271
			'tax_rate_shipping' => (int) $request['shipping'],
272
			'tax_rate_order'    => (int) $request['order'],
273
			'tax_rate_class'    => 'standard' !== $request['class'] ? $request['class'] : '',
274
		);
275
276
		// Create tax rate.
277
		$id = WC_Tax::_insert_tax_rate( $data );
278
279
		// Add locales.
280
		if ( ! empty( $request['postcode'] ) ) {
281
			WC_Tax::_update_tax_rate_postcodes( $id, wc_clean( $request['postcode'] ) );
1 ignored issue
show
Bug introduced by
It seems like wc_clean($request['postcode']) targeting wc_clean() can also be of type array; however, WC_Tax::_update_tax_rate_postcodes() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
282
		}
283
		if ( ! empty( $request['city'] ) ) {
284
			WC_Tax::_update_tax_rate_cities( $id, wc_clean( $request['city'] ) );
1 ignored issue
show
Bug introduced by
It seems like wc_clean($request['city']) targeting wc_clean() can also be of type array; however, WC_Tax::_update_tax_rate_cities() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
285
		}
286
287
		$tax = WC_Tax::_get_tax_rate( $id, OBJECT );
288
289
		$this->update_additional_fields_for_object( $tax, $request );
290
291
		/**
292
		 * Fires after a tax is created or updated via the REST API.
293
		 *
294
		 * @param stdClass        $tax       Data used to create the tax.
295
		 * @param WP_REST_Request $request   Request object.
296
		 * @param boolean         $creating  True when creating tax, false when updating tax.
297
		 */
298
		do_action( 'woocommerce_rest_insert_tax', $tax, $request, true );
299
300
		$request->set_param( 'context', 'edit' );
301
		$response = $this->prepare_item_for_response( $tax, $request );
0 ignored issues
show
Documentation introduced by
$tax is of type array, but the function expects a object<stdClass>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
302
		$response = rest_ensure_response( $response );
303
		$response->set_status( 201 );
304
		$response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $id ) ) );
305
306
		return $response;
307
	}
308
309
	/**
310
	 * Get a single tax.
311
	 *
312
	 * @param WP_REST_Request $request Full details about the request.
313
	 * @return WP_Error|WP_REST_Response
314
	 */
315 View Code Duplication
	public function get_item( $request ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
316
		$id       = (int) $request['id'];
317
		$tax_obj = WC_Tax::_get_tax_rate( $id, OBJECT );
318
319
		if ( empty( $id ) || empty( $tax_obj ) ) {
320
			return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource id.', 'woocommerce' ), array( 'status' => 404 ) );
321
		}
322
323
		$tax = $this->prepare_item_for_response( $tax_obj, $request );
0 ignored issues
show
Documentation introduced by
$tax_obj is of type array, but the function expects a object<stdClass>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
324
		$response = rest_ensure_response( $tax );
325
326
		return $response;
327
	}
328
329
	/**
330
	 * Update a single tax.
331
	 *
332
	 * @param WP_REST_Request $request Full details about the request.
333
	 * @return WP_Error|WP_REST_Response
334
	 */
335
	public function update_item( $request ) {
336
		$id          = (int) $request['id'];
337
		$current_tax = WC_Tax::_get_tax_rate( $id, OBJECT );
338
339
		if ( empty( $id ) || empty( $current_tax ) ) {
340
			return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource id.', 'woocommerce' ), array( 'status' => 404 ) );
341
		}
342
343
		$data   = array();
344
		$fields = array(
345
			'tax_rate_country',
346
			'tax_rate_state',
347
			'tax_rate',
348
			'tax_rate_name',
349
			'tax_rate_priority',
350
			'tax_rate_compound',
351
			'tax_rate_shipping',
352
			'tax_rate_order',
353
			'tax_rate_class'
354
		);
355
356
		foreach ( $fields as $field ) {
357
			$key = 'tax_rate' === $field ? 'rate' : str_replace( 'tax_rate_', '', $field );
358
359
			if ( ! isset( $request[ $key ] ) ) {
360
				continue;
361
			}
362
363
			$value = $request[ $key ];
364
365
			// Fix compund and shipping values.
366
			if ( in_array( $key, array( 'compound', 'shipping' ) ) ) {
367
				$value = (int) $request[ $key ];
368
			}
369
370
			// Test new data against current data.
371
			if ( $current_tax->$field === $value ) {
372
				continue;
373
			}
374
375
			$data[ $field ] = $request[ $key ];
376
		}
377
378
		// Update tax rate.
379
		WC_Tax::_update_tax_rate( $id, $data );
380
381
		// Update locales.
382
		if ( ! isset( $request['postcode'] ) ) {
383
			WC_Tax::_update_tax_rate_postcodes( $id, wc_clean( $request['postcode'] ) );
1 ignored issue
show
Bug introduced by
It seems like wc_clean($request['postcode']) targeting wc_clean() can also be of type array; however, WC_Tax::_update_tax_rate_postcodes() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
384
		}
385
386
		if ( ! isset( $request['city'] ) ) {
387
			WC_Tax::_update_tax_rate_cities( $id, wc_clean( $request['city'] ) );
1 ignored issue
show
Bug introduced by
It seems like wc_clean($request['city']) targeting wc_clean() can also be of type array; however, WC_Tax::_update_tax_rate_cities() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
388
		}
389
390
		$tax = WC_Tax::_get_tax_rate( $id, OBJECT );
391
392
		$this->update_additional_fields_for_object( $tax, $request );
393
394
		/**
395
		 * Fires after a tax is created or updated via the REST API.
396
		 *
397
		 * @param stdClass        $tax       Data used to create the tax.
398
		 * @param WP_REST_Request $request   Request object.
399
		 * @param boolean         $creating  True when creating tax, false when updating tax.
400
		 */
401
		do_action( 'woocommerce_rest_insert_tax', $tax, $request, false );
402
403
		$request->set_param( 'context', 'edit' );
404
		$response = $this->prepare_item_for_response( $tax, $request );
0 ignored issues
show
Documentation introduced by
$tax is of type array, but the function expects a object<stdClass>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
405
		$response = rest_ensure_response( $response );
406
407
		return $response;
408
	}
409
410
	/**
411
	 * Delete a single tax.
412
	 *
413
	 * @param WP_REST_Request $request Full details about the request.
414
	 * @return WP_Error|WP_REST_Response
415
	 */
416
	public function delete_item( $request ) {
417
		global $wpdb;
418
419
		$id    = (int) $request['id'];
420
		$force = isset( $request['force'] ) ? (bool) $request['force'] : false;
421
422
		// We don't support trashing for this type, error out.
423
		if ( ! $force ) {
424
			return new WP_Error( 'woocommerce_rest_trash_not_supported', __( 'Taxes do not support trashing.', 'woocommerce' ), array( 'status' => 501 ) );
425
		}
426
427
		$tax = WC_Tax::_get_tax_rate( $id, OBJECT );
428
429
		if ( empty( $id ) || empty( $tax ) ) {
430
			return new WP_Error( 'woocommerce_rest_invalid_id', __( 'Invalid resource id.', 'woocommerce' ), array( 'status' => 400 ) );
431
		}
432
433
		$request->set_param( 'context', 'edit' );
434
		$response = $this->prepare_item_for_response( $tax, $request );
0 ignored issues
show
Documentation introduced by
$tax is of type array, but the function expects a object<stdClass>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
435
436
		WC_Tax::_delete_tax_rate( $id );
437
438
		if ( 0 === $wpdb->rows_affected ) {
439
			return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'The resource cannot be deleted.', 'woocommerce' ), array( 'status' => 500 ) );
440
		}
441
442
		/**
443
		 * Fires after a tax is deleted via the REST API.
444
		 *
445
		 * @param stdClass         $tax      The tax data.
446
		 * @param WP_REST_Response $response The response returned from the API.
447
		 * @param WP_REST_Request  $request  The request sent to the API.
448
		 */
449
		do_action( 'woocommerce_rest_delete_tax', $tax, $response, $request );
450
451
		return $response;
452
	}
453
454
	/**
455
	 * Prepare a single tax output for response.
456
	 *
457
	 * @param stdClass $tax Tax object.
458
	 * @param WP_REST_Request $request Request object.
459
	 * @return WP_REST_Response $response Response data.
460
	 */
461
	public function prepare_item_for_response( $tax, $request ) {
462
		global $wpdb;
463
464
		$id   = (int) $tax->tax_rate_id;
465
		$data = array(
466
			'id'       => $id,
467
			'country'  => $tax->tax_rate_country,
468
			'state'    => $tax->tax_rate_state,
469
			'postcode' => '',
470
			'city'     => '',
471
			'rate'     => $tax->tax_rate,
472
			'name'     => $tax->tax_rate_name,
473
			'priority' => (int) $tax->tax_rate_priority,
474
			'compound' => (bool) $tax->tax_rate_compound,
475
			'shipping' => (bool) $tax->tax_rate_shipping,
476
			'order'    => (int) $tax->tax_rate_order,
477
			'class'    => $tax->tax_rate_class ? $tax->tax_rate_class : 'standard',
478
		);
479
480
		// Get locales from a tax rate.
481
		$locales = $wpdb->get_results( $wpdb->prepare( "
482
			SELECT location_code, location_type
483
			FROM {$wpdb->prefix}woocommerce_tax_rate_locations
484
			WHERE tax_rate_id = %d
485
		", $id ) );
486
487 View Code Duplication
		if ( ! is_wp_error( $tax ) && ! is_null( $tax ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
488
			foreach ( $locales as $locale ) {
489
				$data[ $locale->location_type ] = $locale->location_code;
490
			}
491
		}
492
493
		$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
494
		$data    = $this->add_additional_fields_to_object( $data, $request );
495
		$data    = $this->filter_response_by_context( $data, $context );
496
497
		// Wrap the data in a response object.
498
		$response = rest_ensure_response( $data );
499
500
		$response->add_links( $this->prepare_links( $tax ) );
501
502
		/**
503
		 * Filter tax object returned from the REST API.
504
		 *
505
		 * @param WP_REST_Response $response The response object.
506
		 * @param stdClass         $tax      Tax object used to create response.
507
		 * @param WP_REST_Request  $request  Request object.
508
		 */
509
		return apply_filters( 'woocommerce_rest_prepare_tax', $response, $tax, $request );
510
	}
511
512
	/**
513
	 * Prepare links for the request.
514
	 *
515
	 * @param stdClass $tax Tax object.
516
	 * @return array Links for the given tax.
517
	 */
518 View Code Duplication
	protected function prepare_links( $tax ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
519
		$links = array(
520
			'self' => array(
521
				'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $tax->tax_rate_id ) ),
522
			),
523
			'collection' => array(
524
				'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),
525
			),
526
		);
527
528
		return $links;
529
	}
530
531
	/**
532
	 * Get the Taxes schema, conforming to JSON Schema.
533
	 *
534
	 * @return array
535
	 */
536
	public function get_item_schema() {
537
		$schema = array(
538
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
539
			'title'      => 'tax',
540
			'type'       => 'object',
541
			'properties' => array(
542
				'id' => array(
543
					'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
544
					'type'        => 'integer',
545
					'context'     => array( 'view', 'edit' ),
546
					'readonly'    => true,
547
				),
548
				'country' => array(
549
					'description' => __( 'Country ISO 3166 code.', 'woocommerce' ),
550
					'type'        => 'string',
551
					'context'     => array( 'view', 'edit' ),
552
				),
553
				'state' => array(
554
					'description' => __( 'State code.', 'woocommerce' ),
555
					'type'        => 'string',
556
					'context'     => array( 'view', 'edit' ),
557
				),
558
				'postcode' => array(
559
					'description' => __( 'Postcode/ZIP.', 'woocommerce' ),
560
					'type'        => 'string',
561
					'context'     => array( 'view', 'edit' ),
562
				),
563
				'city' => array(
564
					'description' => __( 'City name.', 'woocommerce' ),
565
					'type'        => 'string',
566
					'context'     => array( 'view', 'edit' ),
567
				),
568
				'rate' => array(
569
					'description' => __( 'Tax rate.', 'woocommerce' ),
570
					'type'        => 'float',
571
					'context'     => array( 'view', 'edit' ),
572
				),
573
				'name' => array(
574
					'description' => __( 'Tax rate name.', 'woocommerce' ),
575
					'type'        => 'string',
576
					'context'     => array( 'view', 'edit' ),
577
				),
578
				'priority' => array(
579
					'description' => __( 'Tax priority.', 'woocommerce' ),
580
					'type'        => 'integer',
581
					'default'     => 1,
582
					'context'     => array( 'view', 'edit' ),
583
				),
584
				'compound' => array(
585
					'description' => __( 'Whether or not this is a compound rate.', 'woocommerce' ),
586
					'type'        => 'boolean',
587
					'default'     => false,
588
					'context'     => array( 'view', 'edit' ),
589
				),
590
				'shipping' => array(
591
					'description' => __( 'Whether or not this tax rate also gets applied to shipping.', 'woocommerce' ),
592
					'type'        => 'boolean',
593
					'default'     => true,
594
					'context'     => array( 'view', 'edit' ),
595
				),
596
				'order' => array(
597
					'description' => __( 'Indicates the order that will appear in queries.', 'woocommerce' ),
598
					'type'        => 'integer',
599
					'context'     => array( 'view', 'edit' ),
600
				),
601
				'class' => array(
602
					'description' => __( 'Tax class.', 'woocommerce' ),
603
					'type'        => 'string',
604
					'default'     => 'standard',
605
					'enum'        => array_merge( array( 'standard' ), array_map( 'sanitize_title', WC_Tax::get_tax_classes() ) ),
606
					'context'     => array( 'view', 'edit' ),
607
				),
608
			),
609
		);
610
611
		return $this->add_additional_fields_schema( $schema );
612
	}
613
614
	/**
615
	 * Get the query params for collections.
616
	 *
617
	 * @return array
618
	 */
619
	public function get_collection_params() {
620
		$params = parent::get_collection_params();
621
622
		$params['context']['default'] = 'view';
623
624
		$params['exclude'] = array(
625
			'description'        => __( 'Ensure result set excludes specific ids.', 'woocommerce' ),
626
			'type'               => 'array',
627
			'default'            => array(),
628
			'sanitize_callback'  => 'wp_parse_id_list',
629
		);
630
		$params['include'] = array(
631
			'description'        => __( 'Limit result set to specific ids.', 'woocommerce' ),
632
			'type'               => 'array',
633
			'default'            => array(),
634
			'sanitize_callback'  => 'wp_parse_id_list',
635
		);
636
		$params['offset'] = array(
637
			'description'        => __( 'Offset the result set by a specific number of items.', 'woocommerce' ),
638
			'type'               => 'integer',
639
			'sanitize_callback'  => 'absint',
640
			'validate_callback'  => 'rest_validate_request_arg',
641
		);
642
		$params['order'] = array(
643
			'default'            => 'asc',
644
			'description'        => __( 'Order sort attribute ascending or descending.', 'woocommerce' ),
645
			'enum'               => array( 'asc', 'desc' ),
646
			'sanitize_callback'  => 'sanitize_key',
647
			'type'               => 'string',
648
			'validate_callback'  => 'rest_validate_request_arg',
649
		);
650
		$params['orderby'] = array(
651
			'default'            => 'order',
652
			'description'        => __( 'Sort collection by object attribute.', 'woocommerce' ),
653
			'enum'               => array(
654
				'id',
655
				'order',
656
			),
657
			'sanitize_callback'  => 'sanitize_key',
658
			'type'               => 'string',
659
			'validate_callback'  => 'rest_validate_request_arg',
660
		);
661
		$params['class'] = array(
662
			'description'        => __( 'Sort by tax class.', 'woocommerce' ),
663
			'enum'               => array_merge( array( 'standard' ), array_map( 'sanitize_title', WC_Tax::get_tax_classes() ) ),
664
			'sanitize_callback'  => 'sanitize_title',
665
			'type'               => 'string',
666
			'validate_callback'  => 'rest_validate_request_arg',
667
		);
668
669
		return $params;
670
	}
671
}
672