Completed
Pull Request — master (#11785)
by Mike
09:46
created

WC_REST_Coupons_Controller   B

Complexity

Total Complexity 42

Size/Duplication

Total Lines 505
Duplicated Lines 28.51 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 9
Bugs 3 Features 1
Metric Value
c 9
b 3
f 1
dl 144
loc 505
rs 8.295
wmc 42
lcom 1
cbo 4

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A register_routes() 60 60 1
A query_args() 0 10 2
C prepare_item_for_response() 3 41 7
A filter_writable_props() 0 3 1
D prepare_item_for_database() 7 79 17
B create_item() 31 31 3
B update_item() 32 32 5
A save_coupon() 0 11 3
B get_item_schema() 0 135 1
A get_collection_params() 10 10 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like WC_REST_Coupons_Controller often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use WC_REST_Coupons_Controller, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * REST API Coupons controller
4
 *
5
 * Handles requests to the /coupons 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 Coupons controller class.
19
 *
20
 * @package WooCommerce/API
21
 * @extends WC_REST_Posts_Controller
22
 */
23
class WC_REST_Coupons_Controller extends WC_REST_Posts_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 = 'coupons';
38
39
	/**
40
	 * Post type.
41
	 *
42
	 * @var string
43
	 */
44
	protected $post_type = 'shop_coupon';
45
46
	/**
47
	 * Order refunds actions.
48
	 */
49
	public function __construct() {
50
		add_filter( "woocommerce_rest_{$this->post_type}_query", array( $this, 'query_args' ), 10, 2 );
51
	}
52
53
	/**
54
	 * Register the routes for coupons.
55
	 */
56 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...
57
		register_rest_route( $this->namespace, '/' . $this->rest_base, array(
58
			array(
59
				'methods'             => WP_REST_Server::READABLE,
60
				'callback'            => array( $this, 'get_items' ),
61
				'permission_callback' => array( $this, 'get_items_permissions_check' ),
62
				'args'                => $this->get_collection_params(),
63
			),
64
			array(
65
				'methods'             => WP_REST_Server::CREATABLE,
66
				'callback'            => array( $this, 'create_item' ),
67
				'permission_callback' => array( $this, 'create_item_permissions_check' ),
68
				'args'                => array_merge( $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array(
69
					'code' => array(
70
						'required' => true,
71
					),
72
				) ),
73
			),
74
			'schema' => array( $this, 'get_public_item_schema' ),
75
		) );
76
77
		register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array(
78
			array(
79
				'methods'             => WP_REST_Server::READABLE,
80
				'callback'            => array( $this, 'get_item' ),
81
				'permission_callback' => array( $this, 'get_item_permissions_check' ),
82
				'args'                => array(
83
					'context'         => $this->get_context_param( array( 'default' => 'view' ) ),
84
				),
85
			),
86
			array(
87
				'methods'         => WP_REST_Server::EDITABLE,
88
				'callback'        => array( $this, 'update_item' ),
89
				'permission_callback' => array( $this, 'update_item_permissions_check' ),
90
				'args'            => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
91
			),
92
			array(
93
				'methods'             => WP_REST_Server::DELETABLE,
94
				'callback'            => array( $this, 'delete_item' ),
95
				'permission_callback' => array( $this, 'delete_item_permissions_check' ),
96
				'args'                => array(
97
					'force' => array(
98
						'default'     => false,
99
						'description' => __( 'Whether to bypass trash and force deletion.', 'woocommerce' ),
100
					),
101
				),
102
			),
103
			'schema' => array( $this, 'get_public_item_schema' ),
104
		) );
105
106
		register_rest_route( $this->namespace, '/' . $this->rest_base . '/batch', array(
107
			array(
108
				'methods'             => WP_REST_Server::EDITABLE,
109
				'callback'            => array( $this, 'batch_items' ),
110
				'permission_callback' => array( $this, 'batch_items_permissions_check' ),
111
				'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
112
			),
113
			'schema' => array( $this, 'get_public_batch_schema' ),
114
		) );
115
	}
116
117
	/**
118
	 * Query args.
119
	 *
120
	 * @param array $args
121
	 * @param WP_REST_Request $request
122
	 * @return array
123
	 */
124
	public function query_args( $args, $request ) {
125
		global $wpdb;
126
127
		if ( ! empty( $request['code'] ) ) {
128
			$id = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM $wpdb->posts WHERE post_title = %s AND post_type = 'shop_coupon' AND post_status = 'publish'", $request['code'] ) );
129
			$args['post__in'] = array( $id );
130
		}
131
132
		return $args;
133
	}
134
135
	/**
136
	 * Prepare a single coupon output for response.
137
	 *
138
	 * @param WP_Post $post Post object.
139
	 * @param WP_REST_Request $request Request object.
140
	 * @return WP_REST_Response $data
141
	 */
142
	public function prepare_item_for_response( $post, $request ) {
143
		$code           = wc_get_coupon_code_by_id( $post->ID );
144
		$coupon         = new WC_Coupon( $code );
145
		$data           = $coupon->get_data();
146
		$format_decimal = array( 'amount', 'minimum_amount', 'maximum_amount' );
147
		$format_date    = array( 'date_created', 'date_modified', 'date_expires' );
148
		$format_null    = array( 'usage_limit', 'usage_limit_per_user', 'limit_usage_to_x_items' );
149
150
		// Format decimal values.
151
		foreach ( $format_decimal as $key ) {
152
			$data[ $key ] = wc_format_decimal( $data[ $key ], 2 );
153
		}
154
155
		// Format date values.
156 View Code Duplication
		foreach ( $format_date as $key ) {
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...
157
			$data[ $key ] = $data[ $key ] ? wc_rest_prepare_date_response( get_gmt_from_date( date( 'Y-m-d H:i:s', $data[ $key ] ) ) ) : null;
158
		}
159
160
		// Format null values.
161
		foreach ( $format_null as $key ) {
162
			$data[ $key ] = $data[ $key ] ? $data[ $key ] : null;
163
		}
164
165
		$context  = ! empty( $request['context'] ) ? $request['context'] : 'view';
166
		$data     = $this->add_additional_fields_to_object( $data, $request );
167
		$data     = $this->filter_response_by_context( $data, $context );
168
		$response = rest_ensure_response( $data );
169
		$response->add_links( $this->prepare_links( $post ) );
170
171
		/**
172
		 * Filter the data for a response.
173
		 *
174
		 * The dynamic portion of the hook name, $this->post_type, refers to post_type of the post being
175
		 * prepared for the response.
176
		 *
177
		 * @param WP_REST_Response   $response   The response object.
178
		 * @param WP_Post            $post       Post object.
179
		 * @param WP_REST_Request    $request    Request object.
180
		 */
181
		return apply_filters( "woocommerce_rest_prepare_{$this->post_type}", $response, $post, $request );
182
	}
183
184
	/**
185
	 * Only reutrn writeable props from schema.
186
	 * @param  array $schema
187
	 * @return bool
188
	 */
189
	protected function filter_writable_props( $schema ) {
190
		return empty( $schema['readonly'] );
191
	}
192
193
	/**
194
	 * Prepare a single coupon for create or update.
195
	 *
196
	 * @param WP_REST_Request $request Request object.
197
	 * @return WP_Error|stdClass $data Post object.
198
	 */
199
	protected function prepare_item_for_database( $request ) {
200
		global $wpdb;
201
202
		$id        = isset( $request['id'] ) ? absint( $request['id'] ) : 0;
203
		$coupon    = new WC_Coupon( $id );
204
		$schema    = $this->get_item_schema();
205
		$data_keys = array_keys( array_filter( $schema['properties'], array( $this, 'filter_writable_props' ) ) );
206
207
		// BW compat
208
		if ( $request['exclude_product_ids'] ) {
209
			$request['excluded_product_ids'] = $request['exclude_product_ids'];
210
		}
211
		if ( $request['expiry_date'] ) {
212
			$request['date_expires'] = $request['expiry_date'];
213
		}
214
215
		// Validate required POST fields.
216
		if ( 'POST' === $request->get_method() && 0 === $coupon->get_id() ) {
217
			if ( empty( $request['code'] ) ) {
218
				return new WP_Error( 'woocommerce_rest_empty_coupon_code', sprintf( __( 'The coupon code cannot be empty.', 'woocommerce' ), 'code' ), array( 'status' => 400 ) );
219
			}
220
		}
221
222
		// Handle all writable props
223
		foreach ( $data_keys as $key ) {
224
			$value = $request[ $key ];
225
226
			if ( ! is_null( $value ) ) {
227
				switch ( $key ) {
228
					case 'code' :
229
						$coupon_code = apply_filters( 'woocommerce_coupon_code', $value );
230
						$id          = $coupon->get_id() ? $coupon->get_id() : 0;
231
232
						// Check for duplicate coupon codes.
233
						$coupon_found = $wpdb->get_var( $wpdb->prepare( "
234
							SELECT $wpdb->posts.ID
235
							FROM $wpdb->posts
236
							WHERE $wpdb->posts.post_type = 'shop_coupon'
237
							AND $wpdb->posts.post_status = 'publish'
238
							AND $wpdb->posts.post_title = %s
239
							AND $wpdb->posts.ID != %s
240
						 ", $coupon_code, $id ) );
241
242
						if ( $coupon_found ) {
243
							return new WP_Error( 'woocommerce_rest_coupon_code_already_exists', __( 'The coupon code already exists', 'woocommerce' ), array( 'status' => 400 ) );
244
						}
245
246
						$coupon->set_code( $coupon_code );
247
						break;
248 View Code Duplication
					case 'meta_data' :
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...
249
						if ( is_array( $value ) ) {
250
							foreach ( $value as $meta ) {
251
								$coupon->update_meta_data( $meta['key'], $meta['value'], $meta['id'] );
252
							}
253
						}
254
						break;
255
					case 'description' :
256
						$coupon->set_description( wp_filter_post_kses( $value ) );
257
						break;
258
					default :
259
						if ( is_callable( array( $coupon, "set_{$key}" ) ) ) {
260
							$coupon->{"set_{$key}"}( $value );
261
						}
262
						break;
263
				}
264
			}
265
		}
266
267
		/**
268
		 * Filter the query_vars used in `get_items` for the constructed query.
269
		 *
270
		 * The dynamic portion of the hook name, $this->post_type, refers to post_type of the post being
271
		 * prepared for insertion.
272
		 *
273
		 * @param WC_Coupon       $coupon        The coupon object.
274
		 * @param WP_REST_Request $request       Request object.
275
		 */
276
		return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}", $coupon, $request );
277
	}
278
279
	/**
280
	 * Create a single item.
281
	 *
282
	 * @param WP_REST_Request $request Full details about the request.
283
	 * @return WP_Error|WP_REST_Response
284
	 */
285 View Code Duplication
	public function create_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...
286
		if ( ! empty( $request['id'] ) ) {
287
			return new WP_Error( "woocommerce_rest_{$this->post_type}_exists", sprintf( __( 'Cannot create existing %s.', 'woocommerce' ), $this->post_type ), array( 'status' => 400 ) );
288
		}
289
290
		$coupon_id = $this->save_coupon( $request );
291
		if ( is_wp_error( $coupon_id ) ) {
292
			return $coupon_id;
293
		}
294
295
		$post = get_post( $coupon_id );
296
		$this->update_additional_fields_for_object( $post, $request );
297
298
		$this->add_post_meta_fields( $post, $request );
0 ignored issues
show
Unused Code introduced by
The call to the method WC_REST_Coupons_Controller::add_post_meta_fields() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
299
300
		/**
301
		 * Fires after a single item is created or updated via the REST API.
302
		 *
303
		 * @param object          $post      Inserted object (not a WP_Post object).
304
		 * @param WP_REST_Request $request   Request object.
305
		 * @param boolean         $creating  True when creating item, false when updating.
306
		 */
307
		do_action( "woocommerce_rest_insert_{$this->post_type}", $post, $request, true );
308
		$request->set_param( 'context', 'edit' );
309
		$response = $this->prepare_item_for_response( $post, $request );
310
		$response = rest_ensure_response( $response );
311
		$response->set_status( 201 );
312
		$response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $post->ID ) ) );
313
314
		return $response;
315
	}
316
317
	/**
318
	 * Update a single coupon.
319
	 *
320
	 * @param WP_REST_Request $request Full details about the request.
321
	 * @return WP_Error|WP_REST_Response
322
	 */
323 View Code Duplication
	public function update_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...
324
		try {
325
			$post_id = (int) $request['id'];
326
327
			if ( empty( $post_id ) || $this->post_type !== get_post_type( $post_id ) ) {
328
				return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'ID is invalid.', 'woocommerce' ), array( 'status' => 400 ) );
329
			}
330
331
			$coupon_id = $this->save_coupon( $request );
332
			if ( is_wp_error( $coupon_id ) ) {
333
				return $coupon_id;
334
			}
335
336
			$post = get_post( $coupon_id );
337
			$this->update_additional_fields_for_object( $post, $request );
338
339
			/**
340
			 * Fires after a single item is created or updated via the REST API.
341
			 *
342
			 * @param object          $post      Inserted object (not a WP_Post object).
343
			 * @param WP_REST_Request $request   Request object.
344
			 * @param boolean         $creating  True when creating item, false when updating.
345
			 */
346
			do_action( "woocommerce_rest_insert_{$this->post_type}", $post, $request, false );
347
			$request->set_param( 'context', 'edit' );
348
			$response = $this->prepare_item_for_response( $post, $request );
349
			return rest_ensure_response( $response );
350
351
		} catch ( Exception $e ) {
352
			return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Exception as the method getErrorCode() does only exist in the following sub-classes of Exception: WC_CLI_Exception, WC_Data_Exception, WC_REST_Exception. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
353
		}
354
	}
355
356
	/**
357
	 * Saves a coupon to the database.
358
	 */
359
	public function save_coupon( $request ) {
360
		try {
361
			$coupon = $this->prepare_item_for_database( $request );
362
			$coupon->save();
363
			return $coupon->get_id();
364
		} catch ( WC_Data_Exception $e ) {
365
			return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
366
		} catch ( WC_REST_Exception $e ) {
367
			return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
368
		}
369
	}
370
371
	/**
372
	 * Get the Coupon's schema, conforming to JSON Schema.
373
	 *
374
	 * @return array
375
	 */
376
	public function get_item_schema() {
377
		$schema = array(
378
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
379
			'title'      => $this->post_type,
380
			'type'       => 'object',
381
			'properties' => array(
382
				'id' => array(
383
					'description' => __( 'Unique identifier for the object.', 'woocommerce' ),
384
					'type'        => 'integer',
385
					'context'     => array( 'view', 'edit' ),
386
					'readonly'    => true,
387
				),
388
				'code' => array(
389
					'description' => __( 'Coupon code.', 'woocommerce' ),
390
					'type'        => 'string',
391
					'context'     => array( 'view', 'edit' ),
392
				),
393
				'date_created' => array(
394
					'description' => __( "The date the coupon was created, in the site's timezone.", 'woocommerce' ),
395
					'type'        => 'date-time',
396
					'context'     => array( 'view', 'edit' ),
397
					'readonly'    => true,
398
				),
399
				'date_modified' => array(
400
					'description' => __( "The date the coupon was last modified, in the site's timezone.", 'woocommerce' ),
401
					'type'        => 'date-time',
402
					'context'     => array( 'view', 'edit' ),
403
					'readonly'    => true,
404
				),
405
				'description' => array(
406
					'description' => __( 'Coupon description.', 'woocommerce' ),
407
					'type'        => 'string',
408
					'context'     => array( 'view', 'edit' ),
409
				),
410
				'discount_type' => array(
411
					'description' => __( 'Determines the type of discount that will be applied.', 'woocommerce' ),
412
					'type'        => 'string',
413
					'default'     => 'fixed_cart',
414
					'enum'        => array_keys( wc_get_coupon_types() ),
415
					'context'     => array( 'view', 'edit' ),
416
				),
417
				'amount' => array(
418
					'description' => __( 'The amount of discount.', 'woocommerce' ),
419
					'type'        => 'string',
420
					'context'     => array( 'view', 'edit' ),
421
				),
422
				'date_expires' => array(
423
					'description' => __( 'UTC DateTime when the coupon expires.', 'woocommerce' ),
424
					'type'        => 'string',
425
					'context'     => array( 'view', 'edit' ),
426
				),
427
				'usage_count' => array(
428
					'description' => __( 'Number of times the coupon has been used already.', 'woocommerce' ),
429
					'type'        => 'integer',
430
					'context'     => array( 'view', 'edit' ),
431
					'readonly'    => true,
432
				),
433
				'individual_use' => array(
434
					'description' => __( 'Whether coupon can only be used individually.', 'woocommerce' ),
435
					'type'        => 'boolean',
436
					'default'     => false,
437
					'context'     => array( 'view', 'edit' ),
438
				),
439
				'product_ids' => array(
440
					'description' => __( "List of product ID's the coupon can be used on.", 'woocommerce' ),
441
					'type'        => 'array',
442
					'context'     => array( 'view', 'edit' ),
443
				),
444
				'excluded_product_ids' => array(
445
					'description' => __( "List of product ID's the coupon cannot be used on.", 'woocommerce' ),
446
					'type'        => 'array',
447
					'context'     => array( 'view', 'edit' ),
448
				),
449
				'usage_limit' => array(
450
					'description' => __( 'How many times the coupon can be used.', 'woocommerce' ),
451
					'type'        => 'integer',
452
					'context'     => array( 'view', 'edit' ),
453
				),
454
				'usage_limit_per_user' => array(
455
					'description' => __( 'How many times the coupon can be used per customer.', 'woocommerce' ),
456
					'type'        => 'integer',
457
					'context'     => array( 'view', 'edit' ),
458
				),
459
				'limit_usage_to_x_items' => array(
460
					'description' => __( 'Max number of items in the cart the coupon can be applied to.', 'woocommerce' ),
461
					'type'        => 'integer',
462
					'context'     => array( 'view', 'edit' ),
463
				),
464
				'free_shipping' => array(
465
					'description' => __( 'Define if can be applied for free shipping.', 'woocommerce' ),
466
					'type'        => 'boolean',
467
					'default'     => false,
468
					'context'     => array( 'view', 'edit' ),
469
				),
470
				'product_categories' => array(
471
					'description' => __( "List of category ID's the coupon applies to.", 'woocommerce' ),
472
					'type'        => 'array',
473
					'context'     => array( 'view', 'edit' ),
474
				),
475
				'excluded_product_categories' => array(
476
					'description' => __( "List of category ID's the coupon does not apply to.", 'woocommerce' ),
477
					'type'        => 'array',
478
					'context'     => array( 'view', 'edit' ),
479
				),
480
				'exclude_sale_items' => array(
481
					'description' => __( 'Define if should not apply when have sale items.', 'woocommerce' ),
482
					'type'        => 'boolean',
483
					'default'     => false,
484
					'context'     => array( 'view', 'edit' ),
485
				),
486
				'minimum_amount' => array(
487
					'description' => __( 'Minimum order amount that needs to be in the cart before coupon applies.', 'woocommerce' ),
488
					'type'        => 'string',
489
					'context'     => array( 'view', 'edit' ),
490
				),
491
				'maximum_amount' => array(
492
					'description' => __( 'Maximum order amount allowed when using the coupon.', 'woocommerce' ),
493
					'type'        => 'string',
494
					'context'     => array( 'view', 'edit' ),
495
				),
496
				'email_restrictions' => array(
497
					'description' => __( 'List of email addresses that can use this coupon.', 'woocommerce' ),
498
					'type'        => 'array',
499
					'context'     => array( 'view', 'edit' ),
500
				),
501
				'used_by' => array(
502
					'description' => __( 'List of user IDs who have used the coupon.', 'woocommerce' ),
503
					'type'        => 'array',
504
					'context'     => array( 'view', 'edit' ),
505
					'readonly'    => true,
506
				),
507
			),
508
		);
509
		return $this->add_additional_fields_schema( $schema );
510
	}
511
512
	/**
513
	 * Get the query params for collections of attachments.
514
	 *
515
	 * @return array
516
	 */
517 View Code Duplication
	public function get_collection_params() {
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...
518
		$params = parent::get_collection_params();
519
		$params['code'] = array(
520
			'description'       => __( 'Limit result set to resources with a specific code.', 'woocommerce' ),
521
			'type'              => 'string',
522
			'sanitize_callback' => 'sanitize_text_field',
523
			'validate_callback' => 'rest_validate_request_arg',
524
		);
525
		return $params;
526
	}
527
}
528